Model

可以使用 @ModelAttribute 注释:

You can use the @ModelAttribute annotation:

  • On a method argument in @RequestMapping methods to create or access an Object from the model and to bind it to the request through a WebDataBinder.

  • As a method-level annotation in @Controller or @ControllerAdvice classes, helping to initialize the model prior to any @RequestMapping method invocation.

  • On a @RequestMapping method to mark its return value as a model attribute.

本部分讨论 @ModelAttribute 方法,即上述列表中的第二项。控制器可包含任意数量的 @ModelAttribute 方法。所有此类方法在同一控制器中的 @RequestMapping 方法之前调用。@ModelAttribute 方法还可通过 @ControllerAdvice 在控制器之间共享。有关详细信息,请参阅 Controller Advice 部分。

This section discusses @ModelAttribute methods, or the second item from the preceding list. A controller can have any number of @ModelAttribute methods. All such methods are invoked before @RequestMapping methods in the same controller. A @ModelAttribute method can also be shared across controllers through @ControllerAdvice. See the section on Controller Advice for more details.

@ModelAttribute 方法具有灵活的方法签名。它们支持与 @RequestMapping 方法相同的大多数参数(@ModelAttribute 自身及其与请求正文相关的所有内容除外)。

@ModelAttribute methods have flexible method signatures. They support many of the same arguments as @RequestMapping methods (except for @ModelAttribute itself and anything related to the request body).

以下示例使用 @ModelAttribute 方法:

The following example uses a @ModelAttribute method:

  • Java

  • Kotlin

@ModelAttribute
public void populateModel(@RequestParam String number, Model model) {
	model.addAttribute(accountRepository.findAccount(number));
	// add more ...
}
@ModelAttribute
fun populateModel(@RequestParam number: String, model: Model) {
	model.addAttribute(accountRepository.findAccount(number))
	// add more ...
}

以下示例仅添加一个属性:

The following example adds one attribute only:

  • Java

  • Kotlin

@ModelAttribute
public Account addAccount(@RequestParam String number) {
	return accountRepository.findAccount(number);
}
@ModelAttribute
fun addAccount(@RequestParam number: String): Account {
	return accountRepository.findAccount(number);
}

如果未显式指定名称,系统会根据类型选择一个默认名称,如 Conventions 中的 javadoc 所述。您始终可以通过使用重载的 addAttribute 方法或通过 @ModelAttribute 中的名称属性(用于返回值)指定显式名称。

When a name is not explicitly specified, a default name is chosen based on the type, as explained in the javadoc for Conventions. You can always assign an explicit name by using the overloaded addAttribute method or through the name attribute on @ModelAttribute (for a return value).

与 Spring MVC 不同,Spring WebFlux 在模型中明确支持反应式类型(例如,Mono<Account>io.reactivex.Single<Account>)。此类异步模型属性可以透明地解析(并更新模型) 为调用 @RequestMapping 时的实际值,前提是声明了 @ModelAttribute 参数,且没有包装,如下例所示:

Spring WebFlux, unlike Spring MVC, explicitly supports reactive types in the model (for example, Mono<Account> or io.reactivex.Single<Account>). Such asynchronous model attributes can be transparently resolved (and the model updated) to their actual values at the time of @RequestMapping invocation, provided a @ModelAttribute argument is declared without a wrapper, as the following example shows:

  • Java

  • Kotlin

@ModelAttribute
public void addAccount(@RequestParam String number) {
    Mono<Account> accountMono = accountRepository.findAccount(number);
    model.addAttribute("account", accountMono);
}

@PostMapping("/accounts")
public String handle(@ModelAttribute Account account, BindingResult errors) {
	// ...
}
import org.springframework.ui.set

@ModelAttribute
fun addAccount(@RequestParam number: String) {
	val accountMono: Mono<Account> = accountRepository.findAccount(number)
	model["account"] = accountMono
}

@PostMapping("/accounts")
fun handle(@ModelAttribute account: Account, errors: BindingResult): String {
	// ...
}

此外,具有反应式类型包装的任何模型属性都会在渲染视图前解析为其实际值(并更新模型)。

In addition, any model attributes that have a reactive type wrapper are resolved to their actual values (and the model updated) just prior to view rendering.

还可以将 @ModelAttribute 用作 @RequestMapping 方法上的方法级注释,在这种情况下,@RequestMapping 方法的返回值将被解释为模型属性。通常情况下,这是不需要的,因为这是 HTML 控制器中的默认行为,除非返回值是会解释为视图名称的 String@ModelAttribute 还可以帮助自定义模型属性名称,如下例所示:

You can also use @ModelAttribute as a method-level annotation on @RequestMapping methods, in which case the return value of the @RequestMapping method is interpreted as a model attribute. This is typically not required, as it is the default behavior in HTML controllers, unless the return value is a String that would otherwise be interpreted as a view name. @ModelAttribute can also help to customize the model attribute name, as the following example shows:

  • Java

  • Kotlin

@GetMapping("/accounts/{id}")
@ModelAttribute("myAccount")
public Account handle() {
	// ...
	return account;
}
@GetMapping("/accounts/{id}")
@ModelAttribute("myAccount")
fun handle(): Account {
	// ...
	return account
}