@InitBinder
@Controller
クラスまたは @ControllerAdvice
クラスには、WebDataBinder
インスタンスを初期化するための @InitBinder
メソッドを含めることができ、これにより次のことが可能になります。
リクエストパラメーターをモデルオブジェクトにバインドします。
リクエスト値を文字列からオブジェクトのプロパティ型に変換します。
HTML フォームをレンダリングするときに、モデルオブジェクトのプロパティを文字列としてフォーマットします。
@Controller
では、DataBinder
カスタマイズはコントローラー内でローカルに適用されるか、アノテーションを通じて名前で参照される特定のモデル属性にも適用されます。@ControllerAdvice
では、カスタマイズはコントローラーのすべてまたはサブセットに適用できます。
PropertyEditor
、Converter
、Formatter
コンポーネントを DataBinder
に登録して型変換を行うことができます。あるいは、MVC 設定を使用して、グローバルに共有される FormattingConversionService
に Converter
および Formatter
コンポーネントを登録することもできます。
@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 リクエストのデータバインドには、リクエストパラメーターをモデルオブジェクトにバインドすることが含まれます。デフォルトでは、リクエストパラメーターはモデルオブジェクトの任意のパブリックプロパティにバインドできます。つまり、悪意のあるクライアントは、モデルオブジェクトグラフに存在するが設定されることが予期されていないプロパティに追加の値を提供する可能性があります。このため、モデルオブジェクトの設計には慎重な検討が必要です。
モデルオブジェクトおよびそのネストされたオブジェクトグラフは、コマンドオブジェクト、フォームバッキングオブジェクト、または 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.
}