站長資訊網
        最全最豐富的資訊網站

        面向對象的15、18位中國大陸身份證號碼解析、工具

        最近項目中需要給用戶增加身份證號字段,參考了幾位別人的實現。

        特點:1、面向對象:把身份證號封裝為一個類,解析各個字段、驗證有效性都是對象上的實例方法。對比那種公開多個靜態方法的工具類的方式,我覺得這種面向對象的方式更自然一些。

        2、不可變的。身份證號對象是不可變的,減少使用中的復雜性。

        3、不是線程安全的。

        001 import java.text.SimpleDateFormat;
        002 import java.util.Date;
        003  
        004 /**
        005  * 身份證號碼,可以解析身份證號碼的各個字段,以及驗證身份證號碼是否有效<br>
        006  * 身份證號碼構成:6位地址編碼+8位生日+3位順序碼+1位校驗碼
        007  *
        008  * @author liuex
        009  *
        010  */
        011 public class IDCard {
        012     /**
        013      * 完整的身份證號碼
        014      */
        015     private final String cardNumber;
        016     // 緩存身份證是否有效,因為驗證有效性使用頻繁且計算復雜
        017     private Boolean cacheValidateResult = null;
        018     // 緩存出生日期,因為出生日期使用頻繁且計算復雜
        019     private Date cacheBirthDate = null;
        020  
        021     public boolean validate() {
        022         if (null == cacheValidateResult) {
        023             boolean result = true;
        024             // 身份證號不能為空
        025             result = result && (null != cardNumber);
        026             // 身份證號長度是18(新證)
        027             result = result && NEW_CARD_NUMBER_LENGTH == cardNumber.length();
        028             // 身份證號的前17位必須是阿拉伯數字
        029             for (int i = 0; result && i < NEW_CARD_NUMBER_LENGTH - 1; i++) {
        030                 char ch = cardNumber.charAt(i);
        031                 result = result && ch >= '0' && ch <= '9';
        032             }
        033             // 身份證號的第18位校驗正確
        034             result = result
        035                     && (calculateVerifyCode(cardNumber) == cardNumber
        036                             .charAt(NEW_CARD_NUMBER_LENGTH - 1));
        037             // 出生日期不能晚于當前時間,并且不能早于1900年
        038             try {
        039                 Date birthDate = this.getBirthDate();
        040                 result = result && null != birthDate;
        041                 result = result && birthDate.before(new Date());
        042                 result = result && birthDate.after(MINIMAL_BIRTH_DATE);
        043                 /**
        044                  * 出生日期中的年、月、日必須正確,比如月份范圍是[1,12],日期范圍是[1,31],還需要校驗閏年、大月、小月的情況時,
        045                  * 月份和日期相符合
        046                  */
        047                 String birthdayPart = this.getBirthDayPart();
        048                 String realBirthdayPart = this.createBirthDateParser().format(
        049                         birthDate);
        050                 result = result && (birthdayPart.equals(realBirthdayPart));
        051             } catch (Exception e) {
        052                 result = false;
        053             }
        054             // TODO 完整身份證號碼的省市縣區檢驗規則
        055             cacheValidateResult = Boolean.valueOf(result);
        056         }
        057         return cacheValidateResult;
        058     }
        059  
        060     /**
        061      * 如果是15位身份證號碼,則自動轉換為18位
        062      *
        063      * @param cardNumber
        064      */
        065     public IDCard(String cardNumber) {
        066         if (null != cardNumber) {
        067             cardNumber = cardNumber.trim();
        068             if (OLD_CARD_NUMBER_LENGTH == cardNumber.length()) {
        069                 cardNumber = contertToNewCardNumber(cardNumber);
        070             }
        071         }
        072         this.cardNumber = cardNumber;
        073     }
        074  
        075     public String getCardNumber() {
        076         return cardNumber;
        077     }
        078  
        079     public String getAddressCode() {
        080         this.checkIfValid();
        081         return this.cardNumber.substring(0, 6);
        082     }
        083  
        084     public Date getBirthDate() {
        085         if (null == this.cacheBirthDate) {
        086             try {
        087                 this.cacheBirthDate = this.createBirthDateParser().parse(
        088                         this.getBirthDayPart());
        089             } catch (Exception e) {
        090                 throw new RuntimeException("身份證的出生日期無效");
        091             }
        092         }
        093         return new Date(this.cacheBirthDate.getTime());
        094     }
        095  
        096     public boolean isMale() {
        097         return 1 == this.getGenderCode();
        098     }
        099  
        100     public boolean isFemal() {
        101         return false == this.isMale();
        102     }
        103  
        104     /**
        105      * 獲取身份證的第17位,奇數為男性,偶數為女性
        106      *
        107      * @return
        108      */
        109     private int getGenderCode() {
        110         this.checkIfValid();
        111         char genderCode = this.cardNumber.charAt(NEW_CARD_NUMBER_LENGTH - 2);
        112         return (((int) (genderCode - '0')) & 0x1);
        113     }
        114  
        115     private String getBirthDayPart() {
        116         return this.cardNumber.substring(6, 14);
        117     }
        118  
        119     private SimpleDateFormat createBirthDateParser() {
        120         return new SimpleDateFormat(BIRTH_DATE_FORMAT);
        121     }
        122  
        123     private void checkIfValid() {
        124         if (false == this.validate()) {
        125             throw new RuntimeException("身份證號碼不正確!");
        126         }
        127     }
        128  
        129     // 身份證號碼中的出生日期的格式
        130     private final static String BIRTH_DATE_FORMAT = "yyyyMMdd";
        131     // 身份證的最小出生日期,1900年1月1日
        132     private final static Date MINIMAL_BIRTH_DATE = new Date(-2209017600000L);
        133     private final static int NEW_CARD_NUMBER_LENGTH = 18;
        134     private final static int OLD_CARD_NUMBER_LENGTH = 15;
        135     /**
        136      * 18位身份證中最后一位校驗碼
        137      */
        138     private final static char[] VERIFY_CODE = { '1', '0', 'X', '9', '8', '7',
        139             '6', '5', '4', '3', '2' };
        140     /**
        141      * 18位身份證中,各個數字的生成校驗碼時的權值
        142      */
        143     private final static int[] VERIFY_CODE_WEIGHT = { 7, 9, 10, 5, 8, 4, 2, 1,
        144             6, 3, 7, 9, 10, 5, 8, 4, 2 };
        145  
        146     /**
        147      * <li>校驗碼(第十八位數):<br/>
        148      * <ul>
        149      * <li>十七位數字本體碼加權求和公式 S = Sum(Ai * Wi), i = 0...16 ,先對前17位數字的權求和;
        150      * Ai:表示第i位置上的身份證號碼數字值 Wi:表示第i位置上的加權因子 Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4
        151      * 2;</li>
        152      * <li>計算模 Y = mod(S, 11)</li>
        153      * <li>通過模得到對應的校驗碼 Y: 0 1 2 3 4 5 6 7 8 9 10 校驗碼: 1 0 X 9 8 7 6 5 4 3 2</li>
        154      * </ul>
        155      *
        156      * @param cardNumber
        157      * @return
        158      */
        159     private static char calculateVerifyCode(CharSequence cardNumber) {
        160         int sum = 0;
        161         for (int i = 0; i < NEW_CARD_NUMBER_LENGTH - 1; i++) {
        162             char ch = cardNumber.charAt(i);
        163             sum += ((int) (ch - '0')) * VERIFY_CODE_WEIGHT[i];
        164         }
        165         return VERIFY_CODE[sum % 11];
        166     }
        167  
        168     /**
        169      * 把15位身份證號碼轉換到18位身份證號碼<br>
        170      * 15位身份證號碼與18位身份證號碼的區別為:<br>
        171      * 1、15位身份證號碼中,"出生年份"字段是2位,轉換時需要補入"19",表示20世紀<br>
        172      * 2、15位身份證無最后一位校驗碼。18位身份證中,校驗碼根據根據前17位生成
        173      *
        174      * @param cardNumber
        175      * @return
        176      */
        177     private static String contertToNewCardNumber(String oldCardNumber) {
        178         StringBuilder buf = new StringBuilder(NEW_CARD_NUMBER_LENGTH);
        179         buf.append(oldCardNumber.substring(0, 6));
        180         buf.append("19");
        181         buf.append(oldCardNumber.substring(6));
        182         buf.append(IDCard.calculateVerifyCode(buf));
        183         return buf.toString();
        184     }
        185 }

         

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 国产精品欧美一区二区三区不卡| 国产麻豆精品一区二区三区v视界| 最新国产在线精品观看| 国产精品久久99| 日韩精品国产另类专区| 久久精品?ⅴ无码中文字幕| 国产精品一久久香蕉产线看| 亚洲精品成人片在线播放 | 欧美亚洲精品中文字幕乱码免费高清| 国产精品内射后入合集| 亚洲精品无码专区2| 精品久久久久久无码中文野结衣| 国产精品久久国产精品99盘| 精品亚洲aⅴ在线观看| 亚洲高清国产AV拍精品青青草原| 久久久久久国产精品免费免费 | 亚洲国产精品无码久久九九| 国产精品成| 久久亚洲国产精品一区二区| 国产午夜精品久久久久免费视| 亚洲精品字幕在线观看| 亚洲精品宾馆在线精品酒店| 久久国产精品免费一区| 国产精品无码素人福利| 91国内揄拍国内精品情侣对白| 国产精品高清一区二区三区不卡 | 一区二区三区精品国产欧美| 500av导航大全精品| 国产麻豆精品一区二区三区v视界| 亚洲Av无码精品色午夜| 一本久久精品一区二区| 亚洲精品永久在线观看| 亚洲精品国精品久久99热| 亚洲国产一成久久精品国产成人综合| 久久99精品久久久久久噜噜| 精品一区二区无码AV| 久久九九久精品国产免费直播| 精品无码一级毛片免费视频观看| 精品人妻一区二区三区毛片| 久久精品无码av| 自拍偷自拍亚洲精品第1页|