大陆居民身份证验证方法(java)

1、设置接口

@Constraint(validatedBy = ChineseIdNumberValidator.class)
@Target({ElementType.METHOD,
         ElementType.FIELD,
         ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IdNumber {

    String message() default "{common.IdNumber.Pattern}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

2、编写Validator

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.validation.ConstraintValidatorContext;

/**
 *
 * <p>
 * 判断18位身份证的合法性
 * </p>
 * 根据〖中华人民共和国国家标准GB11643-1999〗中有关公民身份号码的规定,公民身份号码是特征组合码,由十七位数字本体码和一位数字校验码组成。
 * 排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。
 * <p>
 * 顺序码: 表示在同一地址码所标识的区域范围内,对同年、同月、同 日出生的人编定的顺序号,顺序码的奇数分配给男性,偶数分配 给女性。
 * </p>
 * <p>
 * 1.前1、2位数字表示:所在省份的代码; 2.第3、4位数字表示:所在城市的代码; 3.第5、6位数字表示:所在区县的代码;
 * 4.第7~14位数字表示:出生年、月、日; 5.第15、16位数字表示:所在地的派出所的代码; 6.第17位数字表示性别:奇数表示男性,偶数表示女性;
 * 7.第18位数字是校检码:也有的说是个人信息码,一般是随计算机的随机产生,用来检验身份证的正确性。校检码可以是0~9的数字,有时也用x表示。
 * </p>
 * <p>
 * 第十八位数字(校验码)的计算方法为: 1.将前面的身份证号码17位数分别乘以不同的系数。从第一位到第十七位的系数分别为:7 9 10 5 8 4 2 1
 * 6 3 7 9 10 5 8 4 2
 * </p>
 * <p>
 * 2.将这17位数字和系数相乘的结果相加。
 * </p>
 * <p>
 * 3.用加出来和除以11,看余数是多少?
 * </p>
 * 4.余数只可能有0 1 2 3 4 5 6 7 8 9 10这11个数字。其分别对应的最后一位身份证的号码为1 0 X 9 8 7 6 5 4 3 2。
 * <p>
 * 5.通过上面得知如果余数是2,就会在身份证的第18位数字上出现罗马数字的Ⅹ。如果余数是10,身份证的最后一位号码就是2。
 * </p>
 *
 * <p>
 * 对于15位身份证,不需要判断最后一位验证码,最后一位代表性别,奇数表示男性,偶数表示女性 默认使用18位身份证号,15位也支持
 * </p>
 *
 * @author rooseek
 *
 *
 */
public class ChineseIdNumberValidator implements ConstraintValidator {

    private final static Map<String, String> code2Province = new HashMap<String, String>() {

        private static final long serialVersionUID = 1L;

        {
            this.put("11", "北京");
            this.put("12", "天津");
            this.put("13", "河北");
            this.put("14", "山西");
            this.put("15", "内蒙古");
            this.put("21", "辽宁");
            this.put("22", "吉林");
            this.put("23", "黑龙江");
            this.put("31", "上海");
            this.put("32", "江苏");
            this.put("33", "浙江");
            this.put("34", "安徽");
            this.put("35", "福建");
            this.put("36", "江西");
            this.put("37", "山东");
            this.put("41", "河南");
            this.put("42", "湖北");
            this.put("43", "湖南");
            this.put("44", "广东");
            this.put("45", "广西");
            this.put("46", "海南");
            this.put("50", "重庆");
            this.put("51", "四川");
            this.put("52", "贵州");
            this.put("53", "云南");
            this.put("54", "西藏");
            this.put("61", "陕西");
            this.put("62", "甘肃");
            this.put("63", "青海");
            this.put("64", "宁夏");
            this.put("65", "新疆");
        }
    };

    private static final int weightFactor[] = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};

    private static final String checkCode[] = {"1", "0", "X", "9", "8", "7", "6", "5",
                                               "4", "3", "2"};

    private static final GregorianCalendar calendar = (GregorianCalendar) GregorianCalendar.getInstance();

    @Override
    public void initialize(IdNumber constraintAnnotation) {
    }

    @Override
    public boolean isValid(String idNumber, ConstraintValidatorContext context) {
        if (idNumber == null) {
            return true;
        }

        return isValid(idNumber);
    }

    protected boolean isValid(String idNumber) {
        if (idNumber == null) {
            return true;
        }

        if (idNumber.length() == 15) {
            return isValid15(idNumber);
        } else if (idNumber.length() == 18) {
            return isValid18(idNumber);
        }

        return false;
    }

    private boolean isValid15(String idNumber) {
        if (idNumber == null || idNumber.length() != 15) {
            return false;
        }

        if (!isDigital(idNumber)) {
            return false;
        }

        //check province code
        String province = idNumber.substring(0, 2);
        if (!code2Province.containsKey(province)) {
            return false;
        }

        //check birthday
        String birthday = idNumber.substring(6, 12);
        int month = Integer.parseInt(idNumber.substring(8, 10));
        int day = Integer.parseInt(idNumber.substring(10, 12));

        //check birthday format and whether this date is before current time
        Date birthDate = null;
        try {
            birthDate = new SimpleDateFormat("yyMMdd").parse(birthday);
        } catch (ParseException ex) {
            Logger.getLogger(ChineseIdNumberValidator.class.getName()).log(Level.SEVERE, null, ex);
        }
        if (birthDate == null || System.currentTimeMillis() <= birthDate.getTime()) {
            return false;
        }

        //check year, month, day
        calendar.setTime(birthDate);
        if (calendar.get(Calendar.YEAR) < IdNumberConstant.MIN_YEAR) {
            return false;
        }

        if (month < 1 || month > 12) {
            return false;
        }
        switch (month) {
            case 1:
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
            case 12:
                if (day < 1 || day > 31) {
                    return false;
                }
            case 4:
            case 6:
            case 9:
            case 11:
                if (day < 1 || day > 30) {
                    return false;
                }
            case 2:
                if (calendar.isLeapYear(calendar.get(Calendar.YEAR))) {
                    if (day < 1 || day > 29) {
                        return false;
                    }
                } else {
                    if (day < 1 || day > 28) {
                        return false;
                    }
                }
        }

        return true;
    }

    private boolean isValid18(String idNumber) {
        if (idNumber == null || idNumber.length() != 18) {
            return false;
        }

        String idNumber17 = idNumber.substring(0, 17);
        String idNumber18Code = idNumber.substring(17, 18);
        char charArray[];

        //check prefix 17 numbers are all digital
        if (isDigital(idNumber17)) {
            charArray = idNumber17.toCharArray();
        } else {
            return false;
        }

        //check region code
        String province = idNumber.substring(0, 2);
        if (!code2Province.containsKey(province)) {
            return false;
        }

        //check birthday
        String birthday = idNumber.substring(6, 14);
        int year = Integer.parseInt(idNumber.substring(6, 10));
        int month = Integer.parseInt(idNumber.substring(10, 12));
        int day = Integer.parseInt(idNumber.substring(12, 14));

        //check birthday format and whether this date is before current time
        Date birthDate = null;
        try {
            birthDate = new SimpleDateFormat("yyyyMMdd").parse(birthday);
        } catch (ParseException ex) {
            Logger.getLogger(ChineseIdNumberValidator.class.getName()).log(Level.SEVERE, null, ex);
        }
        if (birthDate == null || System.currentTimeMillis() <= birthDate.getTime()) {
            return false;
        }

        //check year, month, day
        if (year < IdNumberConstant.MIN_YEAR) {
            return false;
        }

        if (month < 1 || month > 12) {
            return false;
        }
        switch (month) {
            case 1:
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
            case 12:
                if (day < 1 || day > 31) {
                    return false;
                }
                break;
            case 4:
            case 6:
            case 9:
            case 11:
                if (day < 1 || day > 30) {
                    return false;
                }
                break;
            case 2:
                if (isLeapYear(year)) {
                    if (day < 1 || day > 29) {
                        return false;
                    }
                } else {
                    if (day < 1 || day > 28) {
                        return false;
                    }
                }
                break;
        }

        //check the sum of prefix 17 numbers mutilplied by weighted factor equals the last check code
        if (null != charArray) {
            if (!idNumber18Code.equals(
                    getCheckCode(
                            getPowerSum(
                                    char2Int(charArray))))) {
                return false;
            }

        }

        return true;
    }

    @SuppressWarnings("unused")
    private String convert15To18(String idNumber) {
        if (idNumber.length() != 15) {
            return null;
        }

        String idNumber17;
        if (isDigital(idNumber)) {
            String birthday = idNumber.substring(6, 12);
            Date birthdate = null;
            try {
                birthdate = new SimpleDateFormat("yyMMdd").parse(birthday);
            } catch (ParseException ex) {
                Logger.getLogger(ChineseIdNumberValidator.class.getName()).log(Level.SEVERE, null, ex);
            }

            calendar.setTime(birthdate);
            String year = String.valueOf(calendar.get(Calendar.YEAR));
            idNumber17 = idNumber.substring(0, 6) + year + idNumber.substring(8);
            char charArray[] = idNumber17.toCharArray();
            if (null != charArray) {
                int sum17 = getPowerSum(char2Int(charArray));
                idNumber17 += getCheckCode(sum17);
            }
        } else {
            return null;
        }
        return idNumber17;
    }

    private boolean isDigital(String str) {
        return str == null || "".equals(str) ? false : str.matches("[0-9]*");
    }

    private int getPowerSum(int[] bit) {
        int sum = 0;
        if (weightFactor.length != bit.length) {
            return sum;
        }
        for (int i = 0; i < bit.length; i++) {
            sum = sum + bit[i] * weightFactor[i];
        }
        return sum;
    }

    private String getCheckCode(int sum17) {
        return checkCode[sum17 % 11];
    }

    private int[] char2Int(char[] charArray) throws NumberFormatException {
        int[] array = new int[charArray.length];
        int k = 0;
        for (char temp : charArray) {
            array[k++] = Integer.parseInt(String.valueOf(temp));
        }
        return array;
    }

    @SuppressWarnings("unused")
    private boolean isValidIdRegion(String region) {
        if (!Regions.isValidRegion(region)) {
            return false;
        }

        //idNumber start with something like "110000 北京市/110100 市辖区/110200 县" is not valid
        if (region.substring(4, 6).equals(IdNumberConstant.CITY_SUFFIX)) {
            return false;
        }

        //台湾 香港 澳门暂时屏蔽
        String province = region.substring(0, 2);
        if (!isValidProvince(province)) {
            return false;
        }

        return true;
    }

    private boolean isValidProvince(String province) {
        return !(province.equals(IdNumberConstant.TAIWANG)
                 || province.equals(IdNumberConstant.HONGKONG)
                 || province.equals(IdNumberConstant.MACAU));
    }

    private boolean isLeapYear(int year) {
        return (year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0);
    }
}
时间: 2024-11-09 03:16:36

大陆居民身份证验证方法(java)的相关文章

Java连接MySQL数据库实现用户名密码的验证方法 Java语句中sql查询语句&#39;&#39; &quot;&quot;作用

//方法一,可以验证登录,但方法不实用.package com.swift; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; public class Logi

身份证验证(java)

import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.Hashtable; import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; p

java 18位身份证验证小组件idchecker

原文:java 18位身份证验证小组件idchecker 源代码下载地址:http://www.zuidaima.com/share/1550463500012544.htm 代码运行结果: 其它调用方法: package com.zuidaima.idchecker.test; import cn.idchecker.check.Checker; /** * idchecker测试 * @author http://www.zuidaima.com * */ public class Test

Java、Android身份证验证工具 支持15/18位、地区、生日和校验码验证

首先科普一下身份证的一些知识(知道的勿喷) 1-2 位:代表升级行政区代码 3-4 位:代表地级行政区划分代码 5-6 位:代表县区行政区分代码 7-14 位:代表出生年.月.日,例如:19900101 15-17 位:代表 顺序码,同一地区同年.同月.同日出生人的编号,奇数是男性,偶数是女性 18 位:代表校验码,如果是0-9则用0-9表示,如果是10则用X(罗马数字10)表示 注:另外有些15位的身份证号码,年份使用2位数字表示的,并且没有最后一位校验码:从1999年10月1日起,全国实行公

【NumberValidators】大陆身份证验证

原文:[NumberValidators]大陆身份证验证 需要说明的是这里的大陆身份证识别并不是公安局联网的识别,而是按国标GB 11643进行的验证,所以其验证结果只能说符合国标规范,但不能保证该身份证一定真实存在,如果你实际需求是希望身份证一定真实存在,那么你可以在通过此类库初步验证后,再调用第三方(或牛逼的可以直连公安,毕竟所有的第三方其数据来源必定是公安局)以降低调用成本(公安调用一次两块钱,还不是有钱就能调用!!!) 转到正题,在NumberValidators中,大陆身份证相关的代码

java 安全验证方法

输入数据验证:虽然为方便用户而在客户端层上提供数据验证,但仍必须使用 Servlet 在服务器层上执行数据验证.客户端验证本身就不安全,因为这 些验证可轻易绕过,例如,通过禁用 Javascript. 一份好的设计通常需要 Web 应用程序框架,以提供服务器端实用程序例程,从而验证以下内容:[1] 必需字段[2] 字段数据类型(缺省情况下,所有 HTTP 请求参数都是"字符串")[3] 字段长度[4] 字段范围[5] 字段选项[6] 字段模式[7] cookie 值[8] HTTP 响

java身份证验证

import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.Hashtable; import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern;  

java 常用的验证方法帮助类

import java.text.ParseException; import java.util.Collection; import java.util.Map; /** * 常用的验证方法帮助类,提供对字符串,集合,数组,数值的验证 * * */ public class ValidateHelper { /** * 判断一个字符串是否不是一个空字符串 * * @param s 要判断的字符串 * @return 如果不为空返回true,否则返回false */ public static

jQuery Validate扩展验证方法

/***************************************************************** jQuery Validate扩展验证方法 (linjq) *****************************************************************/ $(function(){ // 判断整数value是否等于0 jQuery.validator.addMethod("isIntEqZero", functio