なぜSpring Bootで独自のバリデーションを作りたいの?
API開発を複数人で進めていると、APIで同じ項目が出てきます。
- 注文番号(orderNo)
- 商品コード(itmCd)
- 管理番号(mngNo)
- ユーザーID(usrId)
- 等々...
同じ項目であれば、同じアノテーションでバリデーションする事が当たり前。でも、ドキュメントやルールの周知を頑張っても意思疎通がとりきれずアノテーションがズレたものがポロポロと。。
そんなときの解決策の1つとして、カスタムバリデーションがあると思っています。
カスタムバリデーションのパターン
大きく分けて、2つあると思っています。
- 完全オリジナルなロジックが必要なもの
- 既存バリデーションの組み合わせで済むレベルのもの
後者を作成するとき、自前でロジックを組んでいませんか?
**@ReportAsSingleViolation
**の利用検討をお勧めいたします。
ReportAsSingleViolation
一言でいうと**「アノテーションをまとめるアノテーション」**
どうゆうことか、以下ソースの後にポイントを記載します。
@Documented
@Constraint(validatedBy = {})
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Size(min = 8, max = 10)
@Pattern(regexp = "^[a-zA-Z0-9]*$")
@ReportAsSingleViolation
public @interface UsrId {
/** エラーが発生した場合のエラーメッセージ. */
String message() default "ユーザーIDが正しく設定されていません";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Constraint(validatedBy = {})
{}
なんです。
やりたいことが既存の組み合わせで完結する場合、ロジックを記述するバリデータークラスは必要ありませんよね。
実際、このカスタムアノテーションはアノテーションの組み合わせだけで完結しています。
message() default "xxx"
@ReportAsSingleViolation
を利用するとデフォルトメッセージが機能します。これがすごい。
バリデーション動作時には@Size
と@Pattern
それぞれのメッセージ2つは出力されず、自分が設定したメッセージだけが出力されます。
つまりアノテーションがまとまっているんです。
さいごに
@ReportAsSingleViolation
を作ればファイル1つでカスタムバリデーション完成です。
カスタムバリデーションって難しそうだから忙しいし、今のプロジェクトへの適用は後回し。。という固定概念を破壊するくらいの手軽さ。
しかし効果はしっかり発揮します。
サンプルではユーザーID 項目を使う複数のDTOクラスやGETパラメータに以下がバラまかれるのを防ぎました。
@Size(min = 8, max = 10)
@Pattern(regexp = "^[a-zA-Z0-9]*$")
ルールとして@UsrId
を使おう!というのは必要になります。ですが、特定の引数を付けたバリデーション利用を徹底してください。というルールよりはマシではないか思っています。
是非お試しくださいませ。