SessionAttribute
本章聚焦 Spring MVC 从 Session 中读取已存在属性的机制。
@SessionAttribute用于将HttpSession中已有的属性绑定到控制器方法的参数上,它是只读的——只能获取,不能写入。理解它与@SessionAttributes的区别,是正确使用 Session 数据的关键。
定义与作用
@SessionAttribute 是方法参数级别的注解。它的作用是将当前 HttpSession 中已经存在的指定名称的属性值,自动注入到 Controller 方法的对应参数中。
核心特征:
- 只读不写:只能读取 Session 中已有的属性,不会在 Session 中创建新属性
- 前提条件:Session 中必须已经存在该属性,否则抛出
HttpSessionRequiredException - 类型转换:Spring MVC 会自动进行类型转换,如果类型不匹配会抛出异常
生活类比:档案室取阅
想象飞翔科技的档案室:
@SessionAttribute:你拿着档案编号去档案室取阅已有的档案。如果档案不存在,管理员会告诉你"查无此档"(抛异常)。你只能在阅览区查看,不能把新档案存进去。@SessionAttributes(下一章讲解):这是档案管理员的工作——把新审批通过的档案自动归档到档案室,供后续查阅。
核心原理
Session 属性读取流程
解析时机:@SessionAttribute 的参数解析由 SessionAttributeMethodArgumentResolver 负责。它在参数绑定阶段工作,与 @RequestAttribute 类似,但数据源是 HttpSession 而非 HttpServletRequest。
适用位置与常用属性
| 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|
value / name | String | 是(二选一) | Session 中属性的名称 |
required | boolean | 否 | 属性是否必须存在,默认 true。设为 false 时,不存在则注入 null |
适用位置
- Controller 方法参数:将 Session 属性绑定到方法形参
@GetMapping("/profile")
public String viewProfile(
@SessionAttribute("user") User user) { // 必须存在,否则抛异常
// ...
}
@GetMapping("/settings")
public String viewSettings(
@SessionAttribute(name = "user", required = false) User user) { // 可选
// user 可能为 null
}
完整示例
场景
飞翔科技员工管理系统中,用户登录成功后,用户信息被存入 Session。后续访问"个人中心""系统设置"等页面时,后端小崔需要从 Session 中读取当前登录用户,而不是每次都从请求参数中传递。
登录时写入 Session(前置步骤)
@PostMapping("/login")
public String login(@RequestParam String username,
@RequestParam String password,
HttpSession session) {
// 验证用户名密码...
User user = userService.authenticate(username, password);
session.setAttribute("user", user); // 存入 Session
return "redirect:/dashboard";
}
使用 @SessionAttribute 读取
package com.feixiang.web.controller;
import com.feixiang.web.entity.User;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.support.SessionStatus;
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/profile")
public Object getProfile(@SessionAttribute("user") User user) {
return Map.of(
"username", user.getUsername(),
"department", user.getDepartment(),
"role", user.getRole()
);
}
@GetMapping("/settings")
public Object getSettings(
@SessionAttribute(name = "user", required = false) User user) {
if (user == null) {
return Map.of("error", "未登录,请先登录");
}
return Map.of("theme", user.getPreferenceTheme(), "notify", user.isNotifyEnabled());
}
}
请求示例一:Session 中存在 user 属性
前置条件:用户已登录,session.setAttribute("user", user) 已执行。
curl -X GET http://localhost:8080/user/profile \
-H "Cookie: JSESSIONID=xxx"
响应:
{
"username": "xiaocui",
"department": "研发部",
"role": "后端工程师"
}
请求示例二:Session 中不存在 user 属性(required = false)
curl -X GET http://localhost:8080/user/settings
响应:
{
"error": "未登录,请先登录"
}
请求示例三:Session 中不存在 user 属性(required = true,默认)
curl -X GET http://localhost:8080/user/profile
响应(HTTP 500,未配置异常处理器时):
HttpSessionRequiredException: Expected session attribute 'user'
易错场景与面试考点
误区一:用 @SessionAttribute 向 Session 中写入数据
错误认知:"@SessionAttribute("user") 标注在参数上,如果 Session 中没有,Spring 会帮我创建一个放进去。"
纠正:@SessionAttribute 是只读的。如果 Session 中不存在指定属性且 required = true(默认),会直接抛出 HttpSessionRequiredException。它永远不会向 Session 中写入任何数据。
写入 Session 的正确方式:
- 使用
HttpSession.setAttribute()手动写入 - 使用
@SessionAttributes(类级别注解,下一章讲解)自动同步 Model 属性到 Session
误区二:混淆 @SessionAttribute 与 @SessionAttributes
| 维度 | @SessionAttribute | @SessionAttributes |
|---|---|---|
| 级别 | 方法参数 | 类 |
| 方向 | 只读(从 Session 取) | 读写(Model → Session 同步) |
| 创建属性 | ❌ 不会创建 | ✅ 会自动创建 |
| 清理方式 | 不适用 | 通过 SessionStatus.setComplete() |
| 典型用途 | 读取登录用户信息 | 跨请求保持表单数据(如多步骤向导) |
记忆口诀:带 s 的是类级别的复数形式,负责同步(Sync);不带 s 的是参数级别的单数形式,负责读取(Read)。
面试高频:Session 中属性不存在时的处理
问题:如何避免 @SessionAttribute("user") 在 Session 过期时抛异常?
回答:
- 设置
required = false,在方法内判断是否为null - 配合拦截器,在请求到达 Controller 前检查 Session 中是否存在登录信息,不存在则重定向到登录页
- 配置全局异常处理器捕获
HttpSessionRequiredException
@ExceptionHandler(HttpSessionRequiredException.class)
public ResponseEntity<?> handleSessionMissing() {
return ResponseEntity.status(401).body(Map.of("error", "登录已过期,请重新登录"));
}
小结
@SessionAttribute 用于将 HttpSession 中已存在的属性绑定到 Controller 方法参数。它是只读的,不会在 Session 中创建新属性。如果属性不存在且 required = true,会抛出 HttpSessionRequiredException。它适用于读取登录用户信息、权限信息等需要在整个会话期间保持的数据。
本章与全局的关系:本章讲解了从 Session 读取数据的方式。下一章"SessionAttributes"将讲解类级别的 Session 属性同步机制,以及如何在多步骤表单场景中跨请求保持数据。