你可以在方法参数上使用 @ModelAttribute注解来访问模型中的一个属性,或者在不存在时让它被实例化。模型属性也会被 HTTP Servlet 请求参数的值所覆盖,这些参数的名称与字段名称相匹配。这被称为 数据绑定,它使你不必处理解析和转换单个查询参数和表单字段。下面的例子显示了如何做到这一点:

    1. @PostMapping("/owners/{ownerId}/pets/{petId}/edit")
    2. public String processSubmit(@ModelAttribute Pet pet) {
    3. // method logic...
    4. }

    上面的 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。

    1. @PutMapping("/accounts/{account}")
    2. public String save(@ModelAttribute("account") Account account) {
    3. // ...
    4. }

    在获得模型属性实例后,数据绑定被应用。WebDataBinder 类将 Servlet 请求参数名称(查询参数和表单字段)与目标对象上的字段名称相匹配。必要时,在应用类型转换后,匹配的字段被填充。关于数据绑定(和验证)的更多信息,请参阅 验证。更多关于自定义数据绑定的信息,请参见 DataBinder

    数据绑定可能导致错误。默认情况下,会引发一个 BindException。然而,为了在控制器方法中检查这种错误,你可以在 @ModelAttribute 旁边添加一个 BindingResult 参数,如下例所示:

    1. @PostMapping("/owners/{ownerId}/pets/{petId}/edit")
    2. public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {
    3. if (result.hasErrors()) {
    4. return "petForm";
    5. }
    6. // ...
    7. }

    在某些情况下,你可能想在没有数据绑定的情况下访问一个模型属性。对于这种情况,你可以将模型注入控制器并直接访问它,或者,设置@ModelAttribute(binding=false),如下例所示。

    1. @ModelAttribute
    2. public AccountForm setUpForm() {
    3. return new AccountForm();
    4. }
    5. @ModelAttribute
    6. public Account findAccount(@PathVariable String accountId) {
    7. return accountRepository.findOne(accountId);
    8. }
    9. @PostMapping("update")
    10. public String update(@Valid AccountForm form, BindingResult result,
    11. @ModelAttribute(binding=false) Account account) {
    12. // ...
    13. }

    你可以通过添加 javax.validation.Valid注解或 Spring 的 @Validated注解(Bean ValidationSpring validation)在数据绑定后自动应用验证。下面的例子展示了如何做到这一点。

    1. @PostMapping("/owners/{ownerId}/pets/{petId}/edit")
    2. public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) {
    3. if (result.hasErrors()) {
    4. return "petForm";
    5. }
    6. // ...
    7. }

    注意,使用 @ModelAttribute 是可选的(例如,设置其属性)。默认情况下,任何不是简单值类型(由 BeanUtils#isSimpleProperty决定)且未被任何其他参数解析器解析的参数,将被视为用 @ModelAttribute 注释的参数。

    :::tips 如果看完之后 还不明白是什么意思,可以参考 Model 中的例子 :::