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 以降でないとダメかもしれません