@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 セッションからアクセスされます。デフォルトのコンストラクターを通じてインスタンス化されます。
サーブレットリクエストパラメーターに一致する引数を持つ「プライマリコンストラクター」を通じてインスタンス化されます。引数名は、バイトコード内でランタイムに保持されるパラメーター名によって決定されます。
デフォルトでは、コンストラクターとプロパティデータバインディングの両方が適用されます。ただし、モデルオブジェクトの設計には慎重な検討が必要であり、セキュリティ上の理由から、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
などのインデックスキーに基づく配列引数をサポートします。
WebFlux は、Spring MVC とは異なり、モデル内のリアクティブ型 (例: 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 バリデーションおよび 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 (Javadoc) によって決定される単純な値型ではなく、かつ他の引数リゾルバーによって解決されない引数は、暗黙的な @ModelAttribute として扱われます。 |
GraalVM を使用してネイティブイメージにコンパイルする場合、上記の暗黙的な @ModelAttribute サポートでは、関連するデータバインディングのリフレクションヒントを適切に事前推論できません。結果として、GraalVM ネイティブイメージで使用するためにメソッドパラメーターに @ModelAttribute のアノテーションを明示的に付けることをお勧めします。 |