乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 SpringMVC概述与DispatcherServlet

    • 本章导读:Spring MVC概述与DispatcherServlet
    • Spring MVC 是什么
    • MVC 设计模式
    • 前端控制器模式
    • DispatcherServlet
    • 核心组件协作
  • 第2章 控制器与请求映射

    • 本章导读:控制器与请求映射
    • Controller
    • RestController
    • RequestMapping
    • GetMapping
    • PostMapping
    • PutMapping
    • DeleteMapping
    • PathVariable
    • RESTful
    • 请求映射原理
  • 第3章 请求参数获取与转换

    • 本章导读:请求参数获取与转换
    • RequestParam
    • RequestBody
    • RequestHeader
    • CookieValue
    • Model
    • ModelAttribute
    • 数据绑定原理
    • 数据校验
  • 第4章 响应数据与视图解析

    • 本章导读:响应数据与视图解析
    • ResponseBody
    • ResponseEntity
    • ModelAndView
    • ViewResolver
    • HttpMessageConverter
    • forward与redirect
  • 第5章 拦截器过滤器与跨域

    • 本章导读:拦截器、过滤器与跨域
    • HandlerInterceptor
    • WebMvcConfigurer
    • CrossOrigin
    • 登录验证实战
  • 第6章 文件上传与异常处理

    • 本章导读:文件上传与异常处理
    • MultipartFile
    • 文件下载
    • ExceptionHandler
    • ControllerAdvice
    • RestControllerAdvice
    • ResponseStatus
  • 第7章 高级特性与最佳实践

    • 本章导读:高级特性与最佳实践
    • SessionAttributes
    • SessionAttribute
    • RedirectAttributes
    • MockMvc测试
    • 国际化
    • 最佳实践
  • 第8章 扩展与异步机制

    • 本章导读:扩展与异步机制
    • 异步请求处理
    • 自定义参数解析器
    • 内容协商

SessionAttributes

本章聚焦 Spring MVC 跨请求保持会话数据的机制。@SessionAttributes 标注在控制器类上,将 Model 中的指定属性自动同步到 HttpSession,实现跨请求的会话级数据共享。它与 @SessionAttribute(参数级只读注解)形成互补,是多步骤表单、向导式流程等场景的利器。


定义与作用

@SessionAttributes 是类级别的注解,用于声明哪些 Model 属性需要自动同步到 HttpSession。当 Controller 方法向 Model 中添加指定名称的属性时,Spring MVC 会自动将其复制到 Session 中;后续请求中,即使方法不再向 Model 添加该属性,它依然可以从 Session 中恢复。

核心特征:

  • 自动同步:Model → Session 的同步由框架自动完成
  • 跨请求保持:属性在 Session 生命周期内对所有请求可见
  • 显式清理:需要通过 SessionStatus.setComplete() 标记清理,不会自动删除

生活类比:多步骤入职审批

想象飞翔科技的新员工入职流程分为三步:填写基本信息 → 上传证件 → 确认提交。每一步都是一个独立的 HTTP 请求:

  • 没有 @SessionAttributes:每进入下一步,上一步填写的数据就丢失了,因为每个请求都是无状态的
  • 使用 @SessionAttributes:架构师白歌在 Controller 类上标注 @SessionAttributes("employeeForm"),第一步把表单数据放进 Model,Spring MVC 自动同步到 Session。第二步、第三步即使不重新查询数据库,也能从 Session 中恢复 employeeForm 继续处理。全部完成后,调用 SessionStatus.setComplete() 清理 Session 中的临时数据。

核心原理

Model → Session 同步流程

同步时机:@SessionAttributes 的同步发生在拦截器 postHandle 阶段。当 Controller 方法执行完毕、Model 数据已准备就绪后,Spring MVC 检查类上的 @SessionAttributes 声明,将匹配的属性名同步到 Session。

恢复时机:在后续请求中,如果 Controller 方法的参数类型与 Session 中存储的类型匹配,且参数名(或 @ModelAttribute 指定名)与 @SessionAttributes 声明一致,Spring MVC 会自动从 Session 中恢复该对象并注入到参数中。


适用位置与常用属性

属性类型必填说明
valueString[]否需要同步到 Session 的 Model 属性名称数组
typesClass<?>[]否需要同步到 Session 的 Model 属性类型数组(按类型匹配)

适用位置

  • Controller 类:标注在类声明上
@Controller
@RequestMapping("/employee")
@SessionAttributes("employeeForm")  // 将 Model 中名为 employeeForm 的属性同步到 Session
public class EmployeeWizardController {
    // ...
}

也可以同时按名称和类型声明:

@SessionAttributes(value = {"employeeForm", "draftId"}, types = User.class)

完整示例

场景

飞翔科技的新员工入职采用三步向导式流程。CTO 大翔要求每一步的数据在 Session 中保持,直到最终提交。架构师白歌使用 @SessionAttributes 实现跨请求数据保持,运维李眉关注 Session 清理时机以避免内存泄漏。

向导控制器

package com.feixiang.web.controller;

import com.feixiang.web.entity.EmployeeForm;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.support.SessionStatus;

@Controller
@RequestMapping("/employee")
@SessionAttributes("employeeForm")  // 类级别声明
public class EmployeeWizardController {

    @GetMapping("/new")
    public String startWizard(Model model) {
        if (!model.containsAttribute("employeeForm")) {
            model.addAttribute("employeeForm", new EmployeeForm());
        }
        return "employee/step1";
    }

    @PostMapping("/step1")
    public String step1(@ModelAttribute("employeeForm") EmployeeForm form,
                        @RequestParam String name,
                        @RequestParam String department) {
        form.setName(name);
        form.setDepartment(department);
        // 自动同步到 Session(由 @SessionAttributes 处理)
        return "redirect:/employee/step2";
    }

    @PostMapping("/step2")
    public String step2(@ModelAttribute("employeeForm") EmployeeForm form,
                        @RequestParam String idCard,
                        @RequestParam String phone) {
        form.setIdCard(idCard);
        form.setPhone(phone);
        // 自动同步到 Session
        return "redirect:/employee/step3";
    }

    @PostMapping("/submit")
    public String submit(@ModelAttribute("employeeForm") EmployeeForm form,
                         SessionStatus status) {
        // 保存到数据库
        employeeService.save(form);

        // 清理 Session 中的临时数据
        status.setComplete();

        return "employee/success";
    }
}

请求示例一:第一步提交基本信息

curl -X POST http://localhost:8080/employee/step1 \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "name=张三&department=研发部" \
  -c cookies.txt

行为:

  • Controller 将 employeeForm 放入 Model
  • @SessionAttributes 触发同步,HttpSession 中存入 employeeForm
  • 重定向到 /employee/step2

请求示例二:第二步提交证件信息(Session 自动恢复表单)

curl -X POST http://localhost:8080/employee/step2 \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "idCard=110101199001011234&phone=13800138000" \
  -b cookies.txt

行为:

  • Spring MVC 从 Session 中恢复 employeeForm 对象注入参数
  • form.getName() 仍然是"张三",form.getDepartment() 仍然是"研发部"
  • 更新证件和电话后,再次同步到 Session
  • 重定向到 /employee/step3

请求示例三:最终提交并清理 Session

curl -X POST http://localhost:8080/employee/submit \
  -b cookies.txt

行为:

  • 从 Session 恢复完整的 employeeForm(包含三步的所有数据)
  • 保存到数据库
  • status.setComplete() 标记清理
  • 响应"提交成功"页面后,Session 中的 employeeForm 被移除

易错场景与面试考点

误区一:SessionStatus.setComplete() 立即删除 Session 属性

错误认知:"调用了 setComplete(),Session 中的属性立刻就被删除了。"

纠正:setComplete() 只是标记当前 Controller 的 SessionAttributes 为"完成状态"。真正的清理发生在当前请求处理完毕后的 afterCompletion 阶段。这意味着在 setComplete() 调用后、请求结束前,你仍然可以访问 Session 中的属性。

@PostMapping("/submit")
public String submit(@ModelAttribute("employeeForm") EmployeeForm form,
                     SessionStatus status) {
    status.setComplete();  // 标记完成
    // 此时 form 仍然可用!
    employeeService.save(form);
    return "employee/success";  // 请求结束后才清理
}

误区二:@SessionAttributes 属性名拼写错误

错误代码:

@SessionAttributes("empForm")  // 声明的是 empForm

@PostMapping("/step1")
public String step1(@ModelAttribute("employeeForm") EmployeeForm form, Model model) {
    // 实际放入 Model 的是 employeeForm
    model.addAttribute("employeeForm", form);
    // 与 @SessionAttributes("empForm") 不匹配,不会同步到 Session!
}

问题:@SessionAttributes 按名称精确匹配。名称不一致时,Model 属性不会同步到 Session,后续请求也无法恢复。

纠正:确保 @SessionAttributes 声明的名称与 Model.addAttribute() 和 @ModelAttribute 使用的名称完全一致。

误区三:忘记清理导致 Session 膨胀

问题场景:用户填写到第二步时关闭浏览器,Session 中的 employeeForm 永远不会被清理。

应对方案:

  1. 务必在流程终点调用 status.setComplete()
  2. 配置 Session 超时时间(server.servlet.session.timeout=30m)
  3. 对于长期未完成的向导,可在拦截器中检查时间戳,超时时主动清理

面试高频:@SessionAttributes 与 HttpSession 直接操作的区别

维度@SessionAttributesHttpSession.setAttribute()
抽象层级高(与 Model 集成)低(直接操作 Servlet API)
自动同步✅ Model 自动同步到 Session❌ 完全手动
自动恢复✅ 参数自动从 Session 恢复❌ 需要手动 getAttribute
清理机制✅ SessionStatus.setComplete()❌ 需要手动 removeAttribute
适用场景向导式表单、多步骤流程登录信息、权限等长期保持的数据

标准回答:@SessionAttributes 适合有明确生命周期的临时会话数据(如多步骤表单),它提供了 Model 与 Session 之间的自动同步和便捷的清理机制;而 HttpSession 直接操作适合长期保持的会话数据(如登录用户),需要开发者自行管理生命周期。


小结

@SessionAttributes 是类级别的注解,将 Model 中指定名称的属性自动同步到 HttpSession,实现跨请求的会话级数据保持。它适用于多步骤表单、向导式流程等需要跨请求共享临时数据的场景。SessionStatus.setComplete() 用于标记清理,实际删除发生在当前请求处理完毕后的 afterCompletion 阶段。

本章与全局的关系:本章讲解了向 Session 写入和保持数据的方式。它与上一章的 @SessionAttribute(只读)形成完整互补:一个负责"写和保持",一个负责"读"。下一章"RedirectAttributes"将讲解重定向场景下的临时数据传递机制。

上一页
本章导读:高级特性与最佳实践
下一页
SessionAttribute