上回我们说到spring boot的@validated注解结合@ControllerAdvice实现统一参数校验,末尾我们抛出一个问题,就是@Validated内置的校验注解并不能满足所有的情况,今天我们就来说说这种情况该怎么解决,我们总不能一边用注解一边还手写if、else吧,bi格一下就降下来了,我们写漂亮的代码,不就是为了让人看嘛。所以针对这个我们,我们就用自定义注解来解决。
一、自定义注解(以身份证校验举例)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE ,ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER })
@Inherited
@Documented
@Constraint(validatedBy = IdCardValidator.class)
public @interface IDCARD {
String message() default "身份证不正确,请核对后重新填写";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
@Retention :用来说明该注解类的生命周期。它有以下三个参数:
RetentionPolicy.SOURCE : 注解只保留在源文件中
RetentionPolicy.CLASS : 注解保留在class文件中,在加载到JVM虚拟机时丢弃
RetentionPolicy.RUNTIME : 注解保留在程序运行期间,此时可以通过反射获得定义在某个类上的所有注解。
@Target : 用来说明该注解可以被声明在那些元素之前。
ElementType.TYPE:说明该注解只能被声明在一个类前。
ElementType.FIELD:说明该注解只能被声明在一个类的字段前。
ElementType.METHOD:说明该注解只能被声明在一个类的方法前。
ElementType.PARAMETER:说明该注解只能被声明在一个方法参数前。
ElementType.CONSTRUCTOR:说明该注解只能声明在一个类的构造方法前。
ElementType.LOCAL_VARIABLE:说明该注解只能声明在一个局部变量前。
ElementType.ANNOTATION_TYPE:说明该注解只能声明在一个注解类型前。
ElementType.PACKAGE:说明该注解只能声明在一个包名前。
@Constraint来指定自定义注解的实现接口
二、编写实现类
public class IdCardValidator implements ConstraintValidator<IDCARD, String> {
@Override
public boolean isValid(String cardNo, ConstraintValidatorContext context) {
if (StringUtils.isEmpty(cardNo)) {
return true;
}
if (null != cardNo && cardNo.trim().length() == 15) {
cardNo = cardNo.trim();
StringBuffer sb = new StringBuffer(cardNo);
sb.insert(6, "19");
sb.append(transCardLastNo(sb.toString()));
cardNo = sb.toString();
}
//18位身份证 正则表达
try {
IsValidldCardInterface isValidld = new IsValidIdCardImpl();
String result = isValidld.isValidldCard(cardNo);
if ("".equals(result)) {
return true;
}
} catch (Exception e) {
return false;
}
return false;
}
/**
* @author ken chen
* <p>Title: transCardLastNo</p>
* <p>Description: 15 转换 18身份证补位运算 </p>
*/
private Object transCardLastNo(String newCardId) {
char[] ch = newCardId.toCharArray();
int m = 0;
int[] co = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
char[] verCode = new char[]{'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
for (int i = 0; i < newCardId.length(); i++) {
m += (ch[i] - '0') * co[i];
}
int residue = m % 11;
return String.valueOf(verCode[residue]);
}
@Override
public void initialize(IDCARD constraintAnnotation) {
}
}
注意上面实现类集实现了ConstraintValidator<IDCARD, String>接口,IDCARD是自定义的注解,String是要简要的参数类型。
围绕着@Validated注解我们能讲的就讲完了,写代码不就是越简洁越好吗,其实基于注解我们能玩出好多花来,比如接口幂等,统一权限,统一日志等等,我们以后再来慢慢展开。