@ModelAttribute
@ModelAttribute 注解可以用于方法参数,将请求参数、URI 路径变量和请求标头绑定到模型对象上。
使用示例
java
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) {
// 自动将请求参数绑定到 pet 对象上
return "redirect:/owners/{ownerId}";
}kotlin
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute pet: Pet): String {
// 自动将请求参数绑定到 pet 对象上
return "redirect:/owners/{ownerId}"
}对象来源
Pet 实例可能通过以下方式获取:
- 现有模型:由控制器中的
@ModelAttribute方法提前添加。 - HTTP 会话:如果类上声明了
@SessionAttributes。 - 转换器:如果路径变量名与属性名匹配,且存在对应的
Converter<String, T>。 - 默认构造函数:通过反射实例化。
- 主构造函数:通过匹配 Servlet 请求参数的构造函数实例化(推荐)。
数据绑定与安全
默认情况下,Spring 应用构造函数和属性的数据绑定。
- 安全建议:为了防止“过度提交(Over-posting)”攻击,建议使用专门的 DTO(Data Transfer Object)进行绑定,或者使用
allowedFields模式限制可设置的属性。 - @BindParam:在使用构造函数绑定时,可以用此注解自定义参数名。
校验处理
如果绑定出错,默认抛出 MethodArgumentNotValidException。 你可以通过在参数旁声明 BindingResult 来手动处理错误:
java
@PostMapping("/edit")
public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) {
if (result.hasErrors()) {
return "petForm";
}
return "redirect:/success";
}补充教学
1. 为什么它是“隐式”的?
在 Spring MVC 中,如果你写 public String save(User user),即便不加 @ModelAttribute,Spring 也会因为它不是简单类型(String/int 等)而自动将其视为 @ModelAttribute。
- 提示:在 GraalVM 原生镜像开发中,建议显式加上注解,以便 AOT 编译能正确推断反射提示。
2. binding=false 的妙用
有时候你只想从模型里拿出一个对象(比如之前由拦截器或父类方法放进去的),而不希望 Spring 把当前请求的参数再一次覆盖到它身上。 这时可以使用 @ModelAttribute(binding=false)。
3. @Valid 的位置
记住:@Valid 必须写在 @ModelAttribute 之前。而且 BindingResult 必须紧跟在那个参数后面。如果你中间插了一个 Model 参数,Spring 会报错,因为它不知道这个 BindingResult 是属于谁的。