JAVAWeb | SMBMS项目实战(二)

登录功能实现

login.do 是请求
在这里插入图片描述

1. 编写前端登录页面:login.jsp

<%--<!DOCTYPE html>--%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>系统登录 - 超市订单管理系统</title>
    <link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath }/css/style.css" />
    <script type="text/javascript">
	/* if(top.location!=self.location){
	      top.location=self.location;
	 }*/
    </script>
</head>
<body class="login_bg">
    <section class="loginBox">
        <header class="loginHeader">
            <h1>超市订单管理系统</h1>
        </header>
        <section class="loginCont">
	        <form class="loginForm" action="${pageContext.request.contextPath }/login.do"  name="actionForm" id="actionForm"  method="post" >
				<div class="info">${error}</div>
				<div class="inputbox">
                    <label for="userCode">用户名:</label>
					<input type="text" class="input-text" id="userCode" name="userCode" placeholder="请输入用户名" required/>
				</div>	
				<div class="inputbox">
                    <label for="userPassword">密码:</label>
                    <input type="password" id="userPassword" name="userPassword" placeholder="请输入密码" required/>
                </div>	
				<div class="subBtn">
					
                    <input type="submit" value="登录"/>
                    <input type="reset" value="重置"/>
                </div>	
			</form>
        </section>
    </section>
</body>
</html>

2. 设置欢迎页面,让服务器已启动就跳转到登录页面

配置 web.xml

<!--    设置欢迎页面-->
    <welcome-file-list>
        <welcome-file>login.jsp</welcome-file>
    </welcome-file-list>

启动 tomcat,看是否打开即成功显示 login.jsp
在这里插入图片描述

成功跳出页面,但是登录会显示404未找到,因为后面的还没写!

接下来用户登录后,我们要去判断用户信息和密码是否正确,首先要撰写操作数据库的类,去数据库进行查找

3. 编写Dao层得到用户登录的接口

接口 UserDao:

User getLoginUser(Connection connection, String userCode) throws SQLException;

从数据库中得到要登录的用户,通过用户名利用 sql 进行查询,查询到后将其封装到用户实体类中,封装完成后返回 user

4. 编写Dao层的实现类

UserDaoImpl implements UserDao:

    @Override
    public User getLoginUser(Connection connection, String userCode) throws SQLException {
        PreparedStatement preparedStatement = null;
        ResultSet rs = null;
        User user = null;

        if (connection != null) {
            String sql = "select * from smbms_user where userCode=?"; //  查询表里面的所有人,判断条件 userCode 是否 = 登录的用户名
            Object[] params = {userCode};
            try {
                rs = BaseDao.execute(connection, preparedStatement, rs, sql, params); // 执行 sql
                if (rs.next()) {
                    user = new User();
                    user.setId(rs.getInt("id"));
                    user.setUserCode(rs.getString("userCode"));
                    user.setUserName(rs.getString("userName"));
                    user.setUserPassword(rs.getString("userPassword"));
                    user.setGender(rs.getInt("gender"));
                    user.setBirthday(rs.getDate("birthday"));
                    user.setPhone(rs.getString("phone"));
                    user.setAddress(rs.getString("address"));
                    user.setUserRole(rs.getInt("userRole"));
                    user.setCreatedBy(rs.getInt("createdBy"));
                    user.setCreationDate(rs.getTimestamp("creationDate"));
                    user.setModifyBy(rs.getInt("modifyBy"));
                    user.setModifyDate(rs.getTimestamp("modifyDate"));
                }
                BaseDao.closeResource(null, preparedStatement, rs);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return user;
    }

在这里插入图片描述

5. 编写业务层接口

public User login(String userCode,String password) throws SQLException;

6. 业务层实现类

通过判断密码是否匹配正确,实现用户登录

    @Override
    public User login(String userCode, String password) {
        Connection connection = null;
        User user = null;

        try {
//            System.out.println("UserServiceImpl:"+userCode);
//            System.out.println("UserServiceImpl:"+password);
            connection = BaseDao.getConnection();

            // 通过业务层调用对应的具体数据库操作
            user = userDao.getLoginUser(connection, userCode);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            BaseDao.closeResource(connection, null, null);
        }
        //进行密码匹配
        if (user != null) {
            if (!user.getUserPassword().equals(password)) {
                user = null;
            }
        }
        return user;
    }

在 pom.xml 中加入 junit 依赖,进行单元测试

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>

测试是否可以查询到密码,并输出

    @Test
    public void test() {
        UserServiceImpl userService = new UserServiceImpl();
        User admin = userService.login("admin", "1234567");
        System.out.println(admin.getUserPassword());
    }

当账号:admin 和密码:1234567 正确时,输出正确结果
在这里插入图片描述

否则,错误
在这里插入图片描述

在这里插入图片描述

7. 编写 servlet:用于获取前端请求的参数,并调用业务层判断是否存在该用户

先获取页面用户输入的用户名和密码,然后和数据库中的匹配,匹配成功,则将用户信息放入到 session 中,并跳转到主页,如果没有匹配成功,则无法登录,转发回登录页面,提示用户名或者密码错误

package com.uestc.servlet.user;

import com.uestc.pojo.User;
import com.uestc.service.user.UserServiceImpl;
import com.uestc.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;

// Servlet控制层,调用业务层代码
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        System.out.println("LoginServlet---start");

        //获取用户名和密码
        String userCode = req.getParameter("userCode");
        String userPassword = req.getParameter("userPassword");
        System.out.println("LoginServlet:"+userCode);
        System.out.println("LoginServlet:"+userPassword);

        //和数据库中的密码进行比较,调用业务层
        UserServiceImpl userService = new UserServiceImpl();

        //这里已经把登录的人查出来了
        User user = userService.login(userCode, userPassword);

        //查到了,则进行登录,将用户信息放到Session中
        if (user!=null){
            req.getSession().setAttribute(Constants.USER_SESSION, user);
            //跳转主页
            resp.sendRedirect("jsp/frame.jsp");
        }else {
            //查无此人,无法登录,转发回登录页面,提示用户名或者密码错误
            req.setAttribute("error", "用户名或者密码错误");
            req.getRequestDispatcher("login.jsp").forward(req, resp);
        }
    }

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

上述:req.setAttribute(“error”, “用户名或者密码错误”); 的设置来源于 login.jsp 中如下:
在这里插入图片描述

Utils 中定义 Constants 类,专门用于存储常理,方便修改

package com.uestc.utils;

public class Constants {
    //定义一个用户session常量
    public final static String USER_SESSION = "userSession";
}

在这里插入图片描述

jsp/frame.jsp 用于请求页面跳转,因此,在 webapp 中新建 jsp 文件,并完善页面 frame.jsp

在这里插入图片描述
在这里插入图片描述

web.xml 中进行注册

    <servlet>
        <servlet-name>LoginServlet</servlet-name>
        <servlet-class>com.threepure.servlet.user.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LoginServlet</servlet-name>
        <url-pattern>/login.do</url-pattern>
    </servlet-mapping>

这个请求的名字 /login.do 是规定好的,和 login.jsp 中某处是一致的如下,如果要改,两边都要改
在这里插入图片描述

启动 tomcat,账户输入错误,会显示用户名或密码错误
在这里插入图片描述

输入正确后,即可跳转页面
在这里插入图片描述

但是由于这些功能都还没有实现,所有点击后为 404
在这里插入图片描述

9. 测试访问,保证以上功能可以成功

登录功能优化

登录注销功能实现

1. 编写servlet:用于移除session属性,再返回登录页面

在这里插入图片描述

package com.uestc.servlet.user;

import com.uestc.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 {

        //移除用户的 Constants.USER_SESSION
        req.getSession().removeAttribute(Constants.USER_SESSION);
        
        //重新返回登录页面
        resp.sendRedirect(req.getContextPath()+"/login.jsp"); // req.getContextPath() 为项目目录,但是有时会有后面的请求重复,导致无法找到
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
  • 注意:req.getContextPath() 是为了拿到项目的路径,但是有时候会和后面的请求重复,所有要测试

注册 web.xml

    <servlet>
        <servlet-name>LogoutServlet</servlet-name>
        <servlet-class>com.uestc.servlet.user.LogoutServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LogoutServlet</servlet-name>
        <url-pattern>/jsp/logout.do</url-pattern>
    </servlet-mapping>

注意这里请求为:/jsp/logout.do,那是由于前端页面 head.jsp 的退出系统也是用的 /jsp/logout.do,所以这里注册的请求一定要与前端页面保持一致(前端表示:点击退出系统和退出,自动请求 /jsp/logout.do)
在这里插入图片描述

启动 tomcat 并登录显示如下:并点击退出和退出系统请求的是一样的,但是并没有完成注销,退出之后依然可以登录,所以需要进行登录拦截优化
在这里插入图片描述

登录拦截优化

1. 为了保证用户注销之后不能再进入主页,需要设置过滤器

在这里插入图片描述

package com.uestc.filter;

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

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

//判断是否登录的过滤器

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

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        // 提取 request,response
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        // 过滤器,从 Session 中获取用户
        User user = (User) request.getSession().getAttribute(Constants.USER_SESSION);

        // 无 Session,既已被注销或者没有登录
        if (user == null) {
            // 移除后,再次登录跳转到 error.jsp 页面
//            System.out.println("没有查到用户");
            response.sendRedirect(request.getContextPath() + "/error.jsp");
        } else {
            filterChain.doFilter(servletRequest, servletResponse); // 继续执行程序,注意是 servletRequest, servletResponse, 不是提取的 request,response
        }
    }

    @Override
    public void destroy() {

    }
}

2. 注册过滤器

web.xml 中进行注册,jsp 文件下所有页面都要过这个过滤器

    <filter>
        <filter-name>SysFilter</filter-name>
        <filter-class>com.uestc.filter.SysFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>SysFilter</filter-name>
        <url-pattern>/jsp/*</url-pattern>
    </filter-mapping>

启动 tomcat,并登录,然后复制主页的 url 记录:http://localhost:8080/smbms/jsp/frame.jsp,并点击退出系统
在这里插入图片描述

在导航栏输入刚刚的访问链接 http://localhost:8080/smbms/jsp/frame.jsp,无法再次访问,成功注销
在这里插入图片描述

密码修改

实现增删改查,必须自低向上去编写

1. 导入前端素材

在这里插入图片描述

<li><a href="${pageContext.request.contextPath }/jsp/pwdmodify.jsp">密码修改</a></li>

点击密码修改后弹出如下
在这里插入图片描述

如果点击密码修改没有出现如下页面,而是 404,说明缺少对应页面:pwdmodify.jsp
在这里插入图片描述

pwdmodify.jsp 以及 pwdmodify.js 的配合完成的,及这个密码修改是前端完成的,没有交给后端完成。
在这里插入图片描述

pwdmodify.jsp 基本的外形
在这里插入图片描述

pwdmodify.js 进行一些逻辑规则
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在 pwdmodify.jsp 中,可以找到处理表单的请求为 /jsp/user.do,因此我们要去完善这个请求。
在这里插入图片描述

通常访问网页,前端会去请求 servlet,Servlet 调用 service,service 会调用 Dao 层操作数据库,因此写代码从低层开始往上写,边写边思考架构

在这里插入图片描述

现在我们需要修改密码,也就是根据用户 id,将数据库中的密码修改了,
在这里插入图片描述

1. UserDao 到 UserService 中逐步添加修改密码的方法

先在接口 UserDao 中定义更新密码的接口方法

int updatePwd(Connection connection, int id, String password) throws SQLException;

在这里插入图片描述

UserDaoImpl 中实现该更新密码方法,返回 1 说明修改成功

    @Override
    public int updatePwd(Connection connection, int id, String password) throws SQLException {

        PreparedStatement pstm = null;
        int execute = 0;

        if (connection != null) {
            String sql = "update smbms_user set userPassword = ? where id = ?";
            Object[] params = {password, id};
            try {
                execute = BaseDao.execute(connection, pstm, sql, params);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            BaseDao.closeResource(null, pstm,null); // 只需要关闭 pstm,因为其他都是空
        }
        return execute;
    }

然后业务层接口 UserService 定义修改密码的方法

boolean updatePwd(int id, String pwd);

业务层 UserServiceImpl 实现 updatePwd

    @Override
    public boolean updatePwd(int id, String pwd) {
        Connection connection = null;
        boolean flag = false;

        try {
            connection = BaseDao.getConnection(); // 连接数据库

            // 调用 Dao 层修改密码
            if (userDao.updatePwd(connection, id, pwd) > 0) {
                flag = true; // 成功修改
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            BaseDao.closeResource(connection, null, null); // 关闭资源
        }
        return flag;
    }
servlet 记得实现复用,要提取出方法!

在 dao层 和 service层 自己写映射类和实现类

下面是 servlet 层的主体,可以先注册好 web.xml,因为这个请求是写死了得

    <servlet>
        <servlet-name>UserServlet</servlet-name>
        <servlet-class>com.uestc.servlet.user.UserServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>UserServlet</servlet-name>
        <url-pattern>/jsp/user.do</url-pattern>
    </servlet-mapping>

如果上述请求改一处,就要把前端页面中所有 /jsp/user.do 的请求都改掉
在这里插入图片描述

UserServlet 类,响应密码修改,并调用业务层,业务层调用Dao层,实现底层数据库的用户密码修改(因为 doGet 要实现增删改查,所以将 updatePwd 提取出来,而不是直接写再 doGet 方法内)

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


    private void updatePwd(HttpServletRequest req, HttpServletResponse resp) {
        // 从 Session 中拿到用户 ID
        Object o = req.getSession().getAttribute(Constants.USER_SESSION); // 用户 ID 通过 session 获取
        String newpassword = req.getParameter("newpassword");
        boolean flag = false;

        if (o != null && !StringUtils.isNullOrEmpty(newpassword)) {
            UserService userService = new UserServiceImpl();
            flag = userService.updatePwd(((User) o).getId(), newpassword); // (User) o 强制类型转换
            if (flag) {
                //修改密码成功,移除Session
                req.setAttribute("message", "修改密码成功,请用新密码重新登录");
                req.getSession().removeAttribute(Constants.USER_SESSION);
            } else {
                req.setAttribute("message", "修改密码失败");
            }
        } else {
            req.setAttribute("message", "新密码有问题");
        }

        try {
            req.getRequestDispatcher("pwdmodify.jsp").forward(req, resp);
        } catch (ServletException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  • 代码中 message 与 pwdmodify.jsp 中的一段代码 <div class="info">${message}</div> 是对应的

旧密码是用 AJAX 来进行验证的,所以这里要先将此功能注释掉,在 js 文件夹的 pwdmodify.js 中去掉最下面的如下所示的代码,及把旧密码的判断去掉
在这里插入图片描述

否则会导致在密码修改点击保存时,没有反应
在这里插入图片描述

没有反应是因为 UserServlet 的 updatePwd 方法,一直走的是 req.getRequestDispatcher(“pwdmodify.jsp”).forward(req, resp); 没有真正执行密码修改逻辑部分(旧密码要使用 AJAX 的方法)

注释掉后,重新启动,输入新密码,就有反应啦
在这里插入图片描述

同时可以在页面点击检查,来查看请求是否正确
在这里插入图片描述

可以看到正确请求了 pwdmodify.jsp
在这里插入图片描述

点击确定即可成功修改,数据库 admin 的密码发生了改变
在这里插入图片描述

对于旧密码的判断,一种方法是放入到 UserServlet 的处理中,将旧密码与 session 中的密码进行对比判断,但是效率不高
在这里插入图片描述

优化密码修改使用 Ajax(Ajax验证旧密码实现)

1. 阿里巴巴的 fastjson

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.68</version>
</dependency>

先来看 pwdmodify.js 的就旧密码是如何使用 Ajax 的
在这里插入图片描述

验证旧密码不需要将接口方法写入到 Dao 层中,因为 session 中有用户的密码,直接使用 Servlet 即可。

在这里插入图片描述

pwdmodify.js 的旧密码验证,是键值对的形式,其中:data:{method:“pwdmodify”,oldpassword:oldpassword.val()}, oldpassword.val() 表示是从前端获取,key 为 oldpassword,因此在 UserServlet 类的 pwdmodify 方法中,通过 req.getParameter(“oldpassword”); 来获取 oldpassword
在这里插入图片描述

web.xml 注册设置过期时间,为 30 分钟

    <!--    默认 Session 过期时间:真实业务需求-->
    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>

继续看 pwdmodify.js:注意会传入 data 这个数据,data.result 是自己定义的属性

在这里插入图片描述

在 pom.xml 中引入阿里巴巴的 fastjson

    <dependency>
      <groupId>com.alibaba.fastjson2</groupId>
      <artifactId>fastjson2</artifactId>
      <version>2.0.40</version>
    </dependency>

通过 UserServlet 类中定义 pwdmodify 方法,实现密码验证

    // 验证旧密码, Session 中有用户的密码
    private void pwdmodify(HttpServletRequest req, HttpServletResponse resp) {
        // 从 Session 内获取用户 ID
        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) { // o == null 会导致 Session 失效或过期
            //1.Session失效了或者Session过期了
            resultMap.put("result", "sessionerror"); // 走 pwdmodify.js 中 data.result == "sessionerror" 部分
        } else if (StringUtils.isNullOrEmpty(oldpassword)) { //旧密码输入为空
            //输入为空
            resultMap.put("result", "error"); // 走 pwdmodify.js 中 data.result == "error" 部分
        } else {
            //获取Session中的用户密码
            String userPassword = ((User) o).getUserPassword();
            //判断输入的旧密码是否与当前Session中的密码一致
            if (oldpassword.equals(userPassword)) {
                resultMap.put("result", "true"); // 密码正确,走 data.result == "true" 部分
            } else { //旧密码输入不正确
                resultMap.put("result", "false");
            }
        }

        try {

            // 将上述的一系列判断返回 json 值
            resp.setContentType("application/json"); //就像resp.setContentType("text/html")
            PrintWriter writer = resp.getWriter(); // 定义流处理
            //JSONArray:阿里巴巴的JSON工具类,转换格式
            /* resultMap输出出来是{"result","sessionerror" , "result","error"}一对对的键值对 HashMap<K,V>
               Json格式={key:value}
            * */
            writer.write(JSONArray.toJSONString(resultMap));

            //最后刷新和关闭流资源
            writer.flush();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

以上方法是 AJAX 方式,通过 js 配合实现,是企业常用方式,也可以通过自己写一个类验证,然后在 web.xml 中注册来实现。

启动 tomcat,进行验证,进入密码修改栏目,旧密码出如果输入正确会打勾
在这里插入图片描述

如果输入错误会打叉
在这里插入图片描述

通过检查网页元素,中的网络查看请求,当打开检查,并在旧密码处进行输入时,会看到如下发送了一次请求,AJAX 是异步的
在这里插入图片描述

显示的那条请求分析如下:
在这里插入图片描述

后台处理并返回这个响应 {“result”:“false”}
在这里插入图片描述

这里有 AJAX 返回的代码中看到的键值对 data:{method:“pwdmodify”,oldpassword:oldpassword.val()},
在这里插入图片描述

这里的乱码,需要在 js 里面解决掉,这是来源于 js 的
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值