• Session会话机制的应用(用户登录)



    提示:以下是本篇文章正文内容,Java系列学习将会持续更新

    程序的流程

    1. 静态页面: login.html —(POST请求)—> /login.do
    2. 静态页面: register.html —(POST请求)—> /register.do
    3. 动态页面: URL+回车 —(GET请求)—> /publish.html
    4. 注册 —> 登录 —> 个人动态页面
    5. 用户只有登录后,才能访问到动态页面。

    正是Cookie + Session会话机制的应用:

    1. 用户成功登录后,服务器会生成一个session对象,来存储用户的登录状态。
    2. 服务器依赖cookie将 session-id传递给客户端(浏览器),客户端保存 cookie 值。
    3. 客户端(浏览器)每次请求的时候,都会携带 cookie 值。
      如果能对上,说明用户已经登录,则可以访问到个人动态页面。
      如果对不上,说明用户还没有登录,则访问不到,需要重新登录。

    main

    java

    dao

    UserDao
    // SQL 操作
    public class UserDao { // 单例模式, 饿汉式
    
        private static UserDao userDao = new UserDao();
        private UserDao() { }
        public static UserDao getUserDao() {
            return userDao;
        }
    
        public User selectOneByUsernameAndPassword(String username, String password) {
            try (Connection c = DBUtil.connection()) {
                String sql = "select uid from users where username = ? and password = ?";
                try (PreparedStatement ps = c.prepareStatement(sql)) {
                    ps.setString(1, username);
                    ps.setString(2, password);
    
                    System.out.println("执行 SQL: " + ps);
                    try (ResultSet rs = ps.executeQuery()) {
                        if (!rs.next()) {
                            return null;
                        }
    
                        return new User(rs.getInt("uid"), username, password);
                    }
                }
            } catch (SQLException exc) {
                throw new RuntimeException(exc);
            }
        }
    
        public User insert(String username, String password) {
            // TODO: 表中的username不能重复,暂时不考虑如何解决重复的问题
            try (Connection c = DBUtil.connection()) {
                String sql = "insert into users (username, password) values (?, ?)";
                try (PreparedStatement ps = c.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
                    ps.setString(1, username);
                    ps.setString(2, password);
                    ps.executeUpdate();
                    int uid;
                    try (ResultSet rs = ps.getGeneratedKeys()) {
                        rs.next();
                        uid = rs.getInt(1);
                    }
                    // 返回当前用户
                    return new User(uid, username, password);
                }
            } catch (SQLException exc) {
                throw new RuntimeException(exc);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    回到目录…

    model

    User
    public class User {
        public Integer uid;
        public String username;
        public String password;
    
        public User(int uid, String username, String password) {
            this.uid = uid;
            this.username = username;
            this.password = password;
        }
    
        // 检验用户名和密码合法性
        public static boolean isLegal(String username, String password) {
            if(username == null || password == null) {
                return false;
            }
            if(username.trim().isEmpty() || password.trim().isEmpty()) {
                return false;
            }
            return true;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            User user = (User) o;
            return Objects.equals(username, user.username) && Objects.equals(password, user.password);
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(username, password);
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "uid=" + uid +
                    ", username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    回到目录…

    servlet

    LoginServlet

    login.html发送 POST 请求,访问到 /login.do

    // 登录操作
    @WebServlet("/login.do")
    public class LoginServlet extends HttpServlet {
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 1. 读取 用户名 + 密码
            req.setCharacterEncoding("utf-8");
            String username = req.getParameter("username");
            String password = req.getParameter("password");
            // 检验输入的合法性检查
            if (!User.isLegal(username, password)) {
                // 不合法重新登录
                resp.sendRedirect("/login.html");
                return;
            }
            System.out.println("DEBUG: username=" + username);
            System.out.println("DEBUG: password=" + password);
    
            // 2. 在所有用户之中查找匹配(用户名和密码都相等)的用户
            UserDao userDao = UserDao.getUserDao();
            User currentUser = userDao.selectOneByUsernameAndPassword(username, password);
    
            // 3. 成功进行登录;失败跳回登录页
            if (currentUser == null) {
                // 登录失败
                // 重定向 /login.html
                resp.sendRedirect("/login.html");
                return;
            }
    
            // 进行登录 —— 只有登录才能创建会话
            HttpSession session = req.getSession(true);
            // 这里的 key 设置任何字符串都可以,只要以后一直统一使用即可
            session.setAttribute("currentUser", currentUser);
    
            // 表示登录成功
            resp.setCharacterEncoding("utf-8");
            resp.setContentType("text/plain");
            PrintWriter writer = resp.getWriter();
            writer.printf("欢迎 %s 使用我们的系统的", currentUser);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    回到目录…

    PublishServlet

    用户URL+回车发送 GET 请求,访问到 /publish.html

    // 动态显示页面。登陆后才能显示内容
    @WebServlet("/publish.html")
    public class PublishServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 1. 获取当前登录用户(从会话中读取)
            User currentUser = null;
            // 1.1 获取会话对象(session 对象)
            HttpSession session = req.getSession(false); // 参数必须写 false,确保不新建 session 会话
            if (session == null) {
                // 说明之前没有会话,所以更不可能存在当前用户对象
                resp.sendRedirect("/login.html");
                return;
            }
    
            // 说明 session 对象存在,从 session 对象中拿 当前用户对象
            // 当前用户对象是 LoginServlet 登录成功之后放到 session 对象中的
            currentUser = (User) session.getAttribute("currentUser");
            if (currentUser == null) {
                // 说明 session 存在,但当前用户对象不存在
                resp.sendRedirect("/login.html");
                return;
            }
    
            // 获取到当前用户了,currentUser
            resp.setCharacterEncoding("utf-8");
            resp.setContentType("text/html");
            PrintWriter writer = resp.getWriter();
            writer.printf("

    %s

    "
    , currentUser); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    回到目录…

    RegisterServlet

    register.html发送 POST 请求,访问到 /register.do

    // 注册操作
    @WebServlet("/register.do")
    public class RegisterServlet extends HttpServlet {
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 1. 读取 username + password
            req.setCharacterEncoding("utf-8");
            String username = req.getParameter("username");
            String password = req.getParameter("password");
            // 检验输入的合法性检查
            if (!User.isLegal(username, password)) {
                // 不合法重新注册
                resp.sendRedirect("/register.html");
                return;
            }
    
            // 2. 注册,向表中插入数据,通过 UserDao
            UserDao userDao = UserDao.getUserDao();
            User currentUser = userDao.insert(username, password);
    
            // 再次跳到登录界面
            resp.sendRedirect("/login.html");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    回到目录…

    util

    DBUtil
    public class DBUtil {
        private static final DataSource dataSource;
    
        static {
            MysqlDataSource mysqlDataSource = new MysqlDataSource();
            mysqlDataSource.setUrl("jdbc:mysql:///lianxi?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai");
            mysqlDataSource.setUser("root");
            mysqlDataSource.setPassword("123456");
    
            dataSource = mysqlDataSource;
        }
    
        public static Connection connection() throws SQLException {
            return dataSource.getConnection();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    回到目录…

    webapp

    WEB-INF

    web.xml
    
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                          http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
      version="3.1"
      metadata-complete="false">
    web-app>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    回到目录…

    login.html

    DOCTYPE html>
    <html lang="zh-hans">
    <head>
        <meta charset="UTF-8">
        <title>登录title>
    head>
    <body>
        <form action="/login.do" method="post">
            <input type="text" name="username">
            <input type="password" name="password">
            <button>登录button>
            <a href="./register.html">注册a>
        form>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    回到目录…

    register.html

    DOCTYPE html>
    <html lang="zh-hans">
    <head>
        <meta charset="UTF-8">
        <title>注册title>
    head>
    <body>
        <form action="/register.do" method="post">
            <input type="text" name="username">
            <input type="password" name="password">
            <button>注册button>
        form>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    回到目录…

    运行效果

    1. 注册
      在这里插入图片描述

    2. 登录
      在这里插入图片描述
      在这里插入图片描述

    3. 用户登录后的动态页面
      在这里插入图片描述

    回到目录…


    总结:
    提示:这里对文章进行总结:
    以上就是今天的学习内容,本文是JavaWeb的学习,在我们学会了session会话机制的条件下,我们可以做一个登录的小程序。之后的学习内容将持续更新!!!

  • 相关阅读:
    dubbo中几种protocol的理解
    Vue实现复制粘贴功能
    详解操作符
    四平方和,激光炸弹
    excel巧用拼接函数CONCAT输出JSON、SQL字符串
    【机器学习教程】五、支持向量机(Support Vector Machines)
    校园食堂明厨亮灶智能视频监控
    Default Probability
    基于R语言机器学习方法与案例分析实践技术
    《C++标准库第2版》3.2 虽旧犹新的语言特性 笔记
  • 原文地址:https://blog.csdn.net/qq15035899256/article/details/126391787