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 域的区别。

相关推荐
Thomas.Sir1 小时前
第3课:SpringBoot4.x 自动配置原理:@EnableAutoConfiguration底层源码剖析
java·spring boot
Rain的Java大神之路1 小时前
MySQL 被高并发打爆?从定位到分库分表逐层拆解(含秒杀库存实战)
java·后端·面试
cc_瀚海知行1 小时前
工具调用 6|助手什么时候该停下来?
java·服务器·前端·人工智能·python·ai
Cosolar1 小时前
DeepInfer 完全教程:DeepSeek 内部推理框架原理、架构与部署实战
后端·架构·github
YDS8291 小时前
Small Spring IOC篇:应用上下文实现和Bean的扩展
java·后端·spring
Pniubi1 小时前
ConcurrentHashMap拆分线程池难点再讲
java·jvm
golang学习记1 小时前
IDEA 的 Java 智能,现在跑到 Cursor 和 VS Code 里去了
java·ide·vscode·intellij-idea·claude code
喵个咪1 小时前
GoWind ShortPlay 拆解:Ent privacy/viewer 多租户隔离——从中间件到 SQL 的零信任链
后端·架构·go
全栈弄潮儿1 小时前
Python实战第11期:面向对象编程基础
后端·python·编程语言