一、步骤
1.创建自定义注解 IdCard
- @Constraint指定校验类。
- 除了自定义的message、require属性外,下面的groups和payload也是必须添加的。
/**
* 用于校验身份证的注解
*/
@Target({ElementType.METHOD,ElementType.FIELD,ElementType.ANNOTATION_TYPE,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = IdCardValidator.class)//指定校验类
public @interface IdCard {
boolean required() default true;
String message() default "身份证格式错误";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
2.创建注解校验类 IdCardValidator
校验类需要实现ConstraintValidator接口。
接口使用了泛型,需要指定两个参数,第一个自定义注解类,第二个为需要校验的数据类型。
实现接口后要override两个方法,分别为initialize方法和isValid方法。其中initialize为初始化方法,可以在里面做一些初始化操作,isValid方法就是我们最终需要的校验方法,可以在该方法中实现具体的校验步骤。本示例中进行了身份证校验。
public class IdCardValidator implements ConstraintValidator<IdCard,String> {
private boolean required = false;
@Override
public void initialize(IdCard constraintAnnotation) {
required = constraintAnnotation.required();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
if (required){
return IdentityCardNumberUtil.isValaid(value);
}else{
if (StringUtil.isEmpty(value)){
return true;
}else {
return IdentityCardNumberUtil.isValaid(value);
}
}
}
}
3.创建用户实体类 User
- 在IdCard属性添加了自定义注解
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private static final long serialVersionUID = -53183535344760589L;
private String id;
private String name;
@IdCard
private String IdCard;
}
4.创建全局异常捕获类 GlobalExceptionHandler
- 在valid校验中,如果校验不通过,会产生BindException异常,这边进行全局异常捕获
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 系统内部异常
*
* @param e Exception
* @return Result
*/
@ExceptionHandler(value = Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String handleException(Exception e) {
log.error("系统内部异常,异常信息:", e);
return "系统异常,请联系管理人员";
}
/**
* BindException
*
* @param e BindException
* @return Result
*/
@ExceptionHandler(value = BindException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String BindException(Exception e) {
log.error("身份证校验异常:", e);
return "身份证校验失败";
}
}
5.创建工具类utils
//身份证utils
public final class IdentityCardNumberUtil {
private IdentityCardNumberUtil() {
}
public static boolean isValaid(String idNumber) {
if (StringUtil.isEmpty(idNumber)) {
return false;
} else {
boolean matches = idNumber.matches("\\d{6}(19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]");
if (!matches) {
return false;
} else {
String verifyCode = getVerifyCode(idNumber).toLowerCase();
return verifyCode.equals(idNumber.substring(idNumber.length() - 1).toLowerCase());
}
}
}
private static String getVerifyCode(String idNumber) {
int sum = 0;
for(int i = 0; i < 17; ++i) {
int k = (int)Math.pow(2.0D, (double)(17 - i));
byte weight = (byte)(k % 11);
sum += Integer.parseInt(idNumber.substring(i, i + 1)) * weight;
}
byte mode = (byte)(sum % 11);
return "10X98765432".substring(mode, mode + 1);
}
}
//字符串utils
public final class StringUtil {
private StringUtil() {
}
public static boolean isEmpty(String str) {
return str == null || str.length() == 0;
}
}
6.编写测试类
- 加上@Valid注解开启valid校验。
@RestController
public class TestController {
@GetMapping("/valid")
public String isValid(@Valid User user){
return "校验成功";
}
}
7.执行结果
- 输入正确的身份证号码,返回检验成功
- 输入错误的身份证号码,返回身份证校验失败