@ModelAttribute
@ModelAttribute
メソッドパラメーターアノテーションは、リクエストパラメーターをモデルオブジェクトにバインドします。例:
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 のインスタンスにバインドします。 |
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 を設定することで別のアノテーションを使用することもできます。 |
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 のアノテーションを明示的に付けることをお勧めします。 |