@ModelAttribute
@ModelAttribute
@ModelAttribute方法参数注解可以将表单数据、查询参数、URI路径变量和请求头绑定到模型对象上。例如:
- Java
- Kotlin
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) { } 1
与
Pet实例绑定。
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute pet: Pet): String { } 1
- \ [#1] 与
Pet实例绑定。
表单数据和查询参数的优先级高于 URI 变量及头部信息;只有当这些头部信息不会覆盖同名请求参数时,才会被包含进来。头部信息的名称中的短横线(-)会被删除。
Pet实例可以是:
- 从模型中访问,该模型可能通过Model进行添加。
- 如果模型属性在类级别的@SessionAttributes中列出,则从HTTP会话中访问。
- 通过默认构造函数实例化。
- 通过“主构造函数”实例化,其参数与Servlet请求参数匹配。参数名称是根据字节码中在运行时保留的参数名称来确定的。
在使用构造函数绑定时,你可以通过@BindParam注解来自定义请求参数的名称。例如:
- Java
- Kotlin
class Account {
private final String firstName;
public Account(@BindParam("first-name") String firstName) {
this.firstName = firstName;
}
}
class Account(@BindParam("first-name") val firstName: String)
@BindParam也可以用于对应于构造函数参数的字段上。虽然@BindParam是默认支持的,但你也可以通过在DataBinder上设置DataBinder.NameResolver来使用不同的注解。
构造函数绑定支持List、Map和数组参数,这些参数可以是从单个字符串转换而来的(例如,逗号分隔的列表),也可以是基于索引键的,如accounts[2].name或account[KEY].name。
与Spring MVC不同,WebFlux在模型中支持响应式类型(例如Mono<Account>)。你可以声明一个带有或不带有响应式类型包装器的@ModelAttribute参数,它将根据实际值进行相应的解析。
如果数据绑定导致错误,默认会抛出WebExchangeBindException,但你也可以在@ModelAttribute旁边直接添加一个BindingResult参数,以便在控制器方法中处理此类错误。例如:
- Java
- Kotlin
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) { 1
if (result.hasErrors()) {
return "petForm";
}
// ...
}
添加了
BindingResult。
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute("pet") pet: Pet, result: BindingResult): String { 1
if (result.hasErrors()) {
return "petForm"
}
// ...
}
添加了
BindingResult。
要使用BindingResult参数,你必须先声明没有反应型类型包装的@ModelAttribute参数。如果你想使用反应型类型,就可以通过它直接处理错误。例如:
- Java
- Kotlin
@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 ->
// ...
}
}
你可以在数据绑定后自动应用验证,只需添加 jakarta.validation VALID 注解或 Spring 的 @Validated 注解(请参阅 Bean Validation 和 Spring 验证)。例如:
- Java
- Kotlin
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) { 1
if (result.hasErrors()) {
return "petForm";
}
// ...
}
在模型属性参数上使用
@Valid。
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@Valid @ModelAttribute("pet") pet: Pet, result: BindingResult): String { 1
if (result.hasErrors()) {
return "petForm"
}
// ...
}
在模型属性参数上使用
@Valid。
如果由于其他参数具有@Constraint注解而需要应用方法验证,那么将会抛出HandlerMethodValidationException异常。请参阅关于控制器方法验证的相关部分。
使用@ModelAttribute是可选的。默认情况下,任何不是由BeanUtils#isSimpleProperty判断为简单值类型的参数,并且没有通过其他参数解析器进行解析的,都会被视为隐式的@ModelAttribute。
在使用GraalVM编译为原生镜像时,上述隐式的@ModelAttribute支持不允许对相关的数据绑定反射提示进行适当的提前推断。因此,建议在方法参数上明确标注@ModelAttribute,以便在GraalVM原生镜像中使用。