RedirectAttributes
本章聚焦 Spring MVC 重定向场景下的数据传递机制。
RedirectAttributes是 Flash 属性的容器,专门解决 POST-Redirect-GET 模式中"重定向后如何传递一次性消息"的问题。它是 Spring MVC 对 Servlet 3.0 Flash Attribute 规范的封装,理解其工作原理对构建安全的表单提交流程至关重要。
定义与作用
RedirectAttributes 是 Spring MVC 提供的特殊 Model 接口,用于在**重定向(redirect)**发生前存储临时数据。这些数据会被放入 Flash 作用域,在重定向后的第一次请求中可用,随后自动清除。
核心特征:
- Flash 属性:存储在 Session 中,但只保留一次请求,读取后自动删除
- 两种添加方式:
addFlashAttribute()(放 Flash,URL 不可见)和addAttribute()(放 URL 查询参数) - 自动清理:重定向目标请求处理完毕后,Flash 属性自动从 Session 中移除
生活类比:临时访客通行证
想象飞翔科技大楼的访客系统:
addAttribute():把访客姓名写在 URL 地址栏里(?name=张三),所有人都能看到,但 URL 长度有限,且信息暴露在外addFlashAttribute():给访客发一张临时通行证,存在大楼前台(Session)。访客到达目标楼层时出示通行证,门卫验证后立刻撕掉(自动删除)。信息不暴露在 URL 中,且只能用一次
POST-Redirect-GET 模式就像:你在前台填表(POST)→ 前台给你一张临时通行证 → 你拿着通行证去目标楼层(GET)→ 门卫看完立刻销毁通行证 → 你正常进入。如果刷新页面,通行证已经销毁,不会重复办理业务。
核心原理
Flash 属性传递流程
关键机制:
- 保存阶段:POST 请求处理完毕后,
FlashMapManager将RedirectAttributes中的 Flash 属性存入 Session - 恢复阶段:重定向后的 GET 请求到达时,
FlashMapManager从 Session 中读取 Flash 属性并放入当前请求的 Model,同时从 Session 中删除 - URL 参数:
addAttribute()添加的属性会被拼接到重定向 URL 的查询字符串中,对客户端可见
适用位置与常用属性
RedirectAttributes 作为方法参数类型使用,Spring MVC 自动注入。
| 方法 | 作用 | 数据去向 | 生命周期 | 典型用途 |
|---|---|---|---|---|
addFlashAttribute(String name, Object value) | 添加 Flash 属性 | Session(FlashMap) | 一次请求后自动清除 | 成功/错误提示消息 |
addFlashAttribute(Object value) | 添加 Flash 属性(以类型为隐式名称) | Session(FlashMap) | 一次请求后自动清除 | 传递复杂对象 |
addAttribute(String name, Object value) | 添加 URL 参数 | 重定向 URL 查询字符串 | 永久(在 URL 中) | 传递 ID 等必要参数 |
addFlashAttribute vs addAttribute 对比
| 维度 | addFlashAttribute | addAttribute |
|---|---|---|
| 存储位置 | Session(临时 FlashMap) | URL 查询参数 |
| 客户端可见 | ❌ 不可见 | ✅ 可见 |
| 刷新后保留 | ❌ 不保留(已清除) | ✅ 保留(在 URL 中) |
| 数据类型 | 任意对象 | 只能转为字符串 |
| 长度限制 | 无(受 Session 限制) | 受 URL 长度限制 |
| 安全性 | 高(不暴露数据) | 低(数据在 URL 中) |
完整示例
场景
飞翔科技员工管理系统的"新增员工"页面采用 POST-Redirect-GET 模式。后端小崔使用 RedirectAttributes 在重定向后传递"创建成功"的提示消息,避免用户刷新页面导致表单重复提交。
控制器
package com.feixiang.web.controller;
import com.feixiang.web.entity.EmployeeForm;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
@Controller
@RequestMapping("/employee")
public class EmployeeController {
@PostMapping("/create")
public String createEmployee(@ModelAttribute EmployeeForm form,
RedirectAttributes redirectAttributes) {
// 保存员工
Long employeeId = employeeService.save(form);
// Flash 属性:成功消息,只显示一次
redirectAttributes.addFlashAttribute("successMessage",
"员工 " + form.getName() + " 创建成功!");
// URL 参数:员工 ID,用于详情页查询
redirectAttributes.addAttribute("id", employeeId);
return "redirect:/employee/detail";
}
@GetMapping("/detail")
public String detailPage(@RequestParam Long id, Model model) {
// successMessage 会自动从 Flash 属性恢复到 Model
if (!model.containsAttribute("successMessage")) {
model.addAttribute("employee", employeeService.findById(id));
}
return "employee/detail";
}
}
请求示例一:POST 创建员工(触发重定向)
curl -X POST http://localhost:8080/employee/create \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "name=张三&department=研发部&age=25" \
-c cookies.txt -L -v
响应过程:
< HTTP/1.1 302
< Location: /employee/detail?id=1001
--- 自动跟随重定向 ---
> GET /employee/detail?id=1001
< HTTP/1.1 200
< Content-Type: text/html
<!-- 页面显示:员工 张三 创建成功! -->
请求示例二:直接 GET 详情页(无 Flash 属性)
curl -X GET "http://localhost:8080/employee/detail?id=1001" \
-b cookies.txt
响应:详情页面正常显示,不显示"创建成功"消息(Flash 属性已在上次请求后清除)。
错误提示场景
@PostMapping("/create")
public String createEmployee(@ModelAttribute EmployeeForm form,
RedirectAttributes redirectAttributes) {
if (employeeService.existsByName(form.getName())) {
// 校验失败,重定向回表单页,携带错误消息
redirectAttributes.addFlashAttribute("errorMessage", "员工姓名已存在");
redirectAttributes.addFlashAttribute("form", form); // 回显表单数据
return "redirect:/employee/new";
}
Long employeeId = employeeService.save(form);
redirectAttributes.addFlashAttribute("successMessage", "创建成功");
redirectAttributes.addAttribute("id", employeeId);
return "redirect:/employee/detail";
}
curl -X POST http://localhost:8080/employee/create \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "name=张三&department=研发部" \
-c cookies.txt -L
如果"张三"已存在,重定向到 /employee/new,页面显示错误消息并回显表单数据。
易错场景与面试考点
误区一:在 addFlashAttribute 后尝试在重定向前读取
错误认知:"我 addFlashAttribute 之后,在当前请求里就能从 Model 中读到它。"
纠正:addFlashAttribute 的数据在当前 POST 请求的 Model 中不可见。它只在重定向后的 GET 请求中通过 Model 恢复。如果需要在当前请求中传递数据给视图,应该直接用 model.addAttribute()。
误区二:用 addAttribute 传递敏感信息
错误代码:
redirectAttributes.addAttribute("password", form.getPassword()); // ❌ 危险!
return "redirect:/employee/detail";
问题:addAttribute 的数据会暴露在 URL 中(?password=123456),浏览器历史、服务器日志、Referer 中都会留下痕迹。
纠正:敏感信息必须使用 addFlashAttribute,或者根本不通过重定向传递。
误区三:重定向到外部 URL 时使用 Flash 属性
错误代码:
redirectAttributes.addFlashAttribute("token", secretToken);
return "redirect:https://external.com/callback"; // ❌ Flash 属性会丢失!
问题:Flash 属性依赖 Session,而 Session 是域内(domain)的。重定向到外部域名时,Session 不共享,Flash 属性无法传递。
纠正:跨域重定向只能使用 addAttribute(URL 参数),且不应传递敏感信息。
面试高频:为什么 POST 请求后要 Redirect?
问题:表单提交后为什么要 return "redirect:/xxx" 而不是直接返回视图?
标准回答:
- 防止重复提交:如果直接返回视图,用户刷新页面会重新提交表单(重复 POST)
- URL 规范化:重定向后浏览器地址栏变为 GET 请求的 URL,符合 REST 语义
- 书签友好:用户可以把重定向后的页面加入书签
- 配合 Flash 属性:可以在重定向后传递一次性的成功/错误提示
这就是经典的 POST-Redirect-GET(PRG) 模式。
小结
RedirectAttributes 是 Spring MVC 为 POST-Redirect-GET 模式提供的 Flash 属性容器。addFlashAttribute() 将数据存入 Session 级别的 FlashMap,在重定向后的第一次请求中自动恢复到 Model 并清除;addAttribute() 将数据拼接到重定向 URL 的查询字符串中。前者适合传递提示消息,后者适合传递必要的查询参数。
本章与全局的关系:本章讲解了重定向场景的一次性数据传递。它与上一章的 @SessionAttributes(持久会话数据)形成对比:Flash 属性是"用一次就扔",SessionAttributes 是"保持到显式清理"。下一章"MockMvc 测试"将讲解如何在无需启动 Servlet 容器的情况下测试这些 Web 请求处理逻辑。