<pre>package validator;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.apache.commons.lang3.StringUtils;
/**
* @Description: 身份证作为居民的唯一标识。在很多系统中需要用户输入身份证号信息,今天我们就来编写一个方法验证身份证号的合法性。
*
* 首先我们来看看身份证号的编码规则: 前1-2位数字表示:所在省(直辖市、自治区)的代码; 第3-4位数字表示:所在地级市(自治州)的代码;
* 第5-6位数字表示:所在区(县、自治县、县级市)的代码; 第7-14位数字表示:出生年、月、日; 第15-16位数字表示:所在地的派出所的代码;
* 第17位数字表示性别:奇数表示男性,偶数表示女性; 第18位数字是校检码:也有的说是个人信息码,不是随计算机的随机产生,它是
* 用来检验身份证的正确性。校检码可以是0-9的数字,有时也用X表示。
*
* 知道了规则之后,我们再来看看算法:
* 第一步:将身份证号码的第1位数字与7相乘;将身份证号码的第2位数字与9相乘;将身份证号码的第3位数字与10相乘;将身份证号码的第4位数字与5相乘;将身份证号码的第5位数字与8相乘;将身份证号码的第6位数字与4相乘;将身份证号码的第7位数字与2相乘;将身份证号码的第8位数字与1相乘;将身份证号码的第9位数字与6相乘;将身份证号码的第10位数字与3相乘;将身份证号码的第11位数字与7相乘;将身份证号码的第12位数字与9相乘;将身份证号码的第13位数字与10相乘;将身份证号码的第14位数字与5相乘;将身份证号码的第15位数字与8相乘;将身份证号码的第16位数字与4相乘;将身份证号码的第17位数字与2相乘。
* 第二步:将第一步身份证号码1~17位相乘的结果求和,全部加起来。
* 第三步:用第二步计算出来的结果除以11,这样就会出现余数为0,余数为1,余数为2,余数为3,余数为4,余数为5,余数为6,余数为7,余数为8,余数为9,余数为10共11种可能性。
* 第四步:如果余数为0,那对应的最后一位身份证的号码为1;如果余数为1,那对应的最后一位身份证的号码为0;如果余数为2,那对应的最后一位身份证的号码为X;如果余数为3,那对应的最后一位身份证的号码为9;如果余数为4,那对应的最后一位身份证的号码为8;如果余数为5,那对应的最后一位身份证的号码为7;如果余数为6,那对应的最后一位身份证的号码为6;如果余数为7,那对应的最后一位身份证的号码为5;如果余数为8,那对应的最后一位身份证的号码为4;如果余数为9,那对应的最后一位身份证的号码为3;如果余数为10,那对应的最后一位身份证的号码为2。
*
*/
public class IdCardConstraintValidator implements ConstraintValidator<IdCard, String> {
private final static String ID_CARD_REGEX = "^[1-9][0-9]{16}[0-9xX]$";
/**
* <pre>
* 省、直辖市代码表:
* 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 : 国外
* </pre>
*/
private final static String[] PROVINCE_CODE = { "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 final static int[] POWER = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };
/**
* 余数对应的校验码(字符串在数组中的位置即为余数)
*/
private final static String[] CHECK_CODE = { "1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2" };
private boolean blankable = false;
@Override
public void initialize(IdCard constraintAnnotation) {
if (constraintAnnotation.blankable()) {
blankable = true;
}
}
@Override
public boolean isValid(String idCard, ConstraintValidatorContext context) {
if (blankable && StringUtils.isBlank(idCard)) {
return true;
}
Pattern pattern = Pattern.compile(ID_CARD_REGEX);
Matcher matcher = pattern.matcher(idCard);
if (matcher.matches()) {
idCard = idCard.toUpperCase();
// 验证出生地
String provinceCode = idCard.substring(0, 2);
if (!Arrays.asList(PROVINCE_CODE).contains(provinceCode)) {
return false;
}
// 验证生日
String birthday = idCard.substring(6, 14);
try {
LocalDate now = LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
LocalDate birthdayDate = LocalDate.parse(birthday, formatter);
if (birthdayDate.isAfter(now)) {
return false;
}
} catch (DateTimeException e) {
return false;
}
// 验证校验码
char[] c = idCard.substring(0, 17).toCharArray();
int sum17 = 0;
for (int i = 0; i < c.length; i++) {
int a = Integer.parseInt(String.valueOf(c[i]));
sum17 += a * POWER[i];
}
String checkCode = CHECK_CODE[sum17 % 11];
if (idCard.endsWith(checkCode)) {
return true;
}
}
return false;
}
}
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.ReportAsSingleViolation;
@Documented
@Constraint(validatedBy = {IdCardConstraintValidator.class})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@ReportAsSingleViolation
@Repeatable(value = List.class)
public @interface IdCard {
String message() default "身份证格式错误";
/**
* 是否允许校验的字段为空
* @return
*/
boolean blankable() default false;
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
@interface List {
IdCard[] value();
}
}
</pre>
代码片段: IdCardConstraintValidator-IdCardConstraintValidator.java
package validator;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.regex...
- 发表于 2018-07-06 15:40
- 阅读 ( 461 )
- 分类:代码片段
你可能感兴趣的文章
- Java 添加条码、二维码到PDF文档 134 浏览
- Java 在Excel中添加筛选器并执行筛选 91 浏览
- JAVA + VUE + 简洁UI:分离式软件平台形成之旅 265 浏览
- Java 设置Word中的表格自适应的3种方式 113 浏览
- LeaRun快速开发平台,.net/java项目开发工具简析 142 浏览
- JVM学习笔记之类装载器-ClassLoader 203 浏览
随机文章
- MySQL中查询、删除重复记录的方法大全 4212 浏览
- JAVA判断两个时间戳,相隔多少分钟 4633 浏览
- 工具类:Java操作字节流工具类 2623 浏览
- 微信小程序识别菊花码的生成过程 2641 浏览
- 微信小程序识别菊花码的识别 3339 浏览
相关问题
- java基础知识提问 1 回答
条评论
请先 登录 后评论
发送私信
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!