目标
自定义一个用于校验 身份证号码
格式的注解@IdCard
,能够和现有的 Validation
兼容,使用方式和其他校验注解保持一致(使用 @Valid
注解接口参数)。
校验逻辑
有效格式
符合国家标准。
公民身份号码按照GB11643-1999《公民身份号码》国家标准编制,由18位数字组成:前6位为行政区划代码,第7至14位为出生日期码,第15至17位为顺序码,第18位为校验码。
不校验非空
身份证号码注解,校验的是格式
;不校验是否为空(null 或 空字符串)。如果身份证号码为空,此注解校验是可以通过的;
校验非空,使用注解 @NotEmpty
;根据业务逻辑来确定,身份证号码是否需要判断非空。
校验格式的工具:Hutool
使用Hutool
提供的身份证格式校验方法。
注意,Hutool 校验身份证格式,忽略X的大小写
;也就是,大小写的X,都认为表达的是罗马数字十
。
依赖
- Validation
- Hutool
Validation:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Hutool:
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
核心代码
需要自定义的内容,包含两个部分:
- 注解
@IdCard
- 校验器
IdCardValidator
注解:@IdCard
package com.example.core.validation.idcard;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 身份证号码。字符串必须是格式正确的身份证号码。
* <p>
* {@code null} 或 空字符串,是有效的(能够通过校验)。
* <p>
* 支持的类型:字符串
*
* @author songguanxun
* @since 1.0
*/
@Target({FIELD})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = IdCardValidator.class)
public @interface IdCard {
/**
* @return the error message template
*/
String message() default "身份证号码,格式错误";
/**
* @return the groups the constraint belongs to
*/
Class<?>[] groups() default {};
/**
* @return the payload associated to the constraint
*/
Class<? extends Payload>[] payload() default {};
}
校验器:IdCardValidator
package com.example.core.validation.idcard;
import cn.hutool.core.util.IdcardUtil;
import com.example.core.validation.ResetMessageUtil;
import org.springframework.util.ObjectUtils;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
* 身份证号码,格式校验器
*/
public class IdCardValidator implements ConstraintValidator<IdCard, String> {
@Override
public void initialize(IdCard constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation);
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (ObjectUtils.isEmpty(value)) {
return true;
}
if (value.contains(" ")) {
ResetMessageUtil.reset(context, "身份证号码,格式错误:不能包含空格");
return false;
}
return IdcardUtil.isValidCard(value);
}
}
使用
@IdCard
放在需要校验格式的 身份证号码
字段上。
package com.example.web.response.model.param;
import com.example.core.validation.idcard.IdCard;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(name = "新增用户Param")
public class UserAddParam {
// 其他字段
@IdCard
@Schema(description = "身份证号码", example = "110101202301024130")
private String idCard;
}
补充代码
ResetMessageUtil:重置提示信息工具类
package com.example.core.validation;
import javax.validation.ConstraintValidatorContext;
/**
* 参数校验 - 重置提示信息工具类
*/
public class ResetMessageUtil {
/**
* 重置提示信息
*/
public static void reset(ConstraintValidatorContext context, String message) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
}
}
校验效果
校验工具类(Hutool),测试
对Hutool提供的身份证校验方法,进行测试。
package com.example;
import cn.hutool.core.util.IdcardUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
/**
* 身份证号码校验测试(使用Hutool)
*/
@Slf4j
public class IdCardHutoolTest {
@Test
void test() {
test("110101202301024130");
test("11010120230102857X");
test("11010120230102857x");
test("110101202301024130啊啊啊啊");
}
private void test(String idCard) {
boolean validCard = IdcardUtil.isValidCard(idCard);
log.info("是否为身份证号码格式:{} = {}", idCard, validCard);
}
}
能够正确校验身份证格式。
接口测试
校验结果为 成功