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

@ModelAttribute

您可以将 @ModelAttribute 注解用于方法参数,以从模型中访问属性,或在属性不存在时将其实例化。模型属性还会覆盖与字段名称匹配的查询参数和表单字段的值。这被称为数据绑定,它可避免您处理单独解析和转换查询参数和表单字段的工作。以下示例绑定了一个 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 的一个实例。

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

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

数据绑定可能会导致错误。默认情况下,会抛出一个 WebExchangeBindException,但是,在控制器方法中检查此类错误,你可以在 @ModelAttribute 立即下一个位置添加一个 BindingResult 参数,如下例所示: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 validation)。以下示例使用@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 WebFlux 与 Spring MVC 不同,支持模型中的响应式类型——例如,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