SpringフレームワークにはBinderという概念があります。Spring MVC(Boot)では@RequestParamを使用してパラメータを受け取るときにこのBinderを使用するのですが実はこれ、簡単にカスタマイズすることができるんです。今回はこのBinderのオーバーライドの方法について書いてみます。
例
実際に自分が困った例です。フロントをMPAで実装し、HTMLのformを用いて日時を送信する処理を書きました。このとき未入力でsubmitした場合、空文字がセットされます。
<input type="date" name="bornAt">
@Controller
public class UserController {
@PostMapping
public String createUser(@RequestParam UserRequest user){
// 処理
}
}
public class UserRequest {
private final Date bornAt;
public UserRequest(Date bornAt){
this.bornAt = bornAt;
}
public Date getBornAt() {
return this.bornAt;
}
}
ここでbornAtを空文字で送信した場合、user.bornAtはうまく初期化を行うことができません。これはDateクラスに対するBinderに空文字に対する動作が定義されていないためであると言えます。
ここでuser.bornAtをnullで初期化したい場合を例にとってやってみます。
Binderの登録
コントローラーに以下のようなメソッドを登録するとBinderを受け取れます。
@Controller
public class UserController {
@InitBinder
public void initBinder(WebdataBinder binder){
final var dateFormat = new SimpleDateFormat("yyyy/MM/dd");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
}
// 省略
このWebdataBinderにCustomEditorを登録することでBinderの処理を書き換えていきます。
final var dateFormat = new SimpleDateFormat("yyyy/MM/dd");
として生成されたdateFormatは空文字を受け取ったときにnullを返します。
さらに
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
によりbinderにDateクラスのとき、CustomDateEditorを使用することを伝えます。CustomDateEditorは実際に変換を行うためのクラスであり、もちろんユーザーによる定義も可能です。その場合はPropertyEditorSupportを継承したクラスを作成します。
Date型のように一部の型についてはすでに用意されたものがあるので比較的簡単に実装可能です。
プロパティ名を指定する
上記の方法ではすべてのDateが新しく定義したCustomEditorでバインドされます。これを特定のフィールドのみに絞りたい場合、
binder.registerCustomEditor(Date.class, "user.bornAt", new CustomDateEditor(dateFormat, true));
とすることでuserのbornAtに限定することができます。