项目中有些参数对象的校验要求千奇百怪。
例如:复合、联合、级联、二次校验。
为了省事儿,写了一个接口实现类的校验器
一、注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Constraint(validatedBy = CustomValidator.class)
public @interface CustomValid {
String message() default "custom valid fail";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
二、自定义校验接口
public interface CustomCheck {
/**
* 自定义校验 抛出参数异常
* @return 空白值 则代表无异常
*/
String validSelf();
}
三、自定义校验器
@Slf4j
public class CustomValidator implements ConstraintValidator<CustomValid, CustomCheck> {
@Override
public boolean isValid(CustomCheck customCheck, ConstraintValidatorContext context) {
String message;
try {
message = customCheck.validSelf();
}catch (Exception e){
log.error("校验器校验过程异常:",e);
throw new BaseException(e.getMessage());
}
if (StringUtils.isBlank(message)) {
// 空白返回值则代表正常
return true;
}
// 设置异常消息
context.buildConstraintViolationWithTemplate(message)
.addConstraintViolation();
return false;
}
}
四、使用方式
@Data
@CustomValid
public class EnvlopReqDTO implements CustomCheck {
/**
* 原文
* */
private String plaintext;
/**
* 证书 (外部证书加密使用)
* */
private String cert;
/**
* 内部证书标识
* */
private String certId;
/**
* 数字信封中对称加密算法
* */
@EnumValid(message="algType 证书可选加密算法不在正确枚举中" ,value = EncryptAlgTypeEnum.class, groups = AddGroup.class)
private String algType;
/**
* 密文
* */
private String ciphertext;
/**
* 验证证书相关选项
* */
private VerifyCertOpt verifyCertOpt;
@Override
public String validSelf() {
if (StringUtils.isEmpty(plaintext)) {
return "加密参数不能为空";
}
if (StringUtils.isEmpty(cert) && StringUtils.isEmpty(certId)) {
return "加密证书及证书标识不能都为空";
}
return null;
}
}
五、其它事项
1、被注释的DTO必须实现 “ 接口”。
2、接口返回值不为Blank则校验失败并响应 “ 异常信息 ”。
3、DTO内部使用其它校验注解互不影响。
4、支持分组参数 “ groups = “xxx.class” ”。
5、如果校验不生效,检查一下Controller是否添加@Validated,或者分组参数groups 和注释是否合适。