什么是 Session?
Session(会话)是一种在服务器端维护用户状态的机制,当用户访问一个网站时,服务器会为该用户创建一个唯一的 Session ID,并将其通过 Cookie 发送到客户端浏览器,之后,用户每次发送请求时,浏览器都会带上这个 Session ID,服务器通过这个 ID 就能找到对应的 Session 对象,从而获取或存储与该用户相关的数据。
一个简单的比喻:
- Session ID:就像一张餐厅的桌号牌(A3 桌)。
- Session 对象:就是那张 A3 桌,服务员(服务器)可以在桌上放菜单(数据)、水杯(数据)等。
- 用户:就是坐在 A3 桌的顾客。
- Cookie:就是顾客离开时带走的桌号牌,下次来时出示,服务员就知道他该回 A3 桌了。
如何给 Session 赋值?(代码示例)
在 Java Web 开发中,最常用的技术栈是 Servlet 和 Spring MVC,下面分别介绍在这两种框架中如何给 Session 赋值。
在原生 Servlet 中赋值
在 Servlet 中,我们可以通过 HttpServletRequest 对象来获取和操作 Session。
步骤:
- 通过
request.getSession()方法获取HttpSession对象。这是最关键的一步。- 如果该用户的 Session 已经存在,则返回现有的 Session 对象。
- 如果该用户的 Session 不存在,则会创建一个新的 Session 对象。
- 获取到
HttpSession对象后,调用其setAttribute(String name, Object value)方法来存入数据。
示例代码:
假设有一个登录的 Servlet,用户登录成功后,我们将用户信息存入 Session。
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 获取用户提交的登录信息
String username = request.getParameter("username");
String password = request.getParameter("password");
// 2. 模拟业务逻辑验证(实际项目中这里会查询数据库)
if ("admin".equals(username) && "123456".equals(password)) {
// 登录成功,将用户信息存入 Session
// 关键步骤:获取 Session 对象
HttpSession session = request.getSession();
// 3. 给 Session 赋值(存入数据)
// 参数1: 属性名 (String)
// 参数2: 属性值 (Object)
session.setAttribute("user", username); // 存入用户名
session.setAttribute("loginTime", System.currentTimeMillis()); // 存入登录时间戳
// 可以存入一个自定义的 User 对象
// User user = new User(username, "admin@example.com");
// session.setAttribute("currentUser", user);
System.out.println("用户 " + username + " 登录成功,数据已存入 Session。");
// 重定向到主页
response.sendRedirect("welcome.jsp");
} else {
// 登录失败,返回登录页面
response.sendRedirect("login.jsp?error=1");
}
}
}
在 Spring MVC 中赋值
Spring MVC 提供了更简洁、更强大的方式来操作 Session。
通过 HttpSession 参数注入
在 Controller 方法中,可以直接将 HttpSession 作为参数传入,Spring 会自动为你注入。
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpSession;
@Controller
public class LoginController {
@PostMapping("/login")
public String login(@RequestParam String username,
@RequestParam String password,
HttpSession session) {
// 模拟登录验证
if ("admin".equals(username) && "123456".equals(password)) {
// 直接使用 session 对象进行赋值,和 Servlet 中一样
session.setAttribute("user", username);
session.setAttribute("loginTime", System.currentTimeMillis());
System.out.println("用户 " + username + " 在 Spring MVC 中登录成功。");
// 登录成功后,跳转到主页视图
return "redirect:/welcome"; // 使用 "redirect:" 前缀进行重定向
} else {
// 登录失败,返回登录页面
return "login"; // 返回逻辑视图名,对应 login.jsp
}
}
}
使用 @SessionAttributes 注解(推荐用于复杂场景)
这个注解可以将 Model 中的数据自动同步到 Session 中,它适用于需要将多个数据存入 Session,并且希望这些数据在多个请求之间保持的场景。
工作原理:
- 在 Controller 类上使用
@SessionAttributes注解,指定哪些属性名需要存入 Session。 - 在 Controller 方法中,向
Model或ModelMap添加数据。 - 当方法执行完毕后,Spring 会检查 Model 中的数据,如果其属性名在
@SessionAttributes的列表中,就会自动将其存入 Session。
示例代码:
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
// 告诉 Spring,将名为 "user" 和 "cart" 的属性存入 Session
@SessionAttributes({"user", "cart"})
@Controller
public class ShoppingCartController {
// 添加商品到购物车
@PostMapping("/addToCart")
public String addToCart(@RequestParam String item, Model model) {
// 1. 从 Session 中获取购物车(如果不存在,会创建一个空的 Map)
// 注意:这里直接从 Model 中获取,Spring 会负责从 Session 中同步
Map<String, Integer> cart = (Map<String, Integer>) model.getAttribute("cart");
if (cart == null) {
cart = new HashMap<>();
}
// 2. 更新购物车数据
cart.put(item, cart.getOrDefault(item, 0) + 1);
// 3. 将更新后的购物车放回 Model
// Spring 会检测到 "cart" 在 @SessionAttributes 列表中,自动将其存入 Session
model.addAttribute("cart", cart);
// 模拟一个登录用户并存入 Session
model.addAttribute("user", "JohnDoe");
return "cart"; // 返回购物车页面
}
// 查看购物车
@GetMapping("/cart")
public String viewCart(Model model) {
// 可以直接从 Model 中获取 "cart" 和 "user"
// 因为它们已经被 @SessionAttributes 自动存入 Session 了
Map<String, Integer> cart = (Map<String, Integer>) model.getAttribute("cart");
String user = (String) model.getAttribute("user");
System.out.println("当前用户: " + user);
System.out.println("购物车内容: " + cart);
return "cart";
}
}
从 Session 中获取值
赋值之后,自然也需要知道如何获取。
Servlet 中获取
HttpSession session = request.getSession();
String username = (String) session.getAttribute("user");
Long loginTime = (Long) session.getAttribute("loginTime");
if (username != null) {
System.out.println("从 Session 中获取到用户: " + username);
}
Spring MVC 中获取
@GetMapping("/welcome")
public String welcome(HttpSession session, Model model) {
// 方法1:直接通过 HttpSession 获取
String username1 = (String) session.getAttribute("user");
// 方法2:通过 Model 获取(当使用 @SessionAttributes 时更方便)
// Spring 会自动将 Session 中的数据注入到 Model 中
String username2 = (String) model.getAttribute("user");
return "welcome";
}
最佳实践和注意事项
- 只存必要的数据:Session 存储在服务器内存中,会消耗服务器资源,不要将大对象(如整个 List、文件流等)存入 Session。
- 使用 POJO (Plain Old Java Object):推荐将相关的数据封装在一个 Java 对象(如
User,Cart)中,然后将这个对象存入 Session,而不是存散乱的多个属性,这样更易于管理和维护。 - 处理 Session 过期:Session 有一个生命周期(由
web.xml中的session-timeout配置,默认 30 分钟),在获取 Session 数据时,一定要进行 非空判断,避免因 Session 过期导致的NullPointerException。 - 及时清理:当用户退出登录时,应该主动清除 Session 中的数据,以释放资源并保护用户隐私。
// 在登出时清除 Session session.invalidate(); // 销毁整个 Session // 或者 session.removeAttribute("user"); // 只移除特定属性 - 线程安全:一个
HttpSession对象在同一个用户的多个请求之间是共享的,Session 中存储的对象会被多个线程并发修改(在异步处理中),你需要确保该对象是线程安全的,或者对修改操作进行同步。 - 安全性:Session ID 通过 Cookie 传输,确保你的应用配置了
HttpOnly和Secure属性,以防止 Session ID 被窃取(如跨站脚本攻击 XSS)。
| 操作 | Servlet | Spring MVC (推荐) |
|---|---|---|
| 获取 Session | request.getSession() |
在 Controller 方法中直接添加 HttpSession session 参数 |
| 赋值 | session.setAttribute("key", value) |
session.setAttribute("key", value) 或使用 @SessionAttributes + model.addAttribute() |
| 取值 | session.getAttribute("key") |
session.getAttribute("key") 或直接从 Model 中获取(当使用 @SessionAttributes 时) |
| 清除 | session.invalidate() 或 session.removeAttribute() |
同左 |
对于现代 Java Web 开发,Spring MVC 是主流选择,在简单的单次请求场景下,直接注入 HttpSession 即可,在需要跨多个 Controller 方法共享数据时,使用 @SessionAttributes 注解是更优雅、更结构化的方式。
