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

@ModelAttribute

你可以使用 @ModelAttribute 注解标注方法参数,以访问模型中的属性;如果该属性不存在,则会自动实例化。模型属性还会与名称匹配字段名的查询参数和表单字段的值进行叠加。这被称为数据绑定(data binding),它可以避免你手动解析和转换各个查询参数及表单字段。以下示例将一个 Pet 实例进行绑定:spring-doc.cadn.net.cn

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) { } (1)
1 绑定一个 Pet 的实例。
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute pet: Pet): String { } (1)
1 绑定一个 Pet 的实例。

前面示例中的 Pet 实例解析方式如下:spring-doc.cadn.net.cn

在获取模型属性实例后,将应用数据绑定。WebExchangeDataBinder 类会将查询参数和表单字段的名称与目标 Object 上的字段名称进行匹配。在必要时应用类型转换后,匹配的字段将被填充。有关数据绑定(以及验证)的更多信息,请参阅 验证。有关自定义数据绑定的更多信息,请参阅 DataBinderspring-doc.cadn.net.cn

数据绑定可能会导致错误。默认情况下,会抛出一个 WebExchangeBindException 异常,但若要在控制器方法中检查此类错误,可以在 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
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute("pet") pet: Pet, result: BindingResult): String { (1)
	if (result.hasErrors()) {
		return "petForm"
	}
	// ...
}
1 添加一个 BindingResult

您可以通过添加 jakarta.validation.Valid 注解或 Spring 的 @Validated 注解(另请参阅 Bean ValidationSpring 验证),在数据绑定后自动应用验证。以下示例使用了 @Valid 注解: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 在模型属性参数上使用 @Valid
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@Valid @ModelAttribute("pet") pet: Pet, result: BindingResult): String { (1)
	if (result.hasErrors()) {
		return "petForm"
	}
	// ...
}
1 在模型属性参数上使用 @Valid

与 Spring MVC 不同,Spring WebFlux 在模型中支持响应式类型(reactive types)——例如,Mono<Account>io.reactivex.Single<Account>。您可以声明一个带有或不带响应式类型包装器的 @ModelAttribute 参数,系统会相应地解析该参数,并在必要时解析为实际值。然而请注意,若要使用 BindingResult 参数,您必须像前面所示那样,在其之前声明不带响应式类型包装器的 @ModelAttribute 参数。或者,您也可以通过响应式类型来处理任何错误,如下例所示:spring-doc.cadn.net.cn

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

请注意,使用 @ModelAttribute 是可选的——例如,用于设置其属性。 默认情况下,任何不是简单值类型(由 BeanUtils#isSimpleProperty 判定)且未被其他任何参数解析器解析的参数,都会被视为带有 @ModelAttribute 注解。spring-doc.cadn.net.cn

在使用 GraalVM 编译为原生镜像时,上述描述的隐式 @ModelAttribute 支持无法正确进行相关数据绑定反射提示的提前推断。因此,建议在 GraalVM 原生镜像中显式地为方法参数添加 @ModelAttribute 注解。