@ModelAttribute

@ModelAttribute メソッドパラメーターアノテーションは、リクエストパラメーターをモデルオブジェクトにバインドします。例:

  • Java

  • Kotlin

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) { } (1)
1Pet のインスタンスにバインドします。
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute pet: Pet): String { } (1)
1Pet のインスタンスにバインドします。

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";
	}
	// ...
}
1BindingResult を追加します。
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute("pet") pet: Pet, result: BindingResult): String { (1)
	if (result.hasErrors()) {
		return "petForm"
	}
	// ...
}
1BindingResult を追加します。

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 のアノテーションを明示的に付けることをお勧めします。