Spring Framework Advent Calendar 2011 part.1 - Spring MVC で JSR-303 Validator を使う
前書き
どうも、Java 界のぼっちこと max747 です。
さて 12 月といえば Advent Calendar の時期でございます。各種コミュニティで Advent Calendar の企画が立ち上がっておりますが、私はそれらを遠巻きに眺めつつ Spring Framework の Advent Calendar をやります。Spring Framework およびその周辺プロダクトを中心に、ネタの続く限り続けようかなと。
Java 言語を対象とした Advent Calendar については Java Advent Calendar 2011 : ATND をご覧くださいませ。
JSR-303 Bean Validation
アノテーションを使用して Bean のバリデーションを記述する方法を定めた仕様です。2年ほど前に Final Release が出ています。JSR の名が付いていることからもわかるとおり、Java の標準化プロセスを経て定められている仕様です。リファレンス実装は Hibanate Validator です。ご存知の方も多いでしょう。
基本的な使い方
JSR-303 を使ったバリデーションのやり方については、id:yamkazu さんの記事 JSR 303 Bean Validationで遊んでみるよ! - Yamkazu's Blog に詳しく書かれています。ぜひお読みください。
Spring MVC に組み込むには
Spring MVC 用の Bean 定義ファイルに、以下を記述します。Spring 3.0.x で MVC を使っている方は、きっとすでに設定してありますよね。
<mvc:annotation-driven />
あとは、ライブラリ (jar ファイル) を放り込むだけです。超簡単ですね! なお JSR-303 がサポートされたのは Spring 3.0 からですので、2.x 系をお使いの方は速やかにアップデートされることをおすすめいたします。
バリデーションを動かす
Spring MVC では Controller のメソッドに HTTP の URL をマッピングします。このとき、メソッドの引数に受け取る form を書きますが、この form をバリデーションしたい場合に @Valid アノテーション (javax.validation.Valid) を与えます。すると、このコントローラーメソッドに到達する直前に Bean Validaiton が行われ、その結果が BindingResult オブジェクトに格納されます。
@RequestMapping(value = "/register", method = RequestMethod.POST) public String register(@Valid RegisterForm form, BindingResult result) { if (result.hasErrors()) { return "register/input"; } return "register/end"; }
ここで注意が必要なのは、
- form と BindingResult はセットで引数にする必要があること
- form, BindingResult の順で、隣り合うように引数を並べること
この 2 つです。
エラーメッセージのローカライズ
Hibanate validator の流儀に従うなら、classpath のルートに ValidationMessages.properties ファイルを用意して対応することになります。ただし、そこは Spring ということで、Spring 流の messageSource を使う方法も提供されています*1。方法は、Bean 定義ファイルに messageSource を定義して、
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basename" value="classpath:messages" /> </bean>
メッセージ用のプロパティファイルを用意するだけです。
NotEmpty=\u5fc5\u9808\u3067\u3059 ## NotEmpty=必須です
通常、メッセージ用のプロパティファイルはすでにあるでしょうから、そこに追記すればよいでしょう。なお、バリデーションのメッセージを特定のフォームのときだけ別のメッセージに変更する、といったことも可能です。
NotEmpty=\u5fc5\u9808\u3067\u3059 # すべての NotEmpty アノテーションに影響します registerForm.NotEmpty=\u5fc5\u9808\u3067\u3059 # registerForm の NotEmpty アノテーションに影響します
以上、駆け足でしたが JSR-303 Validator を Spring に組み込む方法の紹介でした。実際に動作するサンプルも用意しています。適当に clone して遊んでください。
https://github.com/max747/spring-examples/
*1:詳細は確認していませんが、バージョン 3.0.4 以降でないとダメかもしれません