Session 是服务器端用来跟踪用户状态的一种会话技术。它解决了“网站如何识别同一个用户发起的不同请求”这一核心问题,从而实现了跨页面的数据共享和用户身份的维持。
1. Session 的工作原理
Session 的基本工作流程如下:
-
创建 Session:当一个用户(客户端)首次访问服务器时,服务器会为其创建一个独一无二的 Session 对象。
-
生成 SessionID:与此同时,服务器会为这个 Session 对象生成一个唯一的标识符,即 SessionID。
-
返回 SessionID:服务器将这个 SessionID 通过响应发送回客户端浏览器。通常,这是通过创建一个名为 JSESSIONID 的 Cookie 来实现的。
-
后续请求:用户在后续访问该网站的其他页面时,浏览器会自动携带包含 SessionID 的 Cookie。
-
身份识别:服务器接收到请求后,会解析出 SessionID,并根据这个 ID 找到与之对应的 Session 对象,从而识别出是哪个用户,并可以访问之前存储在该 Session 中的数据。
-
图解:Session 机制--通过一个唯一的 SessionID 作为“信物”,在无状态的客户端和服务器之间建立起一种“有状态”的联系。
-
2. Session 与 Cookie 的主要区别
-
存储位置:
-
Cookie:数据存储在客户端浏览器中。
-
Session:数据存储在服务器端。SessionID(通常以 Cookie 的形式)存储在客户端,作为访问服务器端 Session 数据的凭证。
-
-
安全性:由于 Session 将敏感、重要的数据(如用户信息、购物车内容)保存在服务器端,相比于将所有数据都存放在客户端的 Cookie,安全性更高,可以有效减少服务器资源的浪费。
-
数据类型:Session 中可以存储任意类型的 Java 对象(Object),而 Cookie 只能存储字符串(String)。
3. HttpSession 接口的核心方法
-
数据存储与读取:
-
void setAttribute(String name, Object value):将一个对象以键值对的形式存入 Session。
-
Object getAttribute(String name):根据键名从 Session 中获取对应的对象。
-
void removeAttribute(String name):从 Session 中移除指定的键值对。
-
-
Session 管理:
-
String getId():获取当前 Session 唯一的 SessionID。
-
void invalidate():立即使当前 Session 失效,清空所有存储的数据。 这通常用于用户登出操作。
-
boolean isNew():判断当前 Session 是否是新创建的,而不是从客户端的请求中获取的既有 Session。
-
-
生命周期管理:
-
long getCreationTime():获取 Session 的创建时间。
-
long getLastAccessedTime():获取客户端最后一次访问该 Session 的时间。
-
void setMaxInactiveInterval(int interval):设置 Session 的最大非活动时间(单位:秒),超过该时间未被访问,Session 将自动失效。
-
4. Session 的实际应用
-
获取 Session 对象:在 Servlet 中,通过 HttpServletRequest 对象的 getSession() 方法来获取 HttpSession 对象,如:HttpSession session = req.getSession();。
-
存储和读取数据:
-
存储:session.setAttribute("name", "小明"); 将一个字符串存入 Session。类似Python字典一个key--name,一个value--小明。
-
读取:String name= (String ) session.getAttribute("name"); 原来类型为Object,为了实现在 Session 中读取数据,进行强制类型转换。
-
-
销毁 Session:
-
手动销毁:调用 session.invalidate(); 方法可以立即让 Session 失效。
-
自动销毁:可以通过在 web.xml 文件中配置 <session-timeout> 标签来设定 Session 的默认超时时间(单位:分钟)。
-
5 示例代码
1:利用 Session 机制在多个请求间共享数据(用户名 "张三"
)
SessionServlet:
public class SessionServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
req.setCharacterEncoding("utf-8");
HttpSession session = req.getSession();
session.setAttribute("username", "张三");
String id = session.getId();
if (session.isNew()) {
resp.getWriter().print("这是你第一次访问本站,你的id是:"+ id);
}else {
resp.getWriter().print("欢迎回来,你的id是:" + id);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
SessionServlet02:
public class SessionServlet02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
req.setCharacterEncoding("utf-8");
HttpSession session = req.getSession();
String username = (String)session.getAttribute("username");
resp.getWriter().print("欢迎回来"+username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
2:通过Servlet验证用户身份,利用Session在不同请求之间保持用户的登录状态,并根据登录状态决定是显示受保护的用户信息页面还是返回登录页面。(利用Session保存类信息)
User: 一个简单的Java类(POJO),用于封装用户的数据,包含姓名、地址、民族和描述等属性。
public class User {
private String userName;
private String address;
private String grooup;
private String description;
public User(String address, String userName, String grooup, String description) {
this.address = address;
this.userName = userName;
this.grooup = grooup;
this.description = description;
}
public User() {
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getGrooup() {
return grooup;
}
public void setGrooup(String grooup) {
this.grooup = grooup;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
登录页面 (Login.jsp)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Login</title>
</head>
<body>
<h2>请输入账号密码进行登录</h2>
<form action="${pageContext.request.contextPath}/LoginServlet01" method="get">
用户名:<input type="text" name="username"><br>
密 码:<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
认证 Servlet (SessionServlet01)
public class SessionServlet01 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
if ("admin".equals(username) && "123456".equals(password)) {
User user = new User("广东省潮州市","Wuguangzhi","han","是个好人");
HttpSession UserSession = req.getSession();
UserSession.setAttribute("username", username);
UserSession.setAttribute("user", user);
resp.sendRedirect("LoginServlet02");
}else {
resp.sendRedirect("Login.jsp");
}
}
}
会话验证 Servlet (SessionServlet02)
public class SessionServlet02 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
HttpSession session = req.getSession(false);
if (session != null && session.getAttribute("user") != null) {
// 用户已登录,转发到JSP页面进行展示
req.getRequestDispatcher("/index.jsp").forward(req, resp);
} else {
// 用户未登录或Session已失效,重定向到登录页面
resp.sendRedirect("Login.jsp");
}
}
}
用户信息展示页面 (index.jsp)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index</title>
</head>
<body>
<h2>欢迎您,${sessionScope.username}</h2><br>
<h1>具体信息如下:</h1><br>
<h2>用户名字: ${sessionScope.user.userName}</h2><br>
<h2>用户地址: ${sessionScope.user.address}</h2><br>
<h2>用户民族: ${sessionScope.user.grooup}</h2><br>
<h2>用户描述: ${sessionScope.user.description}</h2><br>
</body>
</html>
-
Servlets (SessionServlet01, SessionServlet02): Java类,负责处理后端的业务逻辑,例如验证用户身份、管理会话和控制页面流程。
-
JSP 文件 (Login.jsp, index.jsp): 用于构建表示层,即用户看到的Web界面,并动态展示数据。