All Downloads are FREE. Search and download functionalities are using the official Maven repository.

club.zhcs.lina.web.jsr380.validator.IdcardUtils Maven / Gradle / Ivy

The newest version!
package club.zhcs.lina.web.jsr380.validator;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Optional;
import java.util.regex.Pattern;

import org.nutz.lang.Strings;
import org.nutz.lang.Times;
import org.nutz.log.Log;
import org.nutz.log.Logs;

import lombok.experimental.UtilityClass;

/**
 * 
 * @author Kerbores([email protected])
 *
 */
@UtilityClass
public class IdcardUtils {

    /**
     ** 省,直辖市代码表: { 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:"国外"}
     */
    protected static String[][] codeAndCity = {{"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 String[] cityCode = {"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 int[] power = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};

    private static Log logger = Logs.get();

    public static boolean isValidatedAllIdcard(String idcard) {
        if (idcard.length() == 15) {
            idcard = convertIdcarBy15bit(idcard);
        }
        return isValidate18Idcard(Optional.ofNullable(idcard).orElse(""));
    }

    public static boolean isValidate18Idcard(String idcard) {
        // 非18位为假
        if (idcard.length() != 18) {
            return false;
        }
        // 获取前17位
        String idcard17 = idcard.substring(0, 17);
        // 获取第18位
        String idcard18Code = idcard.substring(17, 18);
        char[] c = null;
        String checkCode = "";
        // 是否都为数字
        if (isDigital(idcard17)) {
            c = idcard17.toCharArray();
        } else {
            return false;
        }

        if (null != c) {
            int[] bit = converCharToInt(c);
            int sum17 = 0;
            sum17 = getPowerSum(bit);

            // 将和值与11取模得到余数进行校验码判断
            checkCode = getCheckCodeBySum(sum17);
            if (null == checkCode) {
                return false;
            }
            // 将身份证的第18位与算出来的校码进行匹配,不相等就为假
            if (!idcard18Code.equalsIgnoreCase(checkCode)) {
                return false;
            }
        }
        return true;
    }

    public static boolean isValidate15Idcard(String idcard) {
        if (idcard.length() == 15 && isDigital(idcard)) {
            String provinceid = idcard.substring(0, 2);
            String birthday = idcard.substring(6, 12);
            int year = Integer.parseInt(idcard.substring(6, 8));
            int month = Integer.parseInt(idcard.substring(8, 10));
            int day = Integer.parseInt(idcard.substring(10, 12));
            Date birthdate;
            try {
                birthdate = Times.parse("yyMMdd", birthday);
            }
            catch (ParseException e) {
                logger.debug(e);
                return false;
            }
            // 判断是否为合法的省份
            if (!isProvinceAv(provinceid)) {
                return false;
            }
            if (!isBirthDayAv(birthdate)) {
                return false;
            }
            // 该身份证生出日期在当前日期之后时为假

            // 判断是否为合法的年份
            GregorianCalendar curDay = new GregorianCalendar();
            // 判断是否为合法的日期
            return isYearAndMonthAv(year, month, curDay) && isDayAv(month, day, birthdate, curDay);
        }
        return false;
    }

    /**
     * @param year
     * @param month
     * @param curDay
     */
    private static boolean isYearAndMonthAv(int year, int month, GregorianCalendar curDay) {
        int curYear = curDay.get(Calendar.YEAR);
        int year2bit = Integer.parseInt(String.valueOf(curYear)
                                              .substring(2));

        // 判断该年份的两位表示法,小于50的和大于当前年份的,为假
        if ((year < 50 && year > year2bit)) {
            return false;
        }
        // 判断是否为合法的月份
        return month >= 1 && month <= 12;
    }

    /**
     * @param month
     * @param day
     * @param birthdate
     * @param curDay
     * @return
     */
    private static boolean isDayAv(int month, int day, Date birthdate, GregorianCalendar curDay) {
        boolean mflag;
        curDay.setTime(birthdate); // 将该身份证的出生日期赋于对象curDay
        if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
            mflag = (day >= 1 && day <= 31);
        } else if (month == 4 || month == 6 || month == 9 || month == 11) {
            mflag = (day >= 1 && day <= 30);
        } else {
            if (curDay.isLeapYear(curDay.get(Calendar.YEAR))) {
                mflag = (day >= 1 && day <= 29);
            } else {
                mflag = (day >= 1 && day <= 28);
            }
        }
        return mflag;
    }

    /**
     * @param birthday
     * @return
     */
    private static boolean isBirthDayAv(Date birthday) {
        return birthday != null && birthday.before(Times.now());
    }

    /**
     * @param provinceid
     * @param flag
     * @return
     */
    private static boolean isProvinceAv(String provinceid) {
        for (String id : cityCode) {
            if (id.equals(provinceid)) {
                return true;
            }
        }
        return false;
    }

    public static String convertIdcarBy15bit(String idcard) {
        String idcard17 = null;
        // 非15位身份证
        if (idcard.length() != 15) {
            return null;
        }

        if (isDigital(idcard)) {
            // 获取出生年月日
            String birthday = idcard.substring(6, 12);
            Date birthdate = null;
            try {
                birthdate = new SimpleDateFormat("yyMMdd").parse(birthday);
            }
            catch (ParseException e) {
                logger.debug(e);
                return null;
            }
            Calendar cday = Calendar.getInstance();
            cday.setTime(birthdate);
            String year = String.valueOf(cday.get(Calendar.YEAR));

            idcard17 = idcard.substring(0, 6) + year + idcard.substring(8);

            char[] c = idcard17.toCharArray();
            String checkCode = "";

            if (null != c) {
                int[] bit = converCharToInt(c);
                int sum17 = 0;
                sum17 = getPowerSum(bit);
                // 获取和值与11取模得到余数进行校验码
                checkCode = getCheckCodeBySum(sum17);
                // 获取不到校验位
                if (null == checkCode) {
                    return null;
                }

                // 将前17位与第18位校验码拼接
                idcard17 += checkCode;
            }
        } else { // 身份证包含数字
            return null;
        }
        return idcard17;
    }

    public static boolean isIdcard(String idcard) {
        return !Strings.isBlank(idcard)
               && Pattern.matches(
                                  "(^\\d{15}$)|(\\d{17}(?:\\d|x|X)$)",
                                  idcard);
    }

    public static boolean is15Idcard(String idcard) {
        return !Strings.isBlank(idcard)
               && Pattern.matches(
                                  "^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}$",
                                  idcard);
    }

    public static boolean is18Idcard(String idcard) {
        return Pattern
                      .matches(
                               "^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([\\d|x|X]{1})$",
                               idcard);
    }

    public static boolean isDigital(String str) {
        return !Strings.isBlank(str) && str.matches("^[0-9]*$");
    }

    public static int getPowerSum(int[] bit) {
        int sum = 0;
        if (power.length != bit.length) {
            return sum;
        }
        for (int i = 0; i < bit.length; i++) {
            for (int j = 0; j < power.length; j++) {
                if (i == j) {
                    sum = sum + bit[i] * power[j];
                }
            }
        }
        return sum;
    }

    public static String getCheckCodeBySum(int sum17) {
        String checkCode = null;
        switch (sum17 % 11) {
        case 10:
            checkCode = "2";
            break;
        case 9:
            checkCode = "3";
            break;
        case 8:
            checkCode = "4";
            break;
        case 7:
            checkCode = "5";
            break;
        case 6:
            checkCode = "6";
            break;
        case 5:
            checkCode = "7";
            break;
        case 4:
            checkCode = "8";
            break;
        case 3:
            checkCode = "9";
            break;
        case 2:
            checkCode = "x";
            break;
        case 1:
            checkCode = "0";
            break;
        case 0:
            checkCode = "1";
            break;
        default:
            break;
        }
        return checkCode;
    }

    public static int[] converCharToInt(char[] c) {
        int[] a = new int[c.length];
        int k = 0;
        for (char temp : c) {
            a[k++] = Integer.parseInt(String.valueOf(temp));
        }
        return a;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy