Spring MVC 中实现 request 域效果的几种方式

Spring MVC 中实现 request 域效果的几种方式

request 域的本质是"一次请求内共享数据"。在 Spring MVC 中,除了直接用 HttpServletRequest.setAttribute(),还有多种封装方式,底层最终都会把数据放入 request 域。下面按使用方式分类说明。

一、原生 HttpServletRequest

最直接的方式,Controller 方法声明 HttpServletRequest 参数,手动 setAttribute。

java 复制代码
@GetMapping("/demo")
public String demo(HttpServletRequest request) {
    request.setAttribute("msg", "操作成功");
    return "demo";
}

JSP 或 Thymeleaf 中通过 ${msg} 读取。这种方式最底层,不依赖 Spring 的封装,但代码略显繁琐。

二、Model 接口

Model 是 Spring MVC 提供的模型接口,addAttribute() 添加的数据会自动放入 request 域。

java 复制代码
@GetMapping("/demo")
public String demo(Model model) {
    model.addAttribute("msg", "操作成功");
    model.addAttribute("user", new User("张三"));
    return "demo";
}

Model 是一个接口,实际实现是 ExtendedModelMap,底层继承 ModelMap。

三、ModelMap

ModelMap 是 Model 的实现类,用法与 Model 基本一致,但它是具体类,提供了一些额外方法。

java 复制代码
@GetMapping("/demo")
public String demo(ModelMap modelMap) {
    modelMap.addAttribute("msg", "操作成功");
    modelMap.put("user", new User("张三"));
    return "demo";
}

ModelMap 继承 LinkedHashMap<String, Object>,所以也可以用 put() 方法。日常开发中 Model 和 ModelMap 可以互换,推荐用 Model,面向接口。

四、ModelAndView

ModelAndView 同时封装了模型数据和视图名称,作为方法的返回值。

java 复制代码
@GetMapping("/demo")
public ModelAndView demo() {
    ModelAndView mav = new ModelAndView();
    mav.setViewName("demo");
    mav.addObject("msg", "操作成功");
    mav.addObject("user", new User("张三"));
    return mav;
}

addObject() 添加的数据最终也会放入 request 域。ModelAndView 适合需要同时控制视图和数据的场景,但现代 Spring MVC 更推荐直接返回视图名 + Model 参数,代码更简洁。

五、直接使用 Map 参数

Spring MVC 支持在 Controller 方法中声明 Map<String, Object> 参数,添加到 Map 中的数据会被当作模型数据放入 request 域。

java 复制代码
@GetMapping("/demo")
public String demo(Map<String, Object> map) {
    map.put("msg", "操作成功");
    map.put("user", new User("张三"));
    return "demo";
}

底层 Spring 会把这个 Map 包装成 Model 使用。这种方式写起来简洁,但语义不如 Model 明确,团队中如果约定用 Model,就不建议混用。

六、@ModelAttribute 注解

@ModelAttribute 有两种用法,都会把数据放入 request 域。

1. 标注在方法参数上

方法参数对象会被自动放入 Model,key 默认是类型名首字母小写。

java 复制代码
@GetMapping("/demo")
public String demo(@ModelAttribute("user") User user) {
    // user 对象自动放入 request 域,key 为 "user"
    return "demo";
}

2. 标注在方法上

被 @ModelAttribute 标注的方法会在每个 Controller 方法执行前调用,返回值自动放入 Model,常用于准备公共数据。

java 复制代码
@ModelAttribute("categories")
public List<Category> categories() {
    return categoryService.listAll();
}

@GetMapping("/demo")
public String demo() {
    // 可以直接在视图中使用 ${categories}
    return "demo";
}

这种方式适合全局共享的模型数据,比如下拉框选项、菜单数据。

七、RedirectAttributes(重定向场景)

RedirectAttributes 专门用于重定向时传递数据,它有两种添加方式,行为不同。

java 复制代码
@PostMapping("/save")
public String save(User user, RedirectAttributes redirectAttributes) {
    userService.save(user);
    redirectAttributes.addAttribute("id", user.getId());        // 拼到 URL 上
    redirectAttributes.addFlashAttribute("msg", "保存成功");    // 暂存后取出
    return "redirect:/detail";
}
  • addAttribute():数据拼接到重定向 URL 的查询参数中,本质不是 request 域,而是 URL 参数。
  • addFlashAttribute():数据暂存到 session(FlashMap),重定向后的下一次请求取出后立即删除,效果类似"跨请求的一次性 request 域"。

严格来说,RedirectAttributes 不是 request 域,但它是重定向场景下最常用的传参方式,需要和 request 域区分开。

八、@RequestAttribute(读取 request 域)

前面几种都是"写入"request 域。如果需要"读取"request 域中的数据,可以用 @RequestAttribute。

java 复制代码
@GetMapping("/target")
public String target(@RequestAttribute("msg") String msg) {
    return "target";
}

通常配合请求转发使用:前一个请求 setAttribute,转发到目标方法,目标方法用 @RequestAttribute 读取。

九、各方式对比

方式 写入 request 域 返回值类型 适用场景
HttpServletRequest ✅ 视图名 需要操作原生 Servlet API
Model ✅ 视图名 最常用,推荐
ModelMap ✅ 视图名 需要 Map 风格 API
ModelAndView ✅ ModelAndView 同时控制视图和数据
Map 参数 ✅ 视图名 简洁写法,语义略弱
@ModelAttribute 参数 ✅ 视图名 表单对象绑定并放入模型
@ModelAttribute 方法 ✅ 任意 全局公共模型数据
RedirectAttributes 重定向场景 重定向路径 重定向传参,非严格 request 域

十、底层关系

Model、ModelMap、ModelAndView、Map 参数、@ModelAttribute,最终都会汇聚到 ModelAndViewContainer 的 Model 中。视图渲染时,Spring 会把 Model 中的数据遍历放入 HttpServletRequest 的 attributes 中,然后交给视图解析器渲染。

所以它们的效果等价:视图里都能用 ${key} 取到值,请求结束后数据随 request 一起销毁。

区别只在于写法、返回值和适用场景,运行时没有本质差异。

十一、怎么选

场景 推荐方式
普通 Controller 返回视图 + 数据 Model
需要同时控制视图名和数据 ModelAndView
表单对象绑定并回显 @ModelAttribute 参数
多个方法共享的公共数据 @ModelAttribute 方法
需要操作原生 Servlet API HttpServletRequest
重定向后传递一次性提示 RedirectAttributes.addFlashAttribute()
读取转发过来的 request 域数据 @RequestAttribute

日常开发中,Model 是最常用、最推荐的方式。ModelAndView 适合老项目或需要显式控制视图的场景。@ModelAttribute 方法适合准备全局数据。RedirectAttributes 只在重定向场景使用,且要注意它和 request 域的区别。

相关推荐
秋饼9 分钟前
MCP 2026-07-28 无状态协议大改版:Spring AI 2.1 多轮往返请求与网关路由落地
java·ai·技术分享·后端开发
努力的小郑1 小时前
数据查到了,回答去哪儿了?一次百炼 + LangChain 排查实录
后端·langchain·agent
SL_staff1 小时前
JVS-BI 实战:业务人员如何用零代码 ELT + 可视化配置构建实时经营分析闭环
java·spring·全栈
isfox2 小时前
Python 虚拟环境:别再把所有项目塞进一个"大仓库"了
后端
SL_staff2 小时前
企业AI落地难?JVS-AI渐进式实践:安全可控、小切口验证、标准化沉淀与规模化复制
java·开源·aigc
易师傅2 小时前
技术面试已死?AI 时代,真正拉开程序员差距的是什么?
前端·后端·程序员
苍何2 小时前
办公 Agent 权威评测榜单出炉了,豆包第一
后端
AiMan2 小时前
别再把秘塔会话逐个点开:这可把秘塔多个会话一次导出?AI导出鸭
前端·后端·面试
SL_staff3 小时前
JVS数字底座实践:构建企业级统一内容管理平台的技术路径
java·产品
nice_lcj5203 小时前
【从零理解 Spring AI · 12】MCP 的两种角色:做客户端还是做服务端
java·后端·spring·spring ai·ai应用开发