文章目录
前言
本文是对会话跟踪编程的实践,主要通过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
流程
- 把需要
Web Server
跟踪的数据,写入到Cookie
对象中。 - 服务器从客户端发送的
Cookie
读取。 Cookie
由Server
端创建,Server
端发送一次给客户端。- 客户端每次请求浏览器会自动发送
Cookie
, Server
可以取得客户端发送的Cookie
,取出保存的信息。
只能传输字符串信息,而且个数和大小有限制。
Cookie
编程
-
创建
Cookie
:Cookie c1=new Cookie(String name,String value); // 案例: Cookie userCookie=new Cookie("userid",id);
-
设置
Cookie
的生存周期:// 参数:int,秒数 Cookie.setMaxAge(int second) // 案例:设置让客户端保存一周 userCookie.setMaxAge(7*24*60*60);
如果不设置生存周期长度,默认是关闭浏览器,
Cookie
自动删除。 -
发送
Cookie
到客户端://通过响应对象的addCookie方法实现发送Cookie到客户端: response.addCookie(Cookie cookie); // Cookie在响应头中,一个响应头可以包含多个Cookie // 案例: response.add(userCookie);
客户端发送
Cookie
给Server
。每次请求客户端自动发送所有未过期的Cookie
,Cookie
在请求头中保存。 -
Server
端取得客户端发送的Cookie
Cookie[] cs=request.getCookies();
-
取得指定的
Cookie
对象保存的数据for(Cookie c:cs){ if(c.getName().equals("userid")){ userid=c.getValue(); } }
Cookie
的缺点
- 使用
Cookie
实现会话跟踪时,如果客户端设置了禁止Cookie
的写入,则无法实现使用Cookie
完成会话跟踪功能。 Cookie
只能保存String
类型,每个Cookie
只能存一个字符串对象。- 浏览器存储
Cookie
的个数是有限制的。存储的字符串容量也有限制。
1.4 JavaEE Web的Session对象
Session
流程
Session
对象在Server
端保存,每个客户端请求时,Server
创建对应的Session
对象。Server
把Session
的ID自动保存Cookie
里,发送给客户端。- 客户端以后请求,自动发送所有的
Cookie
,包括有sessionid
的Cookie
。 Server
端自动取得有sessionid
的Cookie
。- 取得其
sessionid
,定位到指定的Session
对象。
Session
编程
-
Servlet
取得Session
HttpSession session=request.getSession();
Server
从请求头中取得保存session id
的Cookie
,与指定的Session
对象关联。无参数的
getSession()
,如果没有session
对象,则创建新的;如果有session
对象,则关联到此对象。HttpSession session=request.getSession(boolean);
当参数为
true
时,与getSession()
相同:HttpSession session=request.getSession(true)
;当参数为
false
时,如果有session
对象存在,则返回此session
对象;如果没有session
对象,则返回null
, 不会创建新的会话对象。 -
JSP
中取得Session
每次请求
JSP
时,JSP
自动取得现有的Session
对象,如果没有Session
对象,则自动调用request.getSession()
取得新的session
对象
并赋值给变量:session
(session
是JSP
的内置对象,不需要声明和定义)。
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数据库的内容
字段名 | 类型 | 说明 |
---|---|---|
id | int | 用户ID |
username | varchar(50) | 用户账号 |
password | varchar(50) | 用户密码 |
4. 后端部分的编写
文件结构
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");
}
}