@ModelAttribute
@ModelAttribute
方法引數註解將請求引數、URI 路徑變數和請求頭繫結到模型物件上。例如
-
Java
-
Kotlin
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) { (1)
// method logic...
}
1 | 繫結到 `Pet` 的一個例項。 |
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute pet: Pet): String { (1)
// method logic...
}
1 | 繫結到 `Pet` 的一個例項。 |
請求引數是 Servlet API 中的一個概念,包括來自請求體的表單資料和查詢引數。URI 變數和請求頭也包括在內,但僅當它們不覆蓋同名請求引數時。請求頭名稱中的破折號會被去除。
上面的 Pet
例項可以
-
從模型中訪問,它可能已透過 @ModelAttribute 方法 新增到模型中。
-
如果模型屬性列在類級別的 `@SessionAttributes` 註解中,則可以從 HTTP 會話中訪問。
-
如果模型屬性名稱與請求值(如路徑變數或請求引數)的名稱匹配,並且存在相容的
Converter<String, T>
,則可以透過Converter
獲取模型物件(示例見下)。 -
透過預設建構函式例項化。
-
透過帶有與 Servlet 請求引數匹配的引數的“主建構函式”例項化。引數名稱透過位元組碼中執行時保留的引數名稱確定。
如上所述,如果模型屬性名稱與請求值(如路徑變數或請求引數)的名稱匹配,並且存在相容的 Converter<String, T>
,則可以使用 Converter<String, T>
獲取模型物件。在下面的示例中,模型屬性名稱 account
與 URI 路徑變數 account
匹配,並且存在一個註冊的 Converter<String, Account>
,它可能會從持久化儲存中檢索物件
-
Java
-
Kotlin
@PutMapping("/accounts/{account}")
public String save(@ModelAttribute("account") Account account) { (1)
// ...
}
@PutMapping("/accounts/{account}")
fun save(@ModelAttribute("account") account: Account): String { (1)
// ...
}
預設情況下,建構函式和屬性資料繫結都會應用。然而,模型物件的設計需要仔細考慮,出於安全原因,建議使用專門為 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
。
在某些情況下,您可能希望在不進行資料繫結的情況下訪問模型屬性。對於這種情況,您可以將 Model
注入到控制器中並直接訪問它,或者,如以下示例所示,設定 @ModelAttribute(binding=false)
-
Java
-
Kotlin
@ModelAttribute
public AccountForm setUpForm() {
return new AccountForm();
}
@ModelAttribute
public Account findAccount(@PathVariable String accountId) {
return accountRepository.findOne(accountId);
}
@PostMapping("update")
public String update(AccountForm form, BindingResult result,
@ModelAttribute(binding=false) Account account) { (1)
// ...
}
1 | 設定 `@ModelAttribute(binding=false)`。 |
@ModelAttribute
fun setUpForm(): AccountForm {
return AccountForm()
}
@ModelAttribute
fun findAccount(@PathVariable accountId: String): Account {
return accountRepository.findOne(accountId)
}
@PostMapping("update")
fun update(form: AccountForm, result: BindingResult,
@ModelAttribute(binding = false) account: Account): String { (1)
// ...
}
1 | 設定 `@ModelAttribute(binding=false)`。 |
如果資料繫結導致錯誤,預設情況下會丟擲 MethodArgumentNotValidException
,但您也可以在 `@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 | 在 `@ModelAttribute` 旁邊新增 BindingResult 。 |
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute("pet") pet: Pet, result: BindingResult): String { (1)
if (result.hasErrors()) {
return "petForm"
}
// ...
}
1 | 在 `@ModelAttribute` 旁邊新增 BindingResult 。 |
您可以透過新增 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 | 驗證 Pet 例項。 |
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@Valid @ModelAttribute("pet") pet: Pet, result: BindingResult): String { (1)
if (result.hasErrors()) {
return "petForm"
}
// ...
}
1 | 驗證 Pet 例項。 |
如果 `@ModelAttribute` 後沒有 BindingResult
引數,則會丟擲 MethodArgumentNotValueException
幷包含驗證錯誤。然而,如果由於其他引數具有 @jakarta.validation.Constraint
註解而應用了方法驗證,則會改為丟擲 HandlerMethodValidationException
。更多詳細資訊,請參閱驗證部分。
使用 `@ModelAttribute` 是可選的。預設情況下,任何非簡單值型別(由 BeanUtils#isSimpleProperty 確定) 並且 沒有被任何其他引數解析器解析的引數,都會被視為一個隱式的 `@ModelAttribute`。 |
使用 GraalVM 編譯成本機映象時,上述描述的隱式 `@ModelAttribute` 支援無法正確地提前推斷相關資料繫結反射提示。因此,建議在使用 GraalVM 本機映象時,顯式地用 `@ModelAttribute` 註解方法引數。 |