@ModelAttribute

@ModelAttribute 方法参数注解将表单数据、查询参数、URI 路径变量和请求标头绑定到模型对象。例如:

The @ModelAttribute method parameter annotation binds form data, query parameters, URI path variables, and request headers onto a model object. For example:

Java
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) { } (1)
1 Bind to an instance of Pet.
Kotlin
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute pet: Pet): String { } (1)
2 Bind to an instance of Pet.

表单数据和查询参数优先于 URI 变量和标头,仅包括那些未用同名请求参数覆盖它们的变量和标头,连字符会从标头名称中删掉。

Form data and query parameters take precedence over URI variables and headers, which are included only if they don’t override request parameters with the same name. Dashes are stripped from header names.

Pet 实例可能是:

The Pet instance may be:

  • Accessed from the model where it could have been added by a Model.

  • Accessed from the HTTP session if the model attribute was listed in the class-level @SessionAttributes.

  • Instantiated through a default constructor.

  • Instantiated through a “primary constructor” with arguments that match to Servlet request parameters. Argument names are determined through runtime-retained parameter names in the bytecode.

默认情况下,构造函数和属性 data binding 都已应用。但是,模型对象设计需要仔细考虑,出于安全原因,建议要么使用专门为 Web 绑定定制的对象,要么只应用构造函数绑定。如果仍必须使用属性绑定,则应设置 allowedFields 模式以限制可以设置哪些属性。有关这方面和示例配置的更多详细信息,请参见 model design

By default, both constructor and property data binding are applied. However, model object design requires careful consideration, and for security reasons it is recommended either to use an object tailored specifically for web binding, or to apply constructor binding only. If property binding must still be used, then allowedFields patterns should be set to limit which properties can be set. For further details on this and example configuration, see model design.

在使用构造函数绑定时,你可以通过 @BindParam 注解自定义请求参数名称。例如:

When using constructor binding, you can customize request parameter names through an @BindParam annotation. For example:

class Account {

    private final String firstName;

	public Account(@BindParam("first-name") String firstName) {
		this.firstName = firstName;
	}
}

也可以将 @BindParam 放置在与构造函数参数对应的字段上。虽然 @BindParam 开箱即用,也可以通过在 DataBinder 上设置 DataBinder.NameResolver 来使用不同的注释。

The @BindParam may also be placed on the fields that correspond to constructor parameters. While @BindParam is supported out of the box, you can also use a different annotation by setting a DataBinder.NameResolver on DataBinder

构造函数绑定支持`List`、Map`和数组参数,这些参数从单个字符串(例如,逗号分隔的列表)转换而来,或者基于索引键(例如`accounts[2].name`或`account[KEY].name)。

Constructor binding supports List, Map, and array arguments either converted from a single string, e.g. comma-separated list, or based on indexed keys such as accounts[2].name or account[KEY].name.

与 Spring MVC 不同,WebFlux 支持模型中的响应式类型,例如 Mono<Account>。您可以声明一个带有或不带有响应式类型包装器的 @ModelAttribute 自变量,它将根据实际值相应进行解析。

WebFlux, unlike Spring MVC, supports reactive types in the model, e.g. Mono<Account>. You can declare a @ModelAttribute argument with or without a reactive type wrapper, and it will be resolved accordingly to the actual value.

如果数据绑定导致错误,则默认情况下会引发 WebExchangeBindException,但是您还可以在 @ModelAttribute 紧挨着添加一个 BindingResult 参数,以便在控制器方法中处理此类错误。例如:

If data binding results in errors, by default a WebExchangeBindException is raised, but you can also add a BindingResult argument immediately next to the @ModelAttribute in order to handle such errors in the controller method. For example:

Java
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) { 1
	if (result.hasErrors()) {
		return "petForm";
	}
	// ...
}
1 Adding a BindingResult.
Kotlin
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute("pet") pet: Pet, result: BindingResult): String { (1)
	if (result.hasErrors()) {
		return "petForm"
	}
	// ...
}
2 Adding a BindingResult.

要使用 BindingResult 参数,您必须在没有任何反应型类型包装的情况下声明 @ModelAttribute 参数。如果您想使用反应型,则可以通过它直接处理错误。例如:

To use a BindingResult argument, you must declare the @ModelAttribute argument before it without a reactive type wrapper. If you want to use the reactive, you can handle errors directly through it. For example:

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public Mono<String> processSubmit(@Valid @ModelAttribute("pet") Mono<Pet> petMono) {
	return petMono
		.flatMap(pet -> {
			// ...
		})
		.onErrorResume(ex -> {
			// ...
		});
}

通过添加 @5 批注或 Spring 的 @6 批注,您可以在数据绑定后自动应用验证(请参阅 @7 和 @8)。例如:

You can automatically apply validation after data binding by adding the jakarta.validation.Valid annotation or Spring’s @Validated annotation (see Bean Validation and Spring validation). For example:

Java
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) { (1)
	if (result.hasErrors()) {
		return "petForm";
	}
	// ...
}
1 Using @Valid on a model attribute argument.
Kotlin
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@Valid @ModelAttribute("pet") pet: Pet, result: BindingResult): String { (1)
	if (result.hasErrors()) {
		return "petForm"
	}
	// ...
}
2 Using @Valid on a model attribute argument.

如果方法验证适用,因为其他参数带有 @9 批注,那么 @10 将会代之以提出。请参阅控制器方法 @11 的章节。

If method validation applies because other parameters have @Constraint annotations, then HandlerMethodValidationException would be raised instead. See the section on controller method Validation.

使用 @ModelAttribute 是可选的。默认情况下,如果某个参数不是使用 https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-AND 确定的简单值类型,并且未通过任何其他参数解析器解析,则该参数将视为隐式的 @ModelAttribute

Using @ModelAttribute is optional. By default, any argument that is not a simple value type as determined by BeanUtils#isSimpleProperty AND that is not resolved by any other argument resolver is treated as an implicit @ModelAttribute.

使用 GraalVM 编译为本机映像时,上面描述的隐式 @ModelAttribute 支持不允许提前正确推断相关的 data binding 反射提示。因此,建议明确使用 @ModelAttribute 为方法参数添加注释,以便在 GraalVM 本机映像中使用。

When compiling to a native image with GraalVM, the implicit @ModelAttribute support described above does not allow proper ahead-of-time inference of related data binding reflection hints. As a consequence, it is recommended to explicitly annotate method parameters with @ModelAttribute for use in a GraalVM native image.