はじめに
Spring Bootを使用して、フォームの値をバリデーションしたい。ただ、単一の項目ではなく、
複数の条件を指定した相関バリデーションを行いたい場合の実装を、自作アノテーションを
用いて対応したので、その備忘録を下記に残す。
今回やりたい例
あるフォーム画面にて、Aは入力していて、かつBは未入力の場合をバリデーションする。
環境
- Java11
実装例
formクラスを作成する
testForm.java
@Setter
@Getter
@TestValidation(targetA= "targetAName", targetBName= "targetB")
public class ProfileForm {
private String targetA;
private String targetB;
- Lombokを使用しているため、
@Setter/@Getter
を付与 -
@testValidation(targetA= "targetA", targetB= "targetB")`
- @testValidation:後記するInterface名
- (targetAName= "targetA", targetBName= "targetB"):左辺がformのname属性で右辺がフィールド名
独自アノテーション用のインタフェースを作成する
TestValidation.Java
@Documented
@Constraint(validatedBy = {TestValidator.class})
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@ReportAsSingleViolation
public @interface TestValidation{
String message() default "エラーメッセージ";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String targetA();
String targetB();
}
-
@Constraint(validatedBy = {TestValidator.class})
- 後記するバリデーションの実装クラス名
作成したアノテーションの実装クラスを作成する
TestValidator.java
public class TestValidator implements ConstraintValidator<TestValidation, Object> {
private String targetA;
private String targetB;
private String message;
@Override
public void initialize(TestValidation constraintAnnotation) {
this.targetA = constraintAnnotation.targetA();
this.targetB = constraintAnnotation.targetB();
this.message = constraintAnnotation.message();
}
@Override
public boolean isValid(Object form, ConstraintValidatorContext constraintValidatorContext) {
if (Objects.isNull(form)) {
return true;
}
// formから対象項目を取得
BeanWrapper beanWrapper = new BeanWrapperImpl(form);
String testTargetA = (String) beanWrapper.getPropertyValue(this.targetA);
String testTargetB = (String) beanWrapper.getPropertyValue(this.targetB);
if (StringUtils.isNotEmpty(testTargetA) && StringUtils.isEmpty(testTargetB)) {
constraintValidatorContext.disableDefaultConstraintViolation();
constraintValidatorContext
.buildConstraintViolationWithTemplate(this.message)
.addPropertyNode(this.testTargetB).addConstraintViolation();
return false;
}
return true;
}
-
ConstraintValidator<TestValidation, Object>
- 第一引数には、先ほど作成したInterface名を記述
- 第二引数には、formが渡されるのでObject型を指定
-
BeanWrapper beanWrapper = new BeanWrapperImpl(form);
- 上記記述で、formから欲しい値を取得
以上。
走り書きなので、追記するかもしれないです。
参考URL