JavaEE学习第四课 会话跟踪编程


前言

本文是对会话跟踪编程的实践,主要通过Cookie编程和Session编程的方式来实现对会话的跟踪。只要体现为对账号和保存天数的跟踪。


1. JavaEE会话编程的四种方式

1.1 URL重写(用于GET请求)

将客户端信息附加在请求地址上:

// url?参数名=参数值&名=值.....
   add.jsp?userid=lhd

1.2 隐藏域(用于POST请求)

<form action="add.do" method="post">
....
<input type="hidden" name="userid" value="${userid}" />
</form>

此方式用于表单提交,与URL重写类似。

1.3 Cookie方式

Cookie流程

  1. 把需要Web Server跟踪的数据,写入到Cookie对象中。
  2. 服务器从客户端发送的Cookie读取。
  3. CookieServer端创建,Server端发送一次给客户端。
  4. 客户端每次请求浏览器会自动发送Cookie
  5. Server可以取得客户端发送的Cookie,取出保存的信息。

只能传输字符串信息,而且个数和大小有限制。

Cookie编程

  1. 创建Cookie

    Cookie c1=new Cookie(String name,String value);
    // 案例:
    Cookie userCookie=new Cookie("userid",id);
    
  2. 设置Cookie的生存周期:

    // 参数:int,秒数
    Cookie.setMaxAge(int second)
        
    // 案例:设置让客户端保存一周
    userCookie.setMaxAge(7*24*60*60);
    

    如果不设置生存周期长度,默认是关闭浏览器,Cookie自动删除。

  3. 发送Cookie到客户端:

    //通过响应对象的addCookie方法实现发送Cookie到客户端:
    response.addCookie(Cookie cookie);
    // Cookie在响应头中,一个响应头可以包含多个Cookie
    // 案例:
    response.add(userCookie);
    

    客户端发送CookieServer。每次请求客户端自动发送所有未过期的CookieCookie在请求头中保存。

  4. Server端取得客户端发送的Cookie

    Cookie[] cs=request.getCookies();
    
  5. 取得指定的Cookie对象保存的数据

    for(Cookie c:cs){
        if(c.getName().equals("userid")){
            userid=c.getValue();
        }
    }
    

Cookie的缺点

  1. 使用Cookie实现会话跟踪时,如果客户端设置了禁止Cookie的写入,则无法实现使用Cookie完成会话跟踪功能。
  2. Cookie只能保存String类型,每个Cookie只能存一个字符串对象。
  3. 浏览器存储Cookie的个数是有限制的。存储的字符串容量也有限制。

1.4 JavaEE Web的Session对象

Session流程

  1. Session对象在Server端保存,每个客户端请求时,Server创建对应的Session对象。
  2. ServerSession的ID自动保存Cookie里,发送给客户端。
  3. 客户端以后请求,自动发送所有的Cookie,包括有sessionidCookie
  4. Server端自动取得有sessionidCookie
  5. 取得其sessionid,定位到指定的Session对象。

Session编程

  1. Servlet取得Session

    HttpSession session=request.getSession(); 
    

    Server从请求头中取得保存session idCookie,与指定的Session对象关联。

    无参数的getSession(),如果没有session对象,则创建新的;如果有session对象,则关联到此对象。

    HttpSession session=request.getSession(boolean);
    

    当参数为true时,与getSession()相同:HttpSession session=request.getSession(true);

    当参数为false时,如果有session对象存在,则返回此session对象;如果没有session对象,则返回null, 不会创建新的会话对象。

  2. JSP中取得Session

    每次请求JSP时,JSP自动取得现有的Session对象,如果没有Session对象,则自动调用request.getSession()取得新的session对象
    并赋值给变量:sessionsessionJSP的内置对象,不需要声明和定义)。

2. 前端页面书写

2.1 login页面

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
    <h2>用户登录</h2>
    <form action="login.do" method="post">
        用户ID: <input type="text" name="username" required><br>
        密码: <input type="password" name="password" required><br>
        保存天数:<br>
        <input type="radio" name="days" value="1" required> 1 天<br>
        <input type="radio" name="days" value="2"> 2 天<br>
        <input type="radio" name="days" value="3"> 3 天<br>
        <input type="submit" value="登录">
    </form>
</body>
</html>

2.2 main页面

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>主页</title>
</head>
<body>
<%
    // 获取Cookie
    Cookie[] cookies = request.getCookies();
    String rememberedUser = null;
    if (cookies != null) {
        for (Cookie cookie : cookies) {
            if ("username".equals(cookie.getName())) { // 确保cookie名称与登录时一致
                rememberedUser = cookie.getValue();
            }
        }
    }

    // 获取session中保存的用户ID和保存天数
    String username = (session != null) ? (String) session.getAttribute("username") : null;
    String saveDays = (session != null) ? (String) session.getAttribute("rememberMe") : null;
%>
    <h1>主页</h1>
    <p>Session 用户ID: <%= username != null ? username : "无" %></p>
    <p>Cookie 用户ID: <%= rememberedUser != null ? rememberedUser : "无" %></p>
    <p>保存选项天数: <%= saveDays != null ? saveDays : "未设置" %></p>
    <a href="logout.do">注销</a>
</body>
</html>

3.Mysql数据库的内容

字段名类型说明
idint用户ID
usernamevarchar(50)用户账号
passwordvarchar(50)用户密码

image-20241007132209274

4. 后端部分的编写

文件结构

image-20241007132531653

4.1 UserLoginController

package com.city.erp.controller;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.sql.*;

// Servlet 映射到 "/login.do"
@WebServlet("/login.do")
public class UserLoginController extends HttpServlet {
    private Connection dbconn; // 用于存放数据库连接的数据

    @Override
    public void init() throws ServletException {
        // 数据库连接字符串,包含数据库名称、用户名和密码
        String dbUrl = "jdbc:mysql://127.0.0.1:3306/cityoa?useSSL=false&serverTimezone=UTC";
        String username = "root";  // MySQL用户名
        String password = "root";  // MySQL密码

        try {
            // 加载MySQL的JDBC驱动
            Class.forName("com.mysql.cj.jdbc.Driver");

            // 建立数据库连接
            dbconn = DriverManager.getConnection(dbUrl, username, password);
            System.out.println("Database connected successfully!");

        } catch (ClassNotFoundException e) {
            // 如果找不到JDBC驱动,抛出异常
            throw new ServletException("JDBC Driver not found", e);
        } catch (SQLException e) {
            // 如果连接数据库时发生错误,抛出异常
            throw new ServletException("Error connecting to the database", e);
        }
    }

    @Override
    public void destroy() {
        // Servlet被销毁时关闭与数据库的连接
        try {
            if (dbconn != null && !dbconn.isClosed()) {
                dbconn.close(); // 关闭连接
                System.out.println("Database connection closed.");
            }
        } catch (SQLException e) {
            e.printStackTrace(); // 打印异常信息
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 转发请求到 login.jsp 页面以显示登录表单
        RequestDispatcher dispatcher = request.getRequestDispatcher("/login/login.jsp");
        dispatcher.forward(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        // 获取用户输入的用户名、密码和保存天数
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String days = request.getParameter("days");

        // 检查用户名和密码是否为空
        if (username == null || password == null) {
            response.sendRedirect("main.do"); // 如果为空,重定向到主页
            return;
        }

        try (PreparedStatement ps = dbconn.prepareStatement("SELECT * FROM oa_employee WHERE username = ? AND password = ?")) {
            // 设置 SQL 查询中的参数
            ps.setString(1, username);
            ps.setString(2, password);
            ResultSet rs = ps.executeQuery(); // 执行查询

            if (rs.next()) { // 用户存在
                HttpSession session = request.getSession(); // 创建或获取会话
                Cookie cookie = new Cookie("username", username); // 创建 Cookie 存储用户名
                cookie.setMaxAge(Integer.parseInt(days) * 24 * 60 * 60); // 设置 Cookie 的生存时间
                response.addCookie(cookie); // 将 Cookie 添加到响应中

                // 将用户名和记住我选项存储到 Session
                session.setAttribute("username", username);
                session.setAttribute("rememberMe", days + " days");

                response.sendRedirect("main.do"); // 登录成功,重定向到主页
            } else {
                response.sendRedirect("login.do"); // 用户不存在,重定向回登录页面
            }
        } catch (SQLException e) {
            e.printStackTrace(); // 打印异常信息
            response.sendRedirect("login.do"); // 出现错误时返回登录页面
        }
    }
}

4.2 MainPageShowController

package com.city.erp.controller;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;

@WebServlet("/main.do")
public class MainPageShowController extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 转发请求到 login.jsp 页面
        RequestDispatcher dispatcher = request.getRequestDispatcher("/main/main.jsp");
        dispatcher.forward(request, response);
    }
}

4.3 UserLogoutController

package com.city.erp.controller;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;

// 将此 Servlet 映射到 "/logout.do"
@WebServlet("/logout.do")
public class UserLogoutController extends HttpServlet {
    // 处理 GET 请求
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取当前会话,参数为 false 表示如果会话不存在则返回 null
        HttpSession session = request.getSession(false);
        
        // 如果会话存在,则无效化会话
        if (session != null) {
            session.invalidate(); // 销毁会话,清除所有会话数据
        }

        // 重定向到登录页面
        response.sendRedirect("login.do");
    }
}

5.结果展示

image-20241007133645887

image-20241007133722751

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值