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

DataBinder

@Controller または @ControllerAdvice クラスには、WebDataBinder のインスタンスを初期化する @InitBinder メソッドを含めることができます。これらのメソッドは、次のことができます。

  • リクエストパラメーター(つまり、フォームまたはクエリデータ)をモデルオブジェクトにバインドします。

  • 文字列ベースのリクエスト値(リクエストパラメーター、パス変数、ヘッダー、Cookie など)をコントローラーメソッド引数のターゲット型に変換します。

  • HTML フォームをレンダリングするときに、モデルオブジェクト値を String 値としてフォーマットします。

@InitBinder メソッドは、コントローラー固有の java.beans.PropertyEditor または Spring Converter および Formatter コンポーネントを登録できます。さらに、MVC 設定を使用して、Converter および Formatter 型をグローバルに共有される FormattingConversionService に登録できます。

@InitBinder メソッドは、@ModelAttribute (コマンドオブジェクト)引数を除き、@RequestMapping メソッドと同じ引数の多くをサポートします。通常、それらは WebDataBinder 引数(登録用)および void 戻り値で宣言されます。次のリストに例を示します。

  • Java

  • Kotlin

@Controller
public class FormController {

	@InitBinder (1)
	public void initBinder(WebDataBinder binder) {
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		dateFormat.setLenient(false);
		binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
	}

	// ...
}
1@InitBinder メソッドの定義。
@Controller
class FormController {

	@InitBinder (1)
	fun initBinder(binder: WebDataBinder) {
		val dateFormat = SimpleDateFormat("yyyy-MM-dd")
		dateFormat.isLenient = false
		binder.registerCustomEditor(Date::class.java, CustomDateEditor(dateFormat, false))
	}

	// ...
}
1@InitBinder メソッドの定義。

あるいは、共有 FormattingConversionService を介して Formatter ベースのセットアップを使用する場合、次の例に示すように、同じアプローチを再利用して、コントローラー固有の Formatter 実装を登録できます。

  • Java

  • Kotlin

@Controller
public class FormController {

	@InitBinder (1)
	protected void initBinder(WebDataBinder binder) {
		binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
	}

	// ...
}
1 カスタムフォーマッタで @InitBinder メソッドを定義します。
@Controller
class FormController {

	@InitBinder (1)
	protected fun initBinder(binder: WebDataBinder) {
		binder.addCustomFormatter(DateFormatter("yyyy-MM-dd"))
	}

	// ...
}
1 カスタムフォーマッタで @InitBinder メソッドを定義します。

モデル設計

Web アプリケーションのコンテキストでは、データバインディングには、HTTP リクエストパラメーター(つまり、フォームデータまたはクエリパラメーター)をモデルオブジェクトとそのネストされたオブジェクトのプロパティにバインドすることが含まれます。

JavaBeans の命名規則 [Oracle] (英語) に続く public プロパティのみがデータバインディングに公開されます。たとえば、firstName プロパティの public String getFirstName() および public void setFirstName(String) メソッドです。

モデルオブジェクトとそのネストされたオブジェクトグラフは、コマンドオブジェクトフォームバッキングオブジェクト、または POJO (Plain Old Java Object)と呼ばれることもあります。

デフォルトでは、Spring はモデルオブジェクトグラフのすべてのパブリックプロパティへのバインドを許可します。これは、クライアントが任意のパブリックプロパティパスをターゲットにできるため、モデルがどのパブリックプロパティを持っているかを慎重に検討する必要があることを意味します。

例: HTTP フォームデータエンドポイントが与えられた場合、悪意のあるクライアントがモデルオブジェクトグラフに存在するがブラウザーに表示される HTML フォームの一部ではないプロパティの値を提供する可能性があります。これにより、モデルオブジェクトとそのネストされたオブジェクトにデータが設定され、更新されることが期待されない可能性があります。

推奨されるアプローチは、フォームの送信に関連するプロパティのみを公開する専用のモデルオブジェクトを使用することです。例: ユーザーのメールアドレスを変更するためのフォームで、モデルオブジェクトは次の ChangeEmailForm のようにプロパティの最小セットを宣言する必要があります。

public class ChangeEmailForm {

	private String oldEmailAddress;
	private String newEmailAddress;

	public void setOldEmailAddress(String oldEmailAddress) {
		this.oldEmailAddress = oldEmailAddress;
	}

	public String getOldEmailAddress() {
		return this.oldEmailAddress;
	}

	public void setNewEmailAddress(String newEmailAddress) {
		this.newEmailAddress = newEmailAddress;
	}

	public String getNewEmailAddress() {
		return this.newEmailAddress;
	}

}

データバインディングのユースケースごとに専用のモデルオブジェクトを使用できない、または使用したくない場合は、データバインディングに許可されるプロパティを制限する必要があります。理想的には、WebDataBinder で setAllowedFields() メソッドを介して許可されたフィールドパターンを登録することにより、これを実現できます。

例: アプリケーションで許可されたフィールドパターンを登録するには、以下に示すように、@Controller または @ControllerAdvice コンポーネントに @InitBinder メソッドを実装できます。

@Controller
public class ChangeEmailController {

	@InitBinder
	void initBinder(WebDataBinder binder) {
		binder.setAllowedFields("oldEmailAddress", "newEmailAddress");
	}

	// @RequestMapping methods, etc.

}

許可されたパターンの登録に加えて、DataBinder およびそのサブクラスの setDisallowedFields() メソッドを介して許可されていないフィールドパターンを登録することもできます。ただし、「許可リスト」は「拒否リスト」よりも安全であることに注意してください。setDisallowedFields() よりも setAllowedFields() を優先する必要があります。

許可されたフィールドパターンとの照合では大文字と小文字が区別されることに注意してください。一方、許可されていないフィールドパターンとの照合では、大文字と小文字は区別されません。さらに、許可されていないパターンに一致するフィールドは、許可されたリストのパターンにも一致する場合でも受け入れられません。

データバインディングの目的でドメインモデルを直接公開する場合は、許可および禁止のフィールドパターンを適切に構成することが非常に重要です。そうでなければ、大きなセキュリティリスクです。

さらに、データバインディングシナリオのモデルオブジェクトとして、JPA や Hibernate エンティティなどのドメインモデルの型を使用しないことを強くお勧めします。