站長資訊網(wǎng)
        最全最豐富的資訊網(wǎng)站

        面向?qū)ο蟮?5、18位中國大陸身份證號(hào)碼解析、工具

        最近項(xiàng)目中需要給用戶增加身份證號(hào)字段,參考了幾位別人的實(shí)現(xiàn)。

        特點(diǎn):1、面向?qū)ο螅喊焉矸葑C號(hào)封裝為一個(gè)類,解析各個(gè)字段、驗(yàn)證有效性都是對(duì)象上的實(shí)例方法。對(duì)比那種公開多個(gè)靜態(tài)方法的工具類的方式,我覺得這種面向?qū)ο蟮姆绞礁匀灰恍?/p>

        2、不可變的。身份證號(hào)對(duì)象是不可變的,減少使用中的復(fù)雜性。

        3、不是線程安全的。

        001 import java.text.SimpleDateFormat;
        002 import java.util.Date;
        003  
        004 /**
        005  * 身份證號(hào)碼,可以解析身份證號(hào)碼的各個(gè)字段,以及驗(yàn)證身份證號(hào)碼是否有效<br>
        006  * 身份證號(hào)碼構(gòu)成:6位地址編碼+8位生日+3位順序碼+1位校驗(yàn)碼
        007  *
        008  * @author liuex
        009  *
        010  */
        011 public class IDCard {
        012     /**
        013      * 完整的身份證號(hào)碼
        014      */
        015     private final String cardNumber;
        016     // 緩存身份證是否有效,因?yàn)轵?yàn)證有效性使用頻繁且計(jì)算復(fù)雜
        017     private Boolean cacheValidateResult = null;
        018     // 緩存出生日期,因?yàn)槌錾掌谑褂妙l繁且計(jì)算復(fù)雜
        019     private Date cacheBirthDate = null;
        020  
        021     public boolean validate() {
        022         if (null == cacheValidateResult) {
        023             boolean result = true;
        024             // 身份證號(hào)不能為空
        025             result = result && (null != cardNumber);
        026             // 身份證號(hào)長度是18(新證)
        027             result = result && NEW_CARD_NUMBER_LENGTH == cardNumber.length();
        028             // 身份證號(hào)的前17位必須是阿拉伯?dāng)?shù)字
        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             // 身份證號(hào)的第18位校驗(yàn)正確
        034             result = result
        035                     && (calculateVerifyCode(cardNumber) == cardNumber
        036                             .charAt(NEW_CARD_NUMBER_LENGTH - 1));
        037             // 出生日期不能晚于當(dāng)前時(shí)間,并且不能早于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],還需要校驗(yàn)閏年、大月、小月的情況時(shí),
        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 完整身份證號(hào)碼的省市縣區(qū)檢驗(yàn)規(guī)則
        055             cacheValidateResult = Boolean.valueOf(result);
        056         }
        057         return cacheValidateResult;
        058     }
        059  
        060     /**
        061      * 如果是15位身份證號(hào)碼,則自動(dòng)轉(zhuǎn)換為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位,奇數(shù)為男性,偶數(shù)為女性
        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("身份證號(hào)碼不正確!");
        126         }
        127     }
        128  
        129     // 身份證號(hào)碼中的出生日期的格式
        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位身份證中最后一位校驗(yàn)碼
        137      */
        138     private final static char[] VERIFY_CODE = { '1', '0', 'X', '9', '8', '7',
        139             '6', '5', '4', '3', '2' };
        140     /**
        141      * 18位身份證中,各個(gè)數(shù)字的生成校驗(yàn)碼時(shí)的權(quán)值
        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>校驗(yàn)碼(第十八位數(shù)):<br/>
        148      * <ul>
        149      * <li>十七位數(shù)字本體碼加權(quán)求和公式 S = Sum(Ai * Wi), i = 0...16 ,先對(duì)前17位數(shù)字的權(quán)求和;
        150      * Ai:表示第i位置上的身份證號(hào)碼數(shù)字值 Wi:表示第i位置上的加權(quán)因子 Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4
        151      * 2;</li>
        152      * <li>計(jì)算模 Y = mod(S, 11)</li>
        153      * <li>通過模得到對(duì)應(yīng)的校驗(yàn)碼 Y: 0 1 2 3 4 5 6 7 8 9 10 校驗(yàn)碼: 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位身份證號(hào)碼轉(zhuǎn)換到18位身份證號(hào)碼<br>
        170      * 15位身份證號(hào)碼與18位身份證號(hào)碼的區(qū)別為:<br>
        171      * 1、15位身份證號(hào)碼中,"出生年份"字段是2位,轉(zhuǎn)換時(shí)需要補(bǔ)入"19",表示20世紀(jì)<br>
        172      * 2、15位身份證無最后一位校驗(yàn)碼。18位身份證中,校驗(yàn)碼根據(jù)根據(jù)前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)
        網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)
        主站蜘蛛池模板: 国产小呦泬泬99精品| 亚洲中文久久精品无码ww16 | 亚洲国产精品毛片av不卡在线| 亚洲av午夜精品一区二区三区 | 久久伊人精品青青草原日本 | 精品人伦一区二区三区潘金莲| 老司机99精品99| 久久香综合精品久久伊人| 精品国产一区二区三区久久蜜臀 | 国产一区精品| 久久夜色精品国产欧美乱| 久久久99精品成人片中文字幕| 久久国产免费观看精品3| 亚洲国产精品13p| 精品国产亚洲一区二区在线观看| 久久精品国产99久久无毒不卡| 国产精品国产三级国产a| 青青草国产精品| 国产精品一区二区久久精品| 精品无人区一区二区三区| 中文字幕精品亚洲无线码一区应用| 精品999久久久久久中文字幕| 欧美日韩国产中文精品字幕自在自线| 第一福利永久视频精品| 精品一区二区三区自拍图片区| 精品国产福利盛宴在线观看| 国产精品第1页| 国产精品无码v在线观看| 国产精品免费高清在线观看| 久久99精品久久久久久久久久| 精品欧美激情在线看| 精品久久久久久无码国产| 国产99精品久久| 亚洲国产精品无码av| 在线亚洲精品自拍| 亚洲精品中文字幕无码蜜桃| 成人国产精品秘 果冻传媒在线| 精品无码一区二区三区亚洲桃色| 久久国产精品偷99| 久久夜色撩人精品国产小说| 99精品人妻少妇一区二区|