@ModelAttribute
@ModelAttribute
方法引數註解將表單資料、查詢引數、URI 路徑變數和請求頭繫結到模型物件上。例如:
-
Java
-
Kotlin
@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 例項。 |
表單資料和查詢引數優先於 URI 變數和請求頭,後者僅在不覆蓋同名請求引數的情況下包含。頭名稱中的連字元會被去除。
Pet
例項可以
-
從模型中訪問,該模型可能由
Model
新增。 -
如果模型屬性在類級別的
@SessionAttributes
中列出,則可從 HTTP 會話中訪問。 -
透過預設建構函式例項化。
-
透過與 Servlet 請求引數匹配的引數的“主建構函式”例項化。引數名稱透過位元組碼中執行時保留的引數名稱確定。
預設情況下,建構函式繫結和屬性資料繫結都會應用。但是,模型物件設計需要仔細考慮,出於安全原因,建議要麼使用專門為 Web 繫結定製的物件,要麼僅應用建構函式繫結。如果仍然必須使用屬性繫結,則應設定 allowedFields 模式以限制哪些屬性可以設定。有關此內容和示例配置的更多詳細資訊,請參見模型設計。
使用建構函式繫結時,可以透過 @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";
}
// ...
}
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 。 |
要使用 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";
}
// ...
}
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 。 |
如果因為其他引數帶有 @Constraint
註解而應用方法驗證,則會丟擲 HandlerMethodValidationException
。請參閱控制器方法驗證部分。
使用 @ModelAttribute 是可選的。預設情況下,任何不是由 BeanUtils#isSimpleProperty 確定的簡單值型別 並且 未由其他任何引數解析器解析的引數,都被視為隱式的 @ModelAttribute 。 |
當使用 GraalVM 編譯成本地映象時,上述隱式 @ModelAttribute 支援不允許提前推斷相關資料繫結反射提示。因此,建議在使用 GraalVM 本地映象時,顯式使用 @ModelAttribute 註解方法引數。 |