いつも書き方を忘れて、ネットの海をさ迷っちゃうのでいい加減自分でまとめようと思う。
コードはここです。
Kotlinなのは特に意味はないけれど、定期的に書かないと忘れちゃうからです。
とりあえず入力チェック編
まずは、必須入力チェックをしてみる。

ポイントその1:@NotNullじゃなくて@NotBlankを使うよ
@NotBlank var name: String = ""
ここ、HTMLのtextフォームからフォームクラスにStringで値が入るときには、空""で入ってくる仕様らしい。
なのでnullかどうかを見る、@NotNullだとバリデートエラーにならなくて、空白か空かどうかも見てくれる、@NotBlankのほうがよさそう。
ポイントその2:BindingResultは必ず@Validatedの後
@RequestMapping(method = arrayOf(RequestMethod.POST))
fun doPost(@Validated inputForm: InputForm, bindingResult: BindingResult, model: Model): String {
return "input/form";
}
BindingResultには、@Validatedを付けた引数のバリデート結果が入る。
んで、このBindingResultを@Validatedが付いた引数の後ろに定義するという村の決まりごとがあって、これをしないとエラーでこける。
日本語で表示したい編
これ、エラー表示が英語じゃないですか!
そうですね、日本語で表示しましょう。
resourcesディレクトリの直下にValidationMessages.propertiesというファイルを作って、以下を書く。
org.hibernate.validator.constraints.NotBlank.message={0}:必須入力ですよ
んで、もう一度アプリケーション起動して、送信してみる。
org.springframework.context.support.DefaultMessageSourceResolvable: codes [inputForm.name,name]; arguments []; default message [name]:必須入力ですよ
なんかtoStringっぽいのが出ているが、無事指定したメッセージが出でる。
@NotBlankは、hibernate validatorのアノテーションなので、そのデフォルトのメッセージ定義を上書きしてあげればよい。
ほかのアノテーションの定義は↓から、確認できる。
ポイントその3 プロパティファイルのはエンコーディングはUTF-8
IDEとかで、プロパティファイルを作ると ISO-8859-1でエンコードされたりするんだけど、これだと日本語が文字化けしてうまく出力されない。
ちゃんと、エンコードの設定を確認する。
ポイントその4 {0}を使うときはメッセージ定義ファイルを作る
で、ここ({0})の部分。
ほかの解説ページとかだと、プロパティ名(今回の例だとname)が出るって書いてあるんだけど、うまく出てない。
org.springframework.context.support.DefaultMessageSourceResolvable: codes [inputForm.name,name]; arguments []; default message [name]
なぜかはわからんが、メッセージ定義ファイルを作ってあげるとちゃんと出る。
(しばらくなんでか調べたけどよくわからんかった)
外部にメッセージ定義(リソース?)を持つ設定の仕方は、いろんなところに書いてあると思うので説明は割愛。
application.propertiesに以下を設定。
spring.messages.basename=messages spring.messages.cache-seconds=-1 spring.messages.encoding=UTF-8
resourcesディレクトリの直下にmessages.propertiesを作る。
(ファイルの名前は設定と一致してればなんでもよさそう)
もう一度起動しなおして、送信。

プロパティ名が出ました。
エラーメッセージにプロパティ名が出たのはいいけど、ユーザからしたらnameって何ぞや状態なので、これも差し替えましょう。
さっき作ったmessages.propertiesに、↓を書く。
name=名前
すると、ちゃんとnameのところが差し変わっている。

ちなみに、nameの部分はプロパティ名で、inputForm.nameとかでもちゃんと置換される。
独自のメッセージを表示したい編
おなじ、@NotBlankエラーでも違うエラーメッセージを項目ごとに出したいことがある。
その時は、次のようにアノテーションを指定する。
InputForm.kt
@NotBlank(message="年齢も恥ずかしがらずにちゃんと入力しよう") var age: String = ""
アノテーションに直接メッセージを埋め込みたくない、几帳面なあなたはValidationMessages.propertiesにメッセージを書いて、それのキーを埋め込もう。
InputForm.kt
@NotBlank(message="{E0001}")
var age: String = ""
ValidationMessages.properties
E0001=年齢も恥ずかしがらずにちゃんと入力しよう
E0001、業務感がすごくてわくわくする

相関チェックしたい編
独自のチェックだったり、二つ以上の項目についてチェックしたいことがある。
そんな時は、自分でアノテーションを定義して、それを使う。
長々と書いてあるが、isValidがfalseならエラーになる。
それだけ。
public boolean isValid(Object value, ConstraintValidatorContext context) {
BeanWrapper beanWrapper = new BeanWrapperImpl(value);
String param1 = (String)beanWrapper.getPropertyValue(this.param1Field);
String param2 = (String)beanWrapper.getPropertyValue(this.param2Field);
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(message)
.addPropertyNode(this.param2Field)
.addConstraintViolation();
return Objects.equals(param1, param2);
}
なぜここだけJavaなのか…
それはKotlinでアノテーションの書き方がわからなかったからだよ。
悲しい。
ポイントその5 アノテーションは、クラス宣言の上につける
相関チェックみたいに複数のプロパティを対象とするバリデートのアノテーションは、クラスの宣言部分の上につける。
@Equals(param1 = "email1", param2 = "email2")
class InputForm {
こんな感じ。
