对于最新的稳定版本,请使用 Spring Framework 6.2.10spring-doc.cadn.net.cn

@ModelAttribute

@ModelAttribute方法参数注解将请求参数绑定到模型上 对象。例如:spring-doc.cadn.net.cn

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) { (1)
	// method logic...
}
1 绑定到Pet.
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute pet: Pet): String { (1)
	// method logic...
}
1 绑定到Pet.

Pet实例可能是:spring-doc.cadn.net.cn

如上所述,一个Converter<String, T>如果出现以下情况,则可用于获取模型对象 模型属性名称与请求值的名称匹配,例如路径变量或 request 参数,并且有一个兼容的Converter<String, T>.在下面的示例中, 模型属性名称account匹配 URI 路径变量account,并且有一个 注册Converter<String, Account>这可能会从持久性存储中检索它:spring-doc.cadn.net.cn

@PutMapping("/accounts/{account}")
public String save(@ModelAttribute("account") Account account) { (1)
	// ...
}
@PutMapping("/accounts/{account}")
fun save(@ModelAttribute("account") account: Account): String { (1)
	// ...
}

默认情况下,同时应用构造函数和属性数据绑定。然而 模型对象设计需要仔细考虑,出于安全原因,它是 建议使用专门为 Web 绑定定制的对象,或将 仅构造函数绑定。如果仍必须使用属性绑定,则应设置 allowedFields 模式以限制可以设置的属性。有关此内容的更多详细信息 和示例配置,请参阅模型设计spring-doc.cadn.net.cn

使用构造函数绑定时,可以通过@BindParam注解。例如:spring-doc.cadn.net.cn

class Account {

    private final String firstName;

	public Account(@BindParam("first-name") String firstName) {
		this.firstName = firstName;
	}
}
class Account(@BindParam("first-name") val firstName: String)
@BindParam也可以放置在与构造函数相对应的字段上 参数。而@BindParam开箱即用,也可以使用 通过设置不同的注释DataBinder.NameResolverDataBinder

在某些情况下,您可能希望在没有数据绑定的情况下访问模型属性。对于这样的 案例,您可以注入Model进入控制器并直接访问它,或者, 或者,将@ModelAttribute(binding=false),如以下示例所示:spring-doc.cadn.net.cn

@ModelAttribute
public AccountForm setUpForm() {
	return new AccountForm();
}

@ModelAttribute
public Account findAccount(@PathVariable String accountId) {
	return accountRepository.findOne(accountId);
}

@PostMapping("update")
public String update(AccountForm form, BindingResult result,
		@ModelAttribute(binding=false) Account account) { (1)
	// ...
}
1 设置@ModelAttribute(binding=false).
@ModelAttribute
fun setUpForm(): AccountForm {
	return AccountForm()
}

@ModelAttribute
fun findAccount(@PathVariable accountId: String): Account {
	return accountRepository.findOne(accountId)
}

@PostMapping("update")
fun update(form: AccountForm, result: BindingResult,
		   @ModelAttribute(binding = false) account: Account): String { (1)
	// ...
}
1 设置@ModelAt\tribute(binding=false).

如果数据绑定导致错误,则默认情况下MethodArgumentNotValidException被抬起, 但您也可以添加BindingResult参数紧邻@ModelAttribute以处理控制器方法中的此类错误。例如:spring-doc.cadn.net.cn

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) { (1)
	if (result.hasErrors()) {
		return "petForm";
	}
	// ...
}
1 添加一个BindingResult旁边的@ModelAttribute.
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute("pet") pet: Pet, result: BindingResult): String { (1)
	if (result.hasErrors()) {
		return "petForm"
	}
	// ...
}
1 添加一个BindingResult旁边的@ModelAttribute.

您可以通过添加jakarta.validation.Valid注释或 Spring 的@Validated注解。 请参阅 Bean 验证Spring 验证。例如:spring-doc.cadn.net.cn

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) { (1)
	if (result.hasErrors()) {
		return "petForm";
	}
	// ...
}
1 验证Pet实例。
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@Valid @ModelAttribute("pet") pet: Pet, result: BindingResult): String { (1)
	if (result.hasErrors()) {
		return "petForm"
	}
	// ...
}
1 验证Pet实例。

如果没有BindingResult参数@ModelAttribute然后MethodArgumentNotValueException会引发验证错误。但是,如果方法validation 适用,因为其他参数具有@jakarta.validation.Constraint附注 然后HandlerMethodValidationException而是引发。有关更多详细信息,请参阅验证部分。spring-doc.cadn.net.cn

@ModelAttribute是可选的。默认情况下,任何不是简单的value 类型(由 BeanUtils#isSimpleProperty 确定且未被任何其他参数解析器解析)的参数都被视为隐式@ModelAttribute.
使用 GraalVM 编译为本机映像时,隐式@ModelAttribute上述支持不允许对相关数据进行适当的提前推断绑定反射提示。因此,建议显式注释方法 参数@ModelAttribute用于 GraalVM 本机映像。