Skip to content

@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 实例可能通过以下方式获取:

  1. 现有模型:由控制器中的 @ModelAttribute 方法提前添加。
  2. HTTP 会话:如果类上声明了 @SessionAttributes
  3. 转换器:如果路径变量名与属性名匹配,且存在对应的 Converter<String, T>
  4. 默认构造函数:通过反射实例化。
  5. 主构造函数:通过匹配 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 是属于谁的。

Based on Spring Framework.