DataBinder

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

  • リクエストパラメーターをモデルオブジェクトにバインドします。

  • リクエスト値を文字列からオブジェクトのプロパティ型に変換します。

  • HTML フォームをレンダリングするときに、モデルオブジェクトのプロパティを文字列としてフォーマットします。

@Controller では、DataBinder カスタマイズはコントローラー内でローカルに適用されるか、アノテーションを通じて名前で参照される特定のモデル属性にも適用されます。@ControllerAdvice では、カスタマイズはコントローラーのすべてまたはサブセットに適用できます。

PropertyEditorConverterFormatter コンポーネントを DataBinder に登録して型変換を行うことができます。あるいは、WebFlux 設定を使用して、グローバルに共有される FormattingConversionService に Converter および Formatter コンポーネントを登録することもできます。

  • 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
	protected void initBinder(WebDataBinder binder) {
		binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd")); (1)
	}

	// ...
}
1 カスタムフォーマッタ(この場合は DateFormatter)を追加します。
@Controller
class FormController {

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

	// ...
}
1 カスタムフォーマッタ(この場合は DateFormatter)を追加します。

モデル設計

Web リクエストのデータバインドには、リクエストパラメーターをモデルオブジェクトにバインドすることが含まれます。デフォルトでは、リクエストパラメーターはモデルオブジェクトの任意のパブリックプロパティにバインドできます。つまり、悪意のあるクライアントは、モデルオブジェクトグラフに存在するが設定されることが予期されていないプロパティに追加の値を提供する可能性があります。このため、モデルオブジェクトの設計には慎重な検討が必要です。

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

Web データバインディング用に JPA エンティティや Hibernate エンティティなどのドメインモデルを公開するのではなく、専用のモデルオブジェクトを使用することをお勧めします。例: メールアドレスを変更するフォームで、入力に必要なプロパティのみを宣言する 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;
	}

}

もう 1 つの良い方法は、コンストラクターバインディングを適用することです。これは、コンストラクター引数に必要なリクエストパラメーターのみを使用し、他の入力は無視されます。これは、一致するプロパティが存在するすべてのリクエストパラメーターをデフォルトでバインドするプロパティバインディングとは対照的です。

専用のモデルオブジェクトもコンストラクターバインディングも十分ではなく、プロパティバインディングを使用する必要がある場合は、予期しないプロパティが設定されるのを防ぐために、WebDataBinder に allowedFields パターン (大文字と小文字を区別) を登録することを強くお勧めします。例:

@Controller
public class ChangeEmailController {

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

	// @RequestMapping methods, etc.

}

disallowedFields パターン (大文字と小文字を区別しない) を登録することもできます。ただし、「許可」設定は、より明示的で間違いが発生しにくいため、「禁止」設定よりも推奨されます。

デフォルトでは、コンストラクターとプロパティバインディングの両方が使用されます。コンストラクターバインディングのみを使用する場合は、コントローラー内でローカルに、または @ControllerAdvice を通じてグローバルに、@InitBinder メソッドを通じて WebDataBinder に declarativeBinding フラグを設定できます。このフラグをオンにすると、allowedFields パターンが構成されていない限り、コンストラクターバインディングのみが使用され、プロパティバインディングは使用されなくなります。例:

@Controller
public class MyController {

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

	// @RequestMapping methods, etc.

}