@ModelAttribute
@ModelAttribute
メソッドパラメーターアノテーションは、リクエストパラメーターをモデルオブジェクトにバインドします。例:
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 のインスタンスにバインドします。 |
Pet
インスタンスは次のとおりです。
@ModelAttribute メソッドによって追加された可能性があるモデルからアクセスされます。
モデル属性がクラスレベルの
@SessionAttributes
アノテーションにリストされている場合は、HTTP セッションからアクセスされます。モデル属性名がパス変数やリクエストパラメーターなどのリクエスト値の名前と一致する場合、
Converter
を通じて取得されます (例は次のとおりです)。デフォルトのコンストラクターを通じてインスタンス化されます。
サーブレットリクエストパラメーターに一致する引数を持つ「プライマリコンストラクター」を通じてインスタンス化されます。引数名は、バイトコード内でランタイムに保持されるパラメーター名によって決定されます。
前述したように、モデル属性名がパス変数やリクエストパラメーターなどのリクエスト値の名前と一致し、互換性のある 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 を設定することで別のアノテーションを使用することもできます。 |
場合によっては、データバインディングなしでモデル属性にアクセスしたい場合があります。このような場合、次の例に示すように、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 | @ModelAt\tribute(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 バリデーションおよび 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 (Javadoc) によって決定される単純な値型ではなく、かつ他の引数リゾルバーによって解決されないパラメーターは、暗黙的な @ModelAttribute として扱われます。 |
GraalVM を使用してネイティブイメージにコンパイルする場合、上記の暗黙的な @ModelAttribute サポートでは、関連するデータバインディングのリフレクションヒントを適切に事前推論できません。結果として、GraalVM ネイティブイメージで使用するためにメソッドパラメーターに @ModelAttribute のアノテーションを明示的に付けることをお勧めします。 |