目录
1.介绍一下org.springframework.ui.Model
[1. 本质与实现原理](#1. 本质与实现原理)
[2. 示例代码](#2. 示例代码)
[3.BindingResult / Errors 必须紧跟在被校验的实体参数后面(代码说明)](#3.BindingResult / Errors 必须紧跟在被校验的实体参数后面(代码说明))
====

====
1.介绍一下org.springframework.ui.Model
org.springframework.ui.Model 是 Spring MVC 框架中极其核心的接口,它的主要作用是在 控制器(Controller) 和 视图(View) 之间建立数据传递的桥梁。
简单来说,当你在后端处理完业务逻辑后,需要将数据(如用户信息、列表)送到前端页面(如 JSP、Thymeleaf)显示,Model 就是那个用来装数据的"容器"。
1. 本质与实现原理
-
本质 :它是一个增强版的
Map<String, Object>。你可以向其中添加 Key-Value 键值对。 -
实际实现类 :在 Spring MVC 运行时,我们直接使用的
Model接口对象的实际实现类通常是BindingAwareModelMap(它继承自ModelMap,而ModelMap又继承自LinkedHashMap)。 -
存储位置 :当你调用
model.addAttribute()时,数据最终会被放入HttpServletRequest的attributes属性域中。因此,它的作用域是 Request 级别(一次请求有效)。
2. 示例代码
java
package com.example.controller; // 假设包名,根据实际情况修改
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
// 自定义的业务类和实体类(根据项目实际包路径导入)
import com.example.service.UserService;
import com.example.entity.User;
@Controller
@RequestMapping("/api/user") // 类级别定义基础路径
public class UserController {
// 模拟业务服务
private UserService userService = new UserService();
// 方式一:method = RequestMethod.GET ------ 查询用户详情
@RequestMapping(value = "/profile", method = RequestMethod.GET)
public String getUserProfile(@RequestParam("id") Long id, Model model) {
// 1. 业务数据
User user = userService.findById(id);
String pageTitle = "用户个人中心";
// 2. 显式将数据放入 Model(推荐,视图名清晰)
model.addAttribute("userInfo", user);
model.addAttribute("title", pageTitle);
// 3. 返回视图逻辑名(由视图解析器解析,如 Thymeleaf 或 JSP)
return "profile"; // 对应 /WEB-INF/views/profile.jsp 或 profile.html
}
// 方式二:method = RequestMethod.POST ------ 新增用户(重定向)
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String addUser(@ModelAttribute User user, Model model) {
// 模拟保存
userService.save(user);
// 给 Model 添加提示信息(仅在当前请求有效)
model.addAttribute("message", "添加成功!");
// 重定向时,Model 中的数据不会带过去(需要用 RedirectAttributes)
return "redirect:/api/user/profile?id=" + user.getId();
}
}
==
2.被@RequestMapping标注的类的方法参数
====
| 分类 | 参数类型 / 注解 | 作用说明 | 示例代码 |
|---|---|---|---|
| 请求数据提取 | @PathVariable |
获取 URL 路径中的占位符变量 | @PathVariable Long id |
@RequestParam |
获取请求参数(URL 查询参数或表单参数) | @RequestParam String name |
|
@RequestParam + required=false |
获取非必填参数,未传时为 null | @RequestParam(required=false) Integer age |
|
@RequestParam + defaultValue |
获取参数,未传时使用默认值 | @RequestParam(defaultValue="1") int page |
|
@RequestBody |
将请求体(JSON/XML)绑定到 Java 对象 | @RequestBody User user |
|
@RequestHeader |
获取 HTTP 请求头中的值 | @RequestHeader("User-Agent") String ua |
|
@CookieValue |
获取 Cookie 中的值 | @CookieValue("JSESSIONID") String jid |
|
@ModelAttribute |
将请求参数绑定到对象,并自动放入 Model | @ModelAttribute User user |
|
@MatrixVariable |
获取矩阵变量(/cars;color=red) |
@MatrixVariable String color |
|
| 数据输出 | Model |
添加键值对数据到 Request 作用域 | model.addAttribute("key", value) |
ModelMap |
Model 的实现类,用法类似 Map |
modelMap.put("key", value) |
|
RedirectAttributes |
重定向时传递数据(Flash Attributes) | redirectAttributes.addFlashAttribute("msg", "成功") |
|
| 验证与错误 | BindingResult |
接收 @Valid 校验的结果(错误信息) |
@Valid @RequestBody User user, BindingResult result |
Errors |
BindingResult 的父接口,功能相同 |
Errors errors |
|
| Servlet API | HttpServletRequest |
获取原生请求对象 | HttpServletRequest request |
HttpServletResponse |
获取原生响应对象 | HttpServletResponse response |
|
HttpSession |
获取当前会话(自动创建) | HttpSession session |
|
WebRequest |
Spring 封装的通用请求接口 | WebRequest webRequest |
|
NativeWebRequest |
更底层的 Web 请求接口 | NativeWebRequest nativeRequest |
|
| 输入输出流 | InputStream / Reader |
获取请求体的原始输入流 | InputStream inputStream |
OutputStream / Writer |
获取响应的原始输出流 | OutputStream outputStream |
|
| 安全与上下文 | Principal |
获取当前登录用户信息(配合 Spring Security) | Principal principal |
Locale |
获取当前请求的语言区域 | Locale locale |
|
TimeZone |
获取当前请求的时区 | TimeZone timeZone |
|
| Spring Data | Pageable |
分页参数(需引入 Spring Data) | Pageable pageable(自动解析 ?page=0&size=10) |
Sort |
排序参数(需引入 Spring Data) | Sort sort(自动解析 ?sort=id,desc) |
|
| 通用封装 | HttpEntity<T> |
封装整个请求(Headers + Body) | HttpEntity<User> entity |
RequestEntity<T> |
HttpEntity 的子类,带更多请求信息 |
RequestEntity<User> requestEntity |
|
| 构建工具 | UriComponentsBuilder |
用于构建动态 URL | UriComponentsBuilder builder |
| 其他可选 | MultipartFile |
接收上传的文件(需搭配 @RequestParam) |
@RequestParam MultipartFile file |
BindingAwareModelMap |
Model 的具体实现类,较少直接用 |
BindingAwareModelMap modelMap |
|
ModelAttribute + @SessionAttributes |
配合 Session 使用的属性 | 类上标注 @SessionAttributes,方法参数直接用 @ModelAttribute 取 |
====
特别提醒
-
BindingResult/Errors必须紧跟在被校验的实体参数后面,否则校验异常会直接抛出,无法进入方法体。 -
Pageable和Sort需要引入 Spring Data 相关依赖才能使用。 -
以上参数可以任意组合 ,顺序基本自由(除了
BindingResult必须紧跟被校验对象)。
===
3.BindingResult / Errors 必须紧跟在被校验的实体参数后面(代码说明)
===
正确代码
java
@RestController
@RequestMapping("/api/user")
public class UserController {
@PostMapping("/register")
public String register(
// 1. 被校验的实体
@Valid @RequestBody User user,
// 2. BindingResult 必须紧跟其后(中间不能插入任何其他参数)
BindingResult result,
// 3. 其他参数可以放在 BindingResult 后面
HttpSession session) {
// 校验是否有错误
if (result.hasErrors()) {
// 获取所有错误信息并返回
String errors = result.getAllErrors()
.stream()
.map(ObjectError::getDefaultMessage)
.collect(Collectors.joining(", "));
return "校验失败:" + errors;
}
// 业务逻辑(只有校验通过才会执行到这里)
userService.register(user);
session.setAttribute("userId", user.getId());
return "注册成功";
}
}
错误代码
===
java
@PostMapping("/register")
public String register(
@Valid @RequestBody User user,
// 错误:中间插入了 HttpSession 参数
HttpSession session, // ← 这里插入了其他参数,打断了顺序
BindingResult result) { // ← 没有紧跟被校验对象
// 即使这里有 if(result.hasErrors()),也永远不会执行到这里
if (result.hasErrors()) {
return "校验失败";
}
// 业务逻辑...
return "注册成功";
}
===