データバインド

データバインディングとは、文字列パラメーターを型変換を伴うオブジェクトグラフにバインドするメカニズムです。これは Spring Framework の中核となるメカニズムであり、アプリケーション構成に役立ちます。Web アプリケーションでは、文字列値のマップではなく、豊富な型を持つオブジェクトを介してクエリパラメーターやフォームデータに簡単にアクセスできるようになります。

データバインディングメカニズム(コンストラクターと setter のバインディング、プロパティ名の構文、型変換など)の詳細については、「コアテクノロジー」セクションのデータバインドを参照してください。

アノテーション付きコントローラーの場合、データバインディングは @ModelAttribute メソッドの引数に適用されます。関数エンドポイントの場合は、ServerRequest の bind メソッドを使用してください。

アノテーション付きコントローラーを使用するブラウザーアプリケーションの場合、@ModelAttribute メソッドを使用して、レンダリングされたビューで使用する追加のモデル属性を初期化できます。

各リクエストは個別の WebDataBinder インスタンスを使用します。アノテーション付きコントローラーの場合、このインスタンスはコントローラー内で @InitBinder メソッドを使用してカスタマイズするか、コントローラー間でコントローラーのアドバイスを使用してカスタマイズできます。関数エンドポイントの場合は、オーバーロードされた ServerRequest.bind メソッドを使用します。

モデル設計

データバインディングとは、信頼できない入力をアプリケーションオブジェクトにバインドすることです。セキュリティ上の理由から、入力が想定されるフィールドのみに適切に制限されていることを確認することが非常に重要です。このセクションでは、安全なバインディングのためのガイダンスを提供します。

まず、Web バインディングには不変オブジェクト設計を推奨します。コンストラクターによってバインディングが想定される入力に自然に制約されるため、安全です。Java レコードまたはプライマリコンストラクターを持つクラスを使用でき、どちらもさらにネストされたオブジェクトを持つことができます。詳細はコンストラクターのバインドを参照してください。

安全なバインディングを実現するもう一つの方法は、想定される入力に合わせて設計された専用オブジェクトを使用することです。このようなオブジェクトは、たとえ変更可能であっても、バインディングを想定される入力に限定するため安全です。

JPA エンティティや Hibernate エンティティなどのドメインオブジェクトは、想定される入力よりも多くのプロパティを含む可能性があるため、一般的に Web バインディングには適していません。このような場合、バインディング用に公開するプロパティを宣言することが重要です。例:

@Controller
public class PersonController {

	@InitBinder
	void initBinder(WebDataBinder binder) {
		// See Javadoc for supported pattern syntax
		binder.setAllowedFields("firstName", "lastName", "*Address");
	}
}
disallowedFields を設定することも可能ですが、これは不安定なため、Spring Framework 7.1 で非推奨 [GitHub] (英語) となる予定です。除外すべきフィールドを見落としたり、時間の経過とともに追加されるフィールドも考慮する必要があります。

デフォルトでは、DataBinder はコンストラクターバインディングと setter バインディングの両方を適用します。これは不変オブジェクトと専用オブジェクトでは問題ありませんが、ドメインオブジェクトの場合は allowedFields を設定する必要があります。データバインディングが、期待される入力が明示的に宣言されている宣言スタイルでのみ使用されるようにするには、DataBinder に declarativeBinding を設定できます。これにより、コンストラクターバインディングが常に適用され、allowedFields が設定されている場合は条件付きで setter バインディングが適用されます。以下に、このフラグをグローバルに設定する方法を示します。また、ControllerAdvice の属性を使用して絞り込むこともできます。

@ControllerAdvice
public class ControllerConfig {

	@InitBinder
	void initBinder(WebDataBinder binder) {
		binder.setDeclarativeBinding(true);
	}
}