最新の安定バージョンについては、Spring Framework 7.0.3 を使用してください!

@ModelAttribute

メソッド引数で @ModelAttribute アノテーションを使用して、モデルから属性にアクセスするか、存在しない場合はインスタンス化することができます。モデル属性には、名前がフィールド名と一致するクエリパラメーターとフォームフィールドの値もオーバーレイされます。これはデータバインディングと呼ばれ、個々のクエリパラメーターとフォームフィールドの解析と変換を行う必要がなくなります。次の例は、Pet のインスタンスをバインドします。

  • 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 を介してすでに追加されている場合はモデルから。

  • HTTP セッションから @SessionAttributes を経由します。

  • デフォルトのコンストラクターの呼び出しから。

  • クエリパラメーターまたはフォームフィールドに一致する引数を持つ「プライマリコンストラクター」の呼び出しから。引数名は、JavaBeans @ConstructorProperties またはバイトコード内の実行時保持パラメーター名によって決定されます。

モデル属性インスタンスが取得された後、データバインディングが適用されます。WebExchangeDataBinder クラスは、クエリパラメーターとフォームフィールドの名前をターゲット Object のフィールド名に一致させます。一致するフィールドは、必要に応じて型変換が適用された後に入力されます。データバインディング(および検証)の詳細については、検証を参照してください。データバインディングのカスタマイズの詳細については、DataBinder を参照してください。

データバインディングはエラーになる可能性があります。デフォルトでは、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 を追加します。

jakarta.validation.Valid アノテーションまたは Spring の @Validated アノテーションを追加することにより、データバインディング後に検証を自動的に適用できます(Bean バリデーションおよび Spring 検証も参照)。次の例では、@Valid アノテーションを使用しています。

  • 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 を使用します。

Spring WebFlux は、Spring MVC とは異なり、モデル内のリアクティブ型 (たとえば、Mono<Account> または io.reactivex.Single<Account>) をサポートします。リアクティブ型ラッパーの有無にかかわらず @ModelAttribute 引数を宣言でき、必要に応じて実際の値に解決されます。ただし、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 ->
				// ...
			}
}

@ModelAttribute の使用はオプションであることに注意してください。たとえば、その属性を設定する場合などです。デフォルトでは、( BeanUtils#isSimpleProperty (Javadoc) によって決定される) 単純な値の型ではなく、他の引数リゾルバーによって解決されない引数は、@ModelAttribute でアノテーションが付けられているかのように扱われます。

GraalVM を使用してネイティブイメージにコンパイルする場合、上記の暗黙的な @ModelAttribute サポートでは、関連するデータバインディングのリフレクションヒントを適切に事前推論できません。結果として、GraalVM ネイティブイメージで使用するためにメソッドパラメーターに @ModelAttribute のアノテーションを明示的に付けることをお勧めします。