Spring 基于自定义条件的验证

Spring custom condition based validation

我想在 spring 验证器中创建基于条件的验证。 我有一个 UserDTO class 因为有两个 DTO class 带有 @Valid 注释。

如果我传递 isPrimary true 那么它应该只验证 primaryDTO bean 并忽略 secendoryDTO 验证。

public class UserDTO {
    @Valid
    private PrimaryDTO primaryDTO;
    @Valid
    private SecendoryDTO secendoryDTO;
    private boolean isPrimary;
}

public class PrimaryDTO {
    @NotEmpty(message = "Please enter email.")
    @Email(message = "Please enter a valid email.")
    private String email;
}

public class SecendoryDTO {
    @NotEmpty(message = "Please enter phone.")
    private String phone;
}

请指导。

谢谢

如果您的验证依赖于多个字段(例如 isPrimaryprimaryDTOsecondaryDTO),那么唯一的解决方案是在类级别编写自定义验证程序(UserDTO) 它将自己实现条件验证。

例如创建注解:

@Documented
@Retention(RUNTIME)
@Target({ANNOTATION_TYPE, TYPE})
@Constraint(validatedBy = SecondaryValidator.class)
public @interface ValidSecondary {
    String message() default "Invalid secondary";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

并创建一个验证器,仅在 isPrimary()false 时验证 secondaryDTO 字段:

@Component
public class SecondaryValidator implements ConstraintValidator<ValidSecondary, UserDTO> {
    private Validator validator;

    public SecondaryValidator(Validator validator) {
        this.validator = validator;
    }

    @Override
    public boolean isValid(UserDTO userDTO, ConstraintValidatorContext constraintValidatorContext) {
        if (userDTO.isPrimary()) {
            return true;
        } else {
            return validator.validate(userDTO.getSecondaryDTO()).isEmpty();
        }
    }
}

之后,您可以从 secondaryDTO 字段中删除 @Valid 注释,并在 UserDTO:

顶部添加 @ValidSecondary 注释
@ValidSecondary // Add this
public class UserDTO {
    @Valid
    private PrimaryDTO primaryDTO;
    private SecondaryDTO secondaryDTO; // No more @Valid
    private boolean primary;
}

但是,在这种情况下,您将丢失来自 SecondaryDTO 中的任何约束违规消息,如果您想要某种传递机制,您可以将违规添加到 constraintValidatorContextisValid() 方法中,例如:

Set<ConstraintViolation<SecondaryDTO>> violations = validator.validate(userDTO.getSecondaryDTO());
violations.forEach(violation -> constraintValidatorContext
    .buildConstraintViolationWithTemplate(violation.getMessage())
    .addConstraintViolation());