你可以在方法参数上使用 @ModelAttribute
注解来访问模型中的一个属性,或者在不存在时让它被实例化。模型属性也会被 HTTP Servlet 请求参数的值所覆盖,这些参数的名称与字段名称相匹配。这被称为 数据绑定,它使你不必处理解析和转换单个查询参数和表单字段。下面的例子显示了如何做到这一点:
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) {
// method logic...
}
上面的 Pet 实例是以下列方式之一获得的:
- 从 模型(model )中获取,它可能是由
@ModelAttribute
方法添加的。 - 从 HTTP 会话中获取,如果模型属性被列在类级的
[@SessionAttributes](https://www.yuque.com/mrcode.cn/read-docs/ld5fg7)
注解中。 - 通过一个转换器获得,其中模型属性名称与请求值的名称相匹配,如路径变量或请求参数(见下例)。
比如访问 /owners/123/pets/456/edit
那么 pet 中的 ownerId=123,petId=456
- 使用其默认构造函数进行实例化。
- 通过一个 「主要构造函数」实例化,其参数与 Servlet 请求参数相匹配。参数名称是通过 JavaBeans 的
@ConstructorProperties
或通过字节码中的运行时参数名称确定的。
除了使用 @ModelAttribute 方法来提供它或依靠框架来创建模型属性外,还有一种方法是用 Converter<String, T>
来提供实例。当模型属性名称与请求值的名称相匹配时,如路径变量或请求参数,并且有一个从 String 到模型属性类型的转换器时,就可以应用这个方法。在下面的例子中,模型属性名是 account,与 URI 路径变量 account 相匹配,并且有一个注册的 Converter<String, Account>
可以从数据存储中加载 Account。
@PutMapping("/accounts/{account}")
public String save(@ModelAttribute("account") Account account) {
// ...
}
在获得模型属性实例后,数据绑定被应用。WebDataBinder 类将 Servlet 请求参数名称(查询参数和表单字段)与目标对象上的字段名称相匹配。必要时,在应用类型转换后,匹配的字段被填充。关于数据绑定(和验证)的更多信息,请参阅 验证。更多关于自定义数据绑定的信息,请参见 DataBinder。
数据绑定可能导致错误。默认情况下,会引发一个 BindException。然而,为了在控制器方法中检查这种错误,你可以在 @ModelAttribute 旁边添加一个 BindingResult 参数,如下例所示:
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {
if (result.hasErrors()) {
return "petForm";
}
// ...
}
在某些情况下,你可能想在没有数据绑定的情况下访问一个模型属性。对于这种情况,你可以将模型注入控制器并直接访问它,或者,设置@ModelAttribute(binding=false)
,如下例所示。
@ModelAttribute
public AccountForm setUpForm() {
return new AccountForm();
}
@ModelAttribute
public Account findAccount(@PathVariable String accountId) {
return accountRepository.findOne(accountId);
}
@PostMapping("update")
public String update(@Valid AccountForm form, BindingResult result,
@ModelAttribute(binding=false) Account account) {
// ...
}
你可以通过添加 javax.validation.Valid
注解或 Spring 的 @Validated
注解(Bean Validation 和 Spring validation)在数据绑定后自动应用验证。下面的例子展示了如何做到这一点。
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) {
if (result.hasErrors()) {
return "petForm";
}
// ...
}
注意,使用 @ModelAttribute 是可选的(例如,设置其属性)。默认情况下,任何不是简单值类型(由 BeanUtils#isSimpleProperty
决定)且未被任何其他参数解析器解析的参数,将被视为用 @ModelAttribute 注释的参数。
:::tips 如果看完之后 还不明白是什么意思,可以参考 Model 中的例子 :::