一、身份证号码工具类
package com.chenwc.tools;
import java.time.LocalDate;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 中国身份证号码工具类
*
* @author chenwc
* @date 2023/3/1 20:28
*/
public class IdCard {
/**
* 18位身份证正则表达式
*/
private final static String ID_18 = "^[1-9][0-9]{5}(18|19|20)[0-9]{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)[0-9]{3}([0-9]|(X|x))";
/**
* 15位身份证正则表达式
*/
private final static String ID_15 = "^[1-9][0-9]{5}[0-9]{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)[0-9]{2}[0-9]";
/**
* 身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X。
*/
private final static String ID_PATTERN = "(^\\d{15}$)|(^\\d{17}([0-9]|X)$)";
/**
* 校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
* 前17位数字相乘的系数
*/
private final static Integer[] arrInt = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
/**
* 校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
* 对17位数字和系数相乘的结果相加,用加出来和除以11,余数
*/
private final static Character[] arrCh = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
/**
* 省份列表
*/
private final static Map<Integer, String> provinceMap = new HashMap<Integer, String>() {{
put(11, "北京市");
put(12, "天津市");
put(13, "河北省");
put(14, "山西省");
put(15, "内蒙古自治区");
put(21, "辽宁省");
put(22, "吉林省");
put(23, "黑龙江省");
put(31, "上海市");
put(32, "江苏省");
put(33, "浙江省");
put(34, "安徽省");
put(35, "福建省");
put(36, "江西省");
put(37, "山东省");
put(41, "河南省");
put(42, "湖北省");
put(43, "湖南省");
put(44, "广东省");
put(45, "广西壮族自治区");
put(46, "海南省");
put(50, "重庆市");
put(51, "四川省");
put(52, "贵州省");
put(53, "云南省");
put(54, "西藏自治区");
put(61, "陕西省");
put(62, "甘肃省");
put(63, "青海省");
put(64, "宁夏回族自治区");
put(65, "新疆维吾尔自治区");
put(71, "台湾省");
put(81, "香港特别行政区");
put(82, "澳门特别行政区");
put(91, "国外");
}};
/**
* 判断是否符合身份证格式,身份证号(15位号码应全为数字,18位号码末位可以为数字或X)
*
* @param idCard 身份证号码字符串
* @return 符合返回true,不符合返回false
*/
public static boolean isIdCardNums(String idCard) {
if (null == idCard || idCard.isEmpty()) {
return false;
}
if (idCard.length() == 15) {
Pattern pattern = Pattern.compile(ID_15);
Matcher matcher = pattern.matcher(idCard);
return matcher.matches();
}
if (idCard.length() == 18) {
Pattern pattern = Pattern.compile(ID_18);
Matcher matcher = pattern.matcher(idCard);
return matcher.matches();
}
return false;
}
/**
* 把15位身份证转成18位
*
* @param IdCard_15 15位身份证
* @return 18位身份证
*/
public static String change15To18IdCard(String IdCard_15) {
int len = IdCard_15.length();
Pattern pattern = Pattern.compile(ID_PATTERN);
Matcher matcher = pattern.matcher(IdCard_15);
if (!matcher.matches()) {
throw new RuntimeException("输入的身份证号长度不对,或者号码不符合规定!15位号码应全为数字。");
}
if (len == 15) {
List<String> numList = new ArrayList<>();
numList.add(IdCard_15.substring(0, 6));
numList.add(IdCard_15.substring(6, 8));
numList.add(IdCard_15.substring(8, 10));
numList.add(IdCard_15.substring(10, 12));
numList.add(IdCard_15.substring(12));
if (!isBirthDayInValid(numList)) {
//将15位身份证转成18位
int nTemp = 0, i;
String IdCard_18;
IdCard_18 = IdCard_15.substring(0, 6) + "19" + IdCard_15.substring(6);
for (i = 0; i < 17; i++) {
nTemp = nTemp + Integer.parseInt(String.valueOf(IdCard_18.charAt(i))) * arrInt[i];
}
IdCard_18 += arrCh[nTemp % 11];
return IdCard_18;
}
}
return null;
}
/**
* 验证15位和18位的身份证,并且包含生日和校验位的验证。
*
* @param num 身份证号码
* @return 符合返回true,不符合返回false
*/
public static boolean isIdCardNo(String num) {
num = num.toUpperCase();
Pattern pattern = Pattern.compile(ID_PATTERN);
Matcher matcher = pattern.matcher(num);
if (!matcher.matches()) {
throw new RuntimeException("输入的身份证号长度不对,或者号码不符合规定!15位号码应全为数字,18位号码末位可以为数字或X。");
}
int province = Integer.parseInt(num.substring(0, 2));
if (!provinceMap.containsKey(province)) {
throw new RuntimeException("非法地区:" + province);
}
//下面分别分析出生日期和校验位
int len = num.length();
if (len == 15) {
List<String> numList = new ArrayList<>();
numList.add(num.substring(0, 6));
numList.add(num.substring(6, 8));
numList.add(num.substring(8, 10));
numList.add(num.substring(10, 12));
numList.add(num.substring(12));
return !isBirthDayInValid(numList);
}
if (len == 18) {
List<String> numList = new ArrayList<>();
numList.add(num.substring(0, 6));
numList.add(num.substring(6, 10));
numList.add(num.substring(10, 12));
numList.add(num.substring(12, 14));
numList.add(num.substring(14));
if (isBirthDayInValid(numList)) {
return false;
} else {
//检验18位身份证的校验码是否正确。
char valnum;
int nTemp = 0, i;
for (i = 0; i < 17; i++) {
nTemp = nTemp + Integer.parseInt(String.valueOf(num.charAt(i))) * arrInt[i];
}
valnum = arrCh[nTemp % 11];
if (!String.valueOf(valnum).equals(num.substring(17))) {
throw new RuntimeException("18位身份证的校验码不正确!应该为:" + valnum);
}
return true;
}
}
return false;
}
/**
* 校验出生日期是否合法
*
* @param numList 出生日期
* @return 不合法返回true,合法返回false
*/
private static boolean isBirthDayInValid(List<String> numList) {
int year;
if (numList.get(1).length() == 2) {
year = Integer.parseInt("19" + numList.get(1));
} else {
year = Integer.parseInt(numList.get(1));
}
int date = Integer.parseInt(numList.get(3));
int month = Integer.parseInt(numList.get(2));
if (year < 1900 || year > 2099) {
throw new RuntimeException("输入的身份证号里出生日期不对: " + year + "年" + month + "月" + date + "日");
}
if (month <= 0 || month > 12) {
throw new RuntimeException("输入的身份证号里出生日期不对: " + year + "年" + month + "月" + date + "日");
}
if (date <= 0) {
throw new RuntimeException("输入的身份证号里出生日期不对: " + year + "年" + month + "月" + date + "日");
}
if (2 == month) {
LocalDate localDate;
if (numList.get(1).length() == 2) {
localDate = LocalDate.parse("19" + numList.get(1) + "-01-01");
} else {
localDate = LocalDate.parse(numList.get(1) + "-01-01");
}
//闰年
if (localDate.isLeapYear()) {
if (date > 29) {
throw new RuntimeException("输入的身份证号里出生日期不对,闰年2月只有29天: " + year + "年" + month + "月" + date + "日");
}
} else {
if (date > 28) {
throw new RuntimeException("输入的身份证号里出生日期不对,非闰年2月只有28天: " + year + "年" + month + "月" + date + "日");
}
}
} else {
if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
if (date > 31) {
throw new RuntimeException("输入的身份证号里出生日期不对," + month + "月只有31天: " + year + "年" + month + "月" + date + "日");
}
} else {
if (date > 30) {
throw new RuntimeException("输入的身份证号里出生日期不对," + month + "月只有30天: " + year + "年" + month + "月" + date + "日");
}
}
}
return false;
}
/**
* 生成随机的18位身份证号码
* 出生日期为:1900-01-01 ~ 今天
*
* @return 18位身份证号码
*/
public static String generateRandom18IdCard() {
StringBuilder stringBuilder = new StringBuilder();
List<Integer> list = new ArrayList<>(provinceMap.keySet());
//生成前6位地区数字
stringBuilder.append(list.get(RandomUuid.getRandomIntByBound(list.size())));
stringBuilder.append(RandomUuid.getRandomInt0To9());
stringBuilder.append(RandomUuid.getRandomInt0To9());
stringBuilder.append(RandomUuid.getRandomInt0To9());
stringBuilder.append(RandomUuid.getRandomInt0To9());
//年
LocalDate today = LocalDate.now();
String[] year = {"19", "20"};
String yearStr;
String addYearStr = year[RandomUuid.getRandomIntByBound(year.length)];
stringBuilder.append(addYearStr);
int lastYear;
int yearBound = 99;
if (!"19".equals(addYearStr)) {
//获取今年的年+1
yearBound = Integer.parseInt(String.valueOf(today.getYear() + 1).substring(2));
}
lastYear = RandomUuid.getRandomIntByBound(yearBound);
if (lastYear < 10) {
stringBuilder.append("0").append(lastYear);
yearStr = addYearStr + "0" + lastYear;
} else {
stringBuilder.append(lastYear);
yearStr = addYearStr + lastYear;
}
//月
int monthBound = 13;
if (today.getYear() == Integer.parseInt(yearStr)) {
monthBound = today.getMonthValue() + 1;
}
int month = RandomUuid.getRandomIntByBound(monthBound);
while (month == 0) {
month = RandomUuid.getRandomIntByBound(monthBound);
}
if (month < 10) {
stringBuilder.append("0").append(month);
} else {
stringBuilder.append(month);
}
//日
int date;
if (2 == month) {
LocalDate localDate = LocalDate.parse(yearStr + "-01-01");
//闰年
int dayBound;
if (localDate.isLeapYear()) {
dayBound = 30;
}
//非闰年
else {
dayBound = 29;
}
if (today.getYear() == Integer.parseInt(yearStr) && month == today.getMonthValue()) {
dayBound = today.getDayOfMonth() + 1;
}
date = RandomUuid.getRandomIntByBound(dayBound);
while (date == 0) {
date = RandomUuid.getRandomIntByBound(dayBound);
}
}
//大月31日
else if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
int dayBound = 32;
if (today.getYear() == Integer.parseInt(yearStr) && month == today.getMonthValue()) {
dayBound = today.getDayOfMonth() + 1;
}
date = RandomUuid.getRandomIntByBound(dayBound);
while (date == 0) {
date = RandomUuid.getRandomIntByBound(dayBound);
}
}
//小月30日
else {
int dayBound = 31;
if (today.getYear() == Integer.parseInt(yearStr) && month == today.getMonthValue()) {
dayBound = today.getDayOfMonth() + 1;
}
date = RandomUuid.getRandomIntByBound(dayBound);
while (date == 0) {
date = RandomUuid.getRandomIntByBound(dayBound);
}
}
if (date < 10) {
stringBuilder.append("0").append(date);
} else {
stringBuilder.append(date);
}
//生成三位随机校验数字
for (int i = 0; i < 3; i++) {
stringBuilder.append(RandomUuid.getRandomInt0To9());
}
//计算校验和
String num = stringBuilder.toString();
int nTemp = 0, i;
for (i = 0; i < 17; i++) {
nTemp = nTemp + Integer.parseInt(String.valueOf(num.charAt(i))) * arrInt[i];
}
stringBuilder.append(arrCh[nTemp % 11]);
return stringBuilder.toString();
}
}
二、随机数工具类
package com.chenwc.tools;
import java.util.Random;
/**
* 自定义随机数生成工具类
*
* @author chenwc
* @date 2023/3/1 20:29
*/
public class RandomUuid {
/**
* 生成指定长度随机数UUID,包含0-9数字和字母(字母包含大小写)
*
* @param len 指定长度
* @return 随机数UUID字符串
*/
public static String getUuidByNumberAndCharacter(int len) {
if (len <= 0) {
throw new RuntimeException("长度要大于0");
}
StringBuilder val = new StringBuilder();
Random random = new Random();
for (int i = 0; i < len; i++) {
String str = random.nextInt(2) % 2 == 0 ? "num" : "char";
if ("char".equalsIgnoreCase(str)) {
// 产生a-z或者A-Z字母
int nextInt = random.nextInt(2) % 2 == 0 ? 65 : 97;
val.append((char) (nextInt + random.nextInt(26)));
} else {
// 产生0-9数字
val.append(random.nextInt(10));
}
}
return val.toString();
}
/**
* 生成指定长度随机数UUID,字母(字母包含大小写)
*
* @param len 指定长度
* @return 随机数UUID字符串
*/
public static String getUuidByCharacter(int len) {
if (len <= 0) {
throw new RuntimeException("长度要大于0");
}
StringBuilder val = new StringBuilder();
Random random = new Random();
for (int i = 0; i < len; i++) {
// 产生a-z或者A-Z字母
int nextInt = random.nextInt(2) % 2 == 0 ? 65 : 97;
val.append((char) (nextInt + random.nextInt(26)));
}
return val.toString();
}
/**
* 生成随机数UUID
*
* @return 随机数UUID字符串
*/
public static String getUuid() {
StringBuilder val = new StringBuilder();
Random random = new Random();
for (int i = 0; i < 32; i++) {
String str = random.nextInt(2) % 2 == 0 ? "num" : "char";
if ("char".equalsIgnoreCase(str)) {
// 产生a-z字母
val.append((char) (97 + random.nextInt(26)));
} else {
// 产生0-9数字
val.append(random.nextInt(10));
}
if (i == 7) {
val.append("-");
}
if (i == 11 || i == 15 || i == 19) {
val.append("-");
}
}
return val.toString();
}
/**
* 生成指定长度的随机整数
*
* @param len 长度
* @return 随机整数
*/
public static String getRandomInt(int len) {
if (len <= 0) {
throw new RuntimeException("长度要大于0");
}
StringBuilder rs = new StringBuilder();
for (int i = 0; i < len; i++) {
int a = getRandomInt0To9();
//首位数字不能为0
if (0 == i) {
while (0 == a) {
a = getRandomInt0To9();
}
}
rs.append(a);
}
return rs.toString();
}
/**
* 获取一个0-9的整数
*
* @return 0-9的整数
*/
public static Integer getRandomInt0To9() {
return getRandomIntByBound(10);
}
/**
* 获取一个0-指定范围的整数
*
* @param bound 范围
* @return 0-指定范围的整数
*/
public static Integer getRandomIntByBound(int bound) {
Random r = new Random();
return r.nextInt(bound);
}
}