JAVA 身份證校驗與統一社會信用代碼校驗

B話少說,上代碼

原理默認大家都懂了,不懂的話可以百度一下

package com.microlinktech.rns.util;

import lombok.Getter;
import lombok.NoArgsConstructor;
import org.apache.commons.lang.StringUtils;

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;

/**
 * @Description:身份證號的util
 * @Author: lcj
 * @Date: Created in 2020-06-29 15:16:15
 */
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;
        }
    }
}

用例:

IdCardUtil.IdCardInformation idCardInformation = IdCardUtil.identityCodeValid(idCard);
// 身份證校驗
if (!idCardInformation.isSuccess()) {
            // 校驗不通過處理。。。。
}
// 性別
System.out.println(idCardInformation.isSex());
// 出生日期
System.out.println(idCardInformation.getBirthday());
// 年齡
System.out.println(idCardInformation.getAge());

統一社會信用代碼:

package com.microlinktech.rns.util;

import org.apache.commons.lang.StringUtils;

import java.util.Arrays;
import java.util.List;

/**
 * @Description:統一信用代碼的util
 * @Author: lcj
 * @Date: Created in 2020-06-30 10:42:26
 */
public class UnifiedCreditCodeUtil {

    /**
     * 最後一位編碼
     */
    private static final List<String> LAST_CODE = Arrays.asList(
            "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
            "A", "B", "C", "D", "E", "F", "G", "H", "J", "K",
            "L", "M", "N", "P", "Q", "R", "T", "U", "W", "X", "Y"
    );

    /**
     * 加權因子
     */
    private static final Integer[] FACTOR = {1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28};

    public static boolean checkUnifiedCreditCode(String unifiedCreditCode) {
        unifiedCreditCode = trim(unifiedCreditCode);
        // 校驗身份證
        if (StringUtils.isBlank(unifiedCreditCode) || unifiedCreditCode.length() != 18) {
            return false;
        }
        final String upperCaseCode = unifiedCreditCode.toUpperCase();
        // 統一社會信用代碼由18位阿拉伯數字或英文大寫字母表示(不包括I,O,Z,S,V以防止和阿拉伯字母混淆)-->V:???關我毛事?
        if (upperCaseCode.contains("I") || upperCaseCode.contains("O") || upperCaseCode.contains("Z") || upperCaseCode.contains("S") || upperCaseCode.contains("V")) {
            return false;
        }
        char[] chars = upperCaseCode.toCharArray();
        int sumCode = 0;
        for (int i = 0; i < 17; i++) {
            String code = String.valueOf(chars[i]);
            int lastCodeIndex = LAST_CODE.indexOf(code);
            Integer factorNum = FACTOR[i];
            sumCode += (lastCodeIndex * factorNum);
        }
        int modCode = 31 - sumCode % 31;
        String lastCode = LAST_CODE.get(modCode % 31);
        return lastCode.equals(String.valueOf(chars[17]));
    }

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

用例:

boolean success = UnifiedCreditCodeUtil.checkUnifiedCreditCode("*****");

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章