かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

Spring Bootで入力値の検証(バリデーション)の順番を制御する

okazuki.hatenablog.com

基本的に上の記事の通りでいいんですが、複数の属性を同じプロパティにつけた場合に、一気にバリデーションが実行されてエラーメッセージがうざいことになってしまいます。例えば以下のようなBeanがあったとして。

package okazuki.validationEdu;

import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;

public class Person {
    @NotEmpty(message = "なまえ入れてね")
    @Length(min = 1, max = 10, message = "1~10の間")
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    
    
}

フォームに何も入力せずにPOSTすると以下のようにNotEmptyとLength両方がバリデーションされてしまいます。

f:id:okazuki:20150713205957p:plain

NotEmptyでエラーになったときはLengthはエラーチェックしなくてもいいという状況に対応するにはgroupsを使います。

以下のようにバリデーションをグルーピングするためのインターフェースを用意します。

package okazuki.validationEdu;

public interface First {

}
package okazuki.validationEdu;

public interface Second {

}

そして、これを束ねるためのインターフェースも用意します。

package okazuki.validationEdu;

import javax.validation.GroupSequence;

@GroupSequence({First.class, Second.class})
public interface All {

}

そして、Personクラスの属性にFirstとSecondを設定します。

package okazuki.validationEdu;

import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;

public class Person {
    @NotEmpty(message = "なまえ入れてね", groups = First.class)
    @Length(min = 1, max = 10, message = "1~10の間", groups = Second.class)
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    
    
}

最後にControllerで@Validated属性に、Allを指定します。

package okazuki.validationEdu;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class HomeController {

    @RequestMapping
    public String index(@ModelAttribute("form") Person p) {
        return "index";
    }

    @RequestMapping(method = RequestMethod.POST)
    public String indexPost(@ModelAttribute("form") @Validated(All.class) Person p, BindingResult r) {
        return "index";
    }
}

こうすると、Firstのgroupのバリデーションを実行してエラーになったらそこでとまります。ここでいうとNotEmptyだけが実行されるようになります。NotEmptyを通過したらLengthがチェックされます。