@ModelAttribute

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

  • Java

  • Kotlin

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

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

@ModelAttribute の後に BindingResult パラメーターがない場合は、検証エラーとともに MethodArgumentNotValueException が発生します。ただし、他のパラメーターに @jakarta.validation.Constraint アノテーションが付いているためにメソッド検証が適用される場合は、代わりに HandlerMethodValidationException が発生します。詳細については、"検証" セクションを参照してください。

@ModelAttribute の使用はオプションです。デフォルトでは、BeanUtils#isSimpleProperty (Javadoc) によって決定される単純な値型ではなくかつ他の引数リゾルバーによって解決されないパラメーターは、暗黙的な @ModelAttribute として扱われます。
GraalVM を使用してネイティブイメージにコンパイルする場合、上記の暗黙的な @ModelAttribute サポートでは、関連するデータバインディングのリフレクションヒントを適切に事前推論できません。結果として、GraalVM ネイティブイメージで使用するためにメソッドパラメーターに @ModelAttribute のアノテーションを明示的に付けることをお勧めします。