身份证自定义校验注解validation

/**
 * 身份证号 @IdCard代码如下
 */
@Excel(name = "身份证号", orderNum = "1", width = 50)
@NotNull(message = "身份证号不能为空")
@Length(min = 18, max = 18, message = "身份证号长度有误")
@IdCard(message = "身份证格式不对")
private String idCard;
/**
 * 校验身份证号码
 * @author zhouyanhaung
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = IdCardValidator.class)
@Documented
public @interface IdCard {
 
    String message() default "";
 
    Class<?>[] groups() default {};
 
    Class<? extends Payload>[] payload() default {};
}
/**
 * @author zhouyanhuang
 * @date 2021-08-06 14:50
 * 实现注解IdCard
 */
public class IdCardValidator implements ConstraintValidator<IdCard, String> {
 
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        // 校验逻辑...
        if (value == null) {
            return true;
        }
        return IdCardUtil.identityCodeValid(value).isSuccess();
    }
}

编写身份证校验的工具类

import io.micrometer.common.util.StringUtils;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;

/**
 * @Author zhouyanhuang:
 * @Date 2023/4/24 17:06
 * @Version 1.0
 */

public class IdCardUtil {
    /**
     * 一代身份证
     */
    private static final Integer FIRST_GENERATION_ID_CARD = 15;

    /**
     * 二代身份证
     */
    private static final Integer SECOND_GENERATION_ID_CARD = 18;

    /**
     * 省编码前2位
     */
    private static final List<String> PROVINCES = Arrays.asList(
            "11", "12", "13", "14", "15",
            "21", "22", "23", "31", "32",
            "33", "34", "35", "36", "37",
            "41", "42", "43", "44", "45",
            "46", "50", "51", "52", "53",
            "54", "61", "62", "63", "64",
            "65", "71", "81", "82", "91"
    );

    /**
     * 加权因子
     */
    private static final Integer[] FACTOR = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};

    /**
     * 身份证正则
     */
    private static final String REGEX = "^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}$|^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9]|X)$";

    /**
     * 校验位
     */
    private static final String[] PARITY = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};

    /**
     * format
     */
    private static final SimpleDateFormat FORMAT = new SimpleDateFormat("yyyy-MM-dd");

    /**
     * now现在
     */
    private static final Date NOW = new Date();

    /**
     * 验证身份证是否合法
     *
     * @param idCard 身份证号码
     * @return 身份证信息对象
     */
    public static IdCardInformation identityCodeValid(String idCard) {
        final String finalIdCard = trim(idCard);
        // 校验身份证
        if (StringUtils.isBlank(finalIdCard) || finalIdCard.length() != 18) {
            return new IdCardInformation();
        }
        // 匹配正则
        if (!Pattern.compile(REGEX).matcher(finalIdCard).matches()) {
            return new IdCardInformation();
        }
        // 校验身份证前2位省编码是否正确
        if (PROVINCES.stream().noneMatch(i -> i.equals(finalIdCard.substring(0, 2)))) {
            return new IdCardInformation();
        }
        // 切割厂
        String[] code = finalIdCard.split("");
        // 拿到最后一位字母
        String lastOneCode = code[17];
        int sum = 0, ai, wi;
        // 取前17位,(每一位数字 * 每一位数字在加权因子数组的对应的数字) 之和
        for (int i = 0; i < 17; i++) {
            ai = Integer.parseInt(code[i]);
            wi = FACTOR[i];
            sum += ai * wi;
        }
        // 算出来的和 mod 11 得到 最后一位,再把传进来的身份证的最后一位和算出来的最后一位对比
        return lastOneCode.equals(PARITY[sum % 11]) ? new IdCardInformation(true, getSex(finalIdCard), getAge(finalIdCard), getBirthday(finalIdCard)) : new IdCardInformation();
    }

    /**
     * 根据身份证号获取性别
     *
     * @param idCard 身份证号码
     * @return 性别
     */
    private static boolean getSex(String idCard) {
        // 一代身份证
        if (idCard.length() == FIRST_GENERATION_ID_CARD) {
            return Integer.parseInt(idCard.substring(14, 15)) % 2 != 0;
        } else if (idCard.length() == SECOND_GENERATION_ID_CARD) {
            // 二代身份证 判断性别
            return Integer.parseInt(idCard.substring(16).substring(0, 1)) % 2 != 0;
        } else {
            return true;
        }
    }

    /**
     * 根据身份证号获取年龄
     *
     * @param idCard 身份证号码
     * @return age
     */
    private static Integer getAge(String idCard) {
        int age = 0;
        //15位身份证号
        if (idCard.length() == FIRST_GENERATION_ID_CARD) {
            // 身份证上的年份(15位身份证为1980年前的)
            String idCardYear = "19" + idCard.substring(6, 8);
            // 身份证上的月份
            String idCardMonth = idCard.substring(8, 10);
            age = getAge(idCardYear, idCardMonth);
            //18位身份证号
        } else if (idCard.length() == SECOND_GENERATION_ID_CARD) {
            // 身份证上的年份
            String idCardYear = idCard.substring(6).substring(0, 4);
            // 身份证上的月份
            String idCardMonth = idCard.substring(10).substring(0, 2);
            age = getAge(idCardYear, idCardMonth);
        }
        return age;
    }

    /**
     * 计算年月获得年龄
     *
     * @param idCardYear  身份证的上年份
     * @param idCardMonth 身份的证上月份
     * @return age
     */
    private static Integer getAge(String idCardYear, String idCardMonth) {
        // 当前年份
        String nowYear = FORMAT.format(NOW).substring(0, 4);
        // 当前月份
        String nowMonth = FORMAT.format(NOW).substring(5, 7);
        int yearDiff = Integer.parseInt(nowYear) - Integer.parseInt(idCardYear);
        if (Integer.parseInt(idCardMonth) <= Integer.parseInt(nowMonth)) {
            return yearDiff + 1;
            // 当前用户还没过生
        } else {
            return yearDiff;
        }
    }

    /**
     * 获取出生日期  yyyy年MM月dd日
     *
     * @param idCard 身份证号码
     * @return 生日
     */
    private static LocalDate getBirthday(String idCard) {
        String year = "";
        String month = "";
        String day = "";
        //15位身份证号
        if (idCard.length() == FIRST_GENERATION_ID_CARD) {
            // 身份证上的年份(15位身份证为1980年前的)
            year = "19" + idCard.substring(6, 8);
            //身份证上的月份
            month = idCard.substring(8, 10);
            //身份证上的日期
            day = idCard.substring(10, 12);
        } else if (idCard.length() == SECOND_GENERATION_ID_CARD) {
            // 18位身份证号 身份证上的年份
            year = idCard.substring(6).substring(0, 4);
            // 身份证上的月份
            month = idCard.substring(10).substring(0, 2);
            //身份证上的日期
            day = idCard.substring(12).substring(0, 2);
        }
        try {
            return LocalDate.now().withYear(Integer.parseInt(year)).withMonth(Integer.parseInt(month)).withDayOfMonth(Integer.parseInt(day));
        } catch (Exception e) {
            int start = idCard.indexOf("19");
            return LocalDate.now().withYear(Integer.parseInt(idCard.substring(start, start + 4))).withMonth(Integer.parseInt(idCard.substring(start + 4, start + 6)))
                    .withDayOfMonth(Integer.parseInt(idCard.substring(start + 6, start + 8)));
        }
    }

    /**
     * 去空格
     *
     * @param str 处理字符串
     * @return 结果字符串
     */
    private static String trim(String str) {
        return str.replaceAll("\n", "").replace(" ", "").trim();
    }

    /**
     * 身份证信息
     */
    @Getter
    @NoArgsConstructor
    public static class IdCardInformation {

        /**
         * 是否成功
         */
        private boolean success = false;

        /**
         * 性别
         */
        private boolean sex;

        /**
         * 年龄
         */
        private Integer age;

        /**
         * 生日
         */
        private LocalDate birthday;

        public IdCardInformation(boolean success, boolean sex, Integer age, LocalDate birthday) {
            this.success = success;
            this.sex = sex;
            this.age = age;
            this.birthday = birthday;
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,您可以使用Java中的自定义注解来实现这一功能。以下是一个示例代码,您可以根据您的需求进行修改: ``` @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface MyValidation { int[] validValues(); // 定义需要校验的值 boolean notEmpty() default false; // 定义是否需要校验非空 String message() default "Validation failed!"; // 定义校验失败时的提示信息 } ``` 在这个示例中,我们定义了一个名为MyValidation注解,该注解包含三个属性:validValues、notEmpty和message。其中,validValues表示需要校验的值,notEmpty表示是否需要校验非空,message表示校验失败时的提示信息。 接下来,您可以在需要进行校验的变量上添加该注解,例如: ``` public class MyClass { @MyValidation(validValues = {1, 2}, notEmpty = true, message = "Validation failed for a or b!") private int a; @MyValidation(validValues = {1, 2}, notEmpty = true, message = "Validation failed for a or b!") private String b; // 省略其他代码 } ``` 在这个示例中,我们在变量a和b上添加了MyValidation注解,并设置了相应的属性。当需要对这些变量进行校验时,您可以使用反射来获取这些注解,并根据注解定义的规则进行校验。例如: ``` public static void validateObject(Object obj) throws Exception { Class<?> clazz = obj.getClass(); for (Field field : clazz.getDeclaredFields()) { if (field.isAnnotationPresent(MyValidation.class)) { MyValidation validation = field.getAnnotation(MyValidation.class); field.setAccessible(true); Object value = field.get(obj); if (value == null) { throw new Exception("Validation failed: " + field.getName() + " is null!"); } if (validation.notEmpty() && value instanceof String && ((String) value).isEmpty()) { throw new Exception("Validation failed: " + field.getName() + " is empty!"); } boolean valid = false; for (int validValue : validation.validValues()) { if (value instanceof Integer && ((Integer) value).intValue() == validValue) { valid = true; break; } } if (!valid) { throw new Exception("Validation failed: " + field.getName() + " is invalid!"); } } } } ``` 在这个示例中,我们定义了一个validateObject方法,该方法接收一个Object类型的参数,并使用反射来获取该对象中所有带有MyValidation注解的变量。然后,根据注解定义的规则进行校验,如果校验失败,则抛出一个异常。 您可以根据您的实际需求进行修改和扩展。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值