代码编织梦想

项目资源可以从我的github上获取

https://github.com/chiyu999/smbms.git

三、登录功能优化(注销及权限过滤)

3.1、注销

在这里插入图片描述

1、编写servlet

package com.zhang.servlet.user;

import com.zhang.utils.Constants;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class LogoutServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //移除用户session
        req.getSession().removeAttribute(Constants.USER_SESSION);
        if (req.getSession().getAttribute(Constants.USER_SESSION) == null){
            System.out.println("成功移除用户session,返回登录页面");
        }
        //返回登录页面
        resp.sendRedirect("login.jsp");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

2、注册servlet

<!--退出登录Servlet-->
    <servlet>
        <servlet-name>LogoutServlet</servlet-name>
        <servlet-class>com.zhang.servlet.user.LogoutServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LogoutServlet</servlet-name>
        <url-pattern>/logout.do</url-pattern>
    </servlet-mapping>

3.2、登录拦截优化

登录成功,然后退出,退出之后发现用链接进去frame.jsp页面也能进去
在这里插入图片描述

退出系统后进入的页面
在这里插入图片描述
于是要写个登录拦截器去拦截所有请求,如果用户为登录,则不能进入后台页面

1、编写Filter

package com.zhang.filter;

import com.zhang.pojo.User;
import com.zhang.utils.Constants;

import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class SystemFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        //过滤器,从session中获取用户
        User user = (User) req.getSession().getAttribute(Constants.USER_SESSION);
        if (user == null){//用户已经注销或者未登录
            resp.sendRedirect("/error.jsp");
        }else {
            chain.doFilter(request, response);
        }
        
    }

    @Override
    public void destroy() {

    }
}

2、注册Filter

<!--登录拦截过滤器-->
    <filter>
        <filter-name>SystemFilter</filter-name>
        <filter-class>com.zhang.filter.SystemFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>SystemFilter</filter-name>
        <url-pattern>/jsp/*</url-pattern>
    </filter-mapping>

3、测试

在这里插入图片描述

四、密码修改

思路:

  • dao:根据传进来的userCode 和 password 执行一条update语句
  • service: 根据前端传进来的参数,跟后台的数据进行匹配,调用dao层实现
  • servlet : 从前端获取数据,调用service层业务

1、编写UserDao接口

/**
     * 修改当前用户密码
     * @param connection
     * @param id
     * @param pwd
     * @return int
     * @throws Exception
     */
    public int updatePwd(Connection connection, int id, String pwd)throws Exception;

2、编写UserDaoImpl实现类

/**
     * 修改当前用户密码
     * @param connection
     * @param id
     * @param pwd
     * @return int
     * @throws Exception
     */
    @Override
    public int updatePwd(Connection connection, int id, String pwd) throws Exception {
        PreparedStatement pstm = null;
        int execute = 0;
        if (connection != null){
            String sql = "update smbms_user set userPassword =? where id = ?";
            //接收参数
            Object[] params = {pwd,id};
            for (int i = 0; i < params.length; i++) {
                pstm.setObject(i+1,params[i]);
            }
            execute = BaseDao.execute(connection, pstm, sql, params);
            BaseDao.closeResource(null,pstm,null);
        }
        return execute;
    }

3、编写UserService接口

/**
     * 根据userId修改用户密码
     * @param id
     * @param pwd
     * @return boolean
     * @throws Exception
     */
    public boolean updatePwd(int id, String pwd);

4、编写UserServiceImpl实现类

/**
     * 根据用户id修改密码
     * @param id
     * @param pwd
     * @return boolean true==修改成功  false==修改失败
     */
    @Override
    public boolean updatePwd(int id, String pwd) {
        Connection connection = null;
        //标志位,用于标志是否修改密码成功
        boolean flag = false;
        try {
            connection = BaseDao.getConnection();
            //修改密码
            if (userDao.updatePwd(connection, id, pwd)>0){
                flag = true;
                return flag;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            BaseDao.closeResource(connection,null,null);
        }
        return flag;
    }

5、编写UserServlet

/**
 * 实现Servlet复用
 * User的操作都在这个Servlet中实现
 */
public class UserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //因为是根据id修改密码,在登录的时候已经把用户的所有信息都存到userSession中了,可以从session中获取当前用户的id
        //获取用户
        Object o = req.getSession().getAttribute(Constants.USER_SESSION);
        //从前端获取新密码
        String newpassword = req.getParameter("newpassword");

        System.out.println("UserServlet========>"+newpassword);


        //设立标志位,默认修改不成功
        boolean flag = false;
        //判断获取到的用户是否为空,新密码是否为空
        if((User)o != null && newpassword != null && newpassword.length()>0){
            //调用service层方法实现业务
            UserServiceImpl userService = new UserServiceImpl();
            //把更新密码的结果设置给flag
            System.out.println("UserServlet"+((User) o).getId());
            flag = userService.updatePwd(((User) o).getId(), newpassword);
            if (flag){ //如果为true,则说明修改密码成功
                //密码修改成功,需要重新登录,提示修改密码成功,移除用户session
                req.setAttribute("message","密码修改成功,请返回登录页面,使用新密码重新登录");
                req.getSession().removeAttribute(Constants.USER_SESSION);
            }else {
                //密码修改失败
                req.setAttribute("message","密码修改失败");
            }
        }else { //
            req.setAttribute("message","新密码有问题");
        }
        req.getRequestDispatcher("pwdmodify.jsp").forward(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }

}

这里为了实现Servlet的复用,在前端用了个隐藏域来定义提交的方法,这里需要把这个代码封装成一个方法,在doget里调用那么UserServlet的代码就会重构成下面这样,之后要操作User,则在本类中增加方法,在doget中增加分支即可

public class UserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getParameter("method");
        if (method != null && method.equals("savepwd")){
            this.updatePwd(req,resp);
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }

    private void updatePwd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //因为是根据id修改密码,在登录的时候已经把用户的所有信息都存到userSession中了,可以从session中获取当前用户的id
        //获取用户
        Object o = req.getSession().getAttribute(Constants.USER_SESSION);
        //从前端获取新密码
        String newpassword = req.getParameter("newpassword");
        //设立标志位,默认修改不成功
        boolean flag = false;
        //判断获取到的用户是否为空,新密码是否为空
        if((User)o != null && newpassword != null && newpassword.length()>0){
            //调用service层方法实现业务
            UserServiceImpl userService = new UserServiceImpl();
            //把更新密码的结果设置给flag
//            System.out.println("UserServlet"+((User) o).getId());
            flag = userService.updatePwd(((User) o).getId(), newpassword);
            if (flag){ //如果为true,则说明修改密码成功
                //密码修改成功,需要重新登录,提示修改密码成功,移除用户session
                req.setAttribute("message","密码修改成功,请返回登录页面,使用新密码重新登录");
                req.getSession().removeAttribute(Constants.USER_SESSION);
            }else {
                //密码修改失败
                req.setAttribute("message","密码修改失败");
            }
        }else { //
            req.setAttribute("message","新密码有问题");
        }
        req.getRequestDispatcher("pwdmodify.jsp").forward(req,resp);
    }

}

6、测试功能

7、遇到的bug

空指针异常

刚开始在编写dao层代码的时候没有进行测试,才导致到后面修改密码不成功,苦恼好久,愣是粗心没有发现这个问题,原先的代码是这样的

public int updatePwd(Connection connection, int id, String pwd) throws Exception {
        PreparedStatement pstm = null;
        int execute = 0;
        if (connection != null){
            String sql = "update smbms_user set userPassword= ? where id = ?";
            //接收参数
            Object[] params = {pwd,id};
            for (int i = 0; i < params.length; i++) {
                pstm.setObject(i+1,params[i]);
            }
            execute = BaseDao.execute(connection, pstm, sql, params);
//            System.out.println("更改密码结果=====>"+execute);
            BaseDao.closeResource(null,pstm,null);
        }
        return execute;
    }

里面有这么一段代码

for (int i = 0; i < params.length; i++) {
                pstm.setObject(i+1,params[i]);
            }

这是给预编译sql占位符设置值的,着原本是在BaseDao这个数据连接公共类中做的,结果在这里我给他赋值了一次,导致他报了个空指针异常

解决思路

因为是空指针异常,所以我第一时间想的是哪一个参数会是空的吗?

我是依次从servlet—>service---->dao层打印了各个参数,结果发现参数都没有问题,可是就是会报空指针,也没有执行到sql语句,结果后来叫了舍友过来看了下,说了出来才理清了思路发现了这里给预编译设置值了结果把代码删了过仍然就可以跑的通了

到最后还在想一个问题,数组里的东西:预编译sql的机制是怎样的,到现在都想不通,只是看到了setobject方法的源码,看了excudeUpdate方法找下去,能力不够,看不懂,想不通想不通
在这里插入图片描述

五、密码修改功能优化

Ajax 实现旧密码验证

前端代码

$.ajax({
			type:"GET",
			url:path+"/jsp/user.do",
			data:{method:"pwdmodify",oldpassword:oldpassword.val()},
			dataType:"json",
			success:function(data){
				if(data.result == "true"){//旧密码正确
					validateTip(oldpassword.next(),{"color":"green"},imgYes,true);
				}else if(data.result == "false"){//旧密码输入不正确
					validateTip(oldpassword.next(),{"color":"red"},imgNo + " 原密码输入不正确",false);
				}else if(data.result == "sessionerror"){//当前用户session过期,请重新登录
					validateTip(oldpassword.next(),{"color":"red"},imgNo + " 当前用户session过期,请重新登录",false);
				}else if(data.result == "error"){//旧密码输入为空
					validateTip(oldpassword.next(),{"color":"red"},imgNo + " 请输入旧密码",false);
				}
			},
			error:function(data){
				//请求出错
				validateTip(oldpassword.next(),{"color":"red"},imgNo + " 请求错误",false);
			}
		});

会走这个请求/jsp/user.do下面的pwdmodify
相当于请求 项目名/jsp/user.do?method=pwdmodify

UserServlet 新增方法

public void getPwdByUserId(HttpServletRequest req, HttpServletResponse resp){
        Object o = req.getSession().getAttribute(Constants.USER_SESSION);
        String oldpassword = req.getParameter("oldpassword");
       //万能的Map,一切东西都可以存放
        Map<String, String> resultMap = new HashMap<String, String>();
        if (o == null){ //Session过期了
            resultMap.put("result","sessionerror");
        }else if (StringUtils.isNullOrEmpty(oldpassword)){//如果前端获取的参数是null或空串
            resultMap.put("result","error");
        }else {
            String userPassword = ((User) o).getUserPassword();
            if (userPassword.equals(oldpassword)){ //旧密码正确
                resultMap.put("result","true");
            }else { //旧密码错误
                resultMap.put("result","false");

            }
        }
        //把Map里的值去除以json格式的字符串返回给前端
        //设置返回响应头
        resp.setContentType("application/json");
        //获取流
        PrintWriter outPrintWriter = null;
        try {
            outPrintWriter = resp.getWriter();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //alibab的JSONArray工具类,转换格式使用
        //={key,value}  然后传递给前端  result
        outPrintWriter.write(JSONArray.toJSONString(resultMap));
        outPrintWriter.flush();
        outPrintWriter.close();
    }

新增分支

else if (method != null && method.equals("pwdmodify")){
            this.getPwdByUserId(req, resp);
        }
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_71614127/article/details/127992369

SMBMS超市订单管理系统-笔记-爱代码爱编程

000000 数据库: BaseDao.java package cn.smbms.dao; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql

超市订单管理系统(smbms)-爱代码爱编程

SMBMS项目 项目架构项目数据库项目文件目录 项目搭建准备工作 使用Maven 搭配一个maven web项目 配置Tomcat 测试项目是否能够跑起来 导入项目中会遇到的jar包 jsp,servlet,mysql驱动,jstl,standard… 创建包结构 编写实体类 ORM映射:表-类映射 编写公共基础类 (1)数据库配置文

SMBMS 超市订单管理系统-爱代码爱编程

SMBMS 超市订单管理系统 学完JavaWeb后必须熟悉练习的一个小项目:如有需要源码的同学可以联系我或在下方评论,这边文章的目的在于帮助你了解项目开发的大致过程. 1.项目搭建准备工作 Tomcat 3.6.1 MySQL 5.7.1 IDEA 2.登录功能实现 通过用户名和密码获取用户登录 3.登录功能优化 3.1注销功

JavaWeb项目smbms超市订单管理系统-爱代码爱编程

项目简介 smbms超市订单管理系统,主要用于用户管理、订单管理、供应商管理等功能,是学习JavaWeb练习的一个小项目 这个博客只讲了部分功能(用户登录界面,和密码修改界面),以及用户管理的实现。 主要写的后端的实现。 使用技术 Maven:管理依赖打包项目 Mysql:存储业务数据 HTML:制作前端登录页面 Servlet:后台服

SMBMS (超市订单管理系统)-爱代码爱编程

SMBMS(超市订单管理系统)(Dao --> Service --> Servlet) 1、项目搭建 1.1 流程 1.2 创建maven项目 1.3 配置tomcat 这里设置了==/smbms== 1.4 创建项目包结构 2、编写实体类 ORM映射(entity) 3、编写基础公共类 3.1 数据库配置文件

SMBMS超市订单管理系统问题总结-爱代码爱编程

问题总结 关于首页不显示 userName 的问题 在标记位置加 req.getSession().setAttribute(“userName”,user.getUserName()); 在 session 中定义 username 并获得当前账号的用户名 import com.yqly.pojo.User; import com.yqly.ser

SMBMS(超市订单管理系统)-爱代码爱编程

系统框架及数据库 转载狂神笔记 1.系统框架 2.数据库源码 CREATE DATABASE `smbms`; USE `smbms`; DROP TABLE IF EXISTS `smbms_address`; CREATE TABLE `smbms_address` ( `id` BIGINT(20) NOT NULL AU

狂神。SMBMS(超市订单管理系统)-爱代码爱编程

SMBMS(超市订单管理系统) 代码:(建议把静态资源和sql拿过来用,其他自己写一遍练手。注意修改相关配置文件。) 链接:https://pan.baidu.com/s/12MmpF9msJVjLT1U77XYfRw 提取码:11fv 数据库: 项目如何搭建? 考虑是不是用Maven?依赖, jar包. 1.项目搭建准备工