Springで独自のバリデータを作成する
相関チェック用のバリデータの作成方法について。
Springには相関チェック用のバリデータが用意されていないため、自分で独自のバリデータを作成する必要があります。
環境
- Spring Boot: 2.3.3.RELEASE
作成方法
今回は属性に指定されたフィールドのうちどれか1つでも入力されていればOKとみなす@NotAllBlank
というアノテーションを作成しました。
ソースコードの内容はほぼ参考書の通りです。
以下に記載するソースコード内で番号付きのコメントの部分以外はコピペで動作可能でした。
アノテーション作成
@Documented
@Constraint(validatedBy = {NotAllBlankValidator.class}) // ①
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface NotAllBlank {
String message() default "{xyz.tenohira.magazinemanager.validation.NotAllBlank.message}"; // ②
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
// ③バリデータの属性定義
String[] fields();
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface List {
NotAllBlank[] value(); // ④
}
}
① @Constraint(validatedBy = {NotAllBlankValidator.class})
@Constraint
のvalidatedBy
属性にバリデータの実装クラスを指定します。
② String message() default "{xyz.tenohira.magazinemanager.validation.NotAllBlank.message}"
デフォルトメッセージを指定します。
ここで指定したxyz.tenohira.magazinemanager.validation.NotAllBlank.message
の内容は後述するValidationMessages.properties
に記載します。
③ バリデータの属性定義
アノテーションに指定できる属性をここで定義します。
④ NotAllBlank[] value();
属性で指定された値を格納する変数を用意します。(と解釈しました)
バリデータの作成
public class NotAllBlankValidator implements ConstraintValidator<NotAllBlank, Object> { // ①
// ②
private String[] fields;
private String message;
// ③バリデータ初期化
public void initialize(NotAllBlank constraintAnnotation) {
this.fields = constraintAnnotation.fields();
this.message = constraintAnnotation.message();
}
// ④検証処理
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
BeanWrapper beanWrapper = new BeanWrapperImpl(value);
for (String string : fields) {
Object fieldValue = beanWrapper.getPropertyValue(string);
if (StringUtils.hasText(fieldValue.toString())) {
return true;
}
}
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(message)
.addPropertyNode(fields[0]).addConstraintViolation();
return false;
}
}
① ConstraintValidator
インターフェースの実装
型パラメータの第一引数に、作成したアノテーション名を指定します。
② 変数
アノテーションの属性名とメッセージを変数として定義します。
③ バリデータ初期化
バリデータで使用する変数を初期化します。
④ 検証処理の実装
検証の内容を記述します。
BeanWrapper.getPropertyValue(属性名の変数)
により、属性に指定した値を取得できます。
この例では1つでも空でないフィールドがあればtrueを返すようにしています。
検証結果がfalseとなる場合(この例では全てのフィールドが空だった場合)、下記のようにエラーメッセージとフィールドを紐づけます。
context.buildConstraintViolationWithTemplate(message).addPropertyNode(fields[0]).addConstraintViolation();
エラーメッセージ定義
ValidationMessages.properties
をsrc/main/resources
直下に作成します。
以下のようにメッセージを定義します。
xyz.tenohira.magazinemanager.validation.NotAllBlank.message={fields}のどれか1つは入力必須です。
使用方法
以下のように使用します。
@Data
@NotAllBlank(fields = {"section", "title"})
public class Article {
/** セクション */
@Length(max = 30)
private String section;
/** タイトル */
@Length(max = 50)
private String title;
// 省略
}
2つ以上のフィールドにまたがるバリデータのため、クラスにアノテーションを付けます。
fields属性にチェックを行いたいフィールドを指定します。
参考
- Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発
- 5.7.6 入力チェックルールの追加(225~228ページ)
- 5.7.9 エラーメッセージの解決(231~235ページ)