forked from plusone/plusone-commons
修改身份证号的实现
parent
274f2d9874
commit
cca3c8b1ee
|
@ -16,26 +16,39 @@
|
||||||
|
|
||||||
package xyz.zhouxy.plusone.commons.model;
|
package xyz.zhouxy.plusone.commons.model;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.errorprone.annotations.Immutable;
|
import com.google.errorprone.annotations.Immutable;
|
||||||
|
|
||||||
|
import xyz.zhouxy.plusone.commons.annotation.ReaderMethod;
|
||||||
import xyz.zhouxy.plusone.commons.annotation.ValueObject;
|
import xyz.zhouxy.plusone.commons.annotation.ValueObject;
|
||||||
|
import xyz.zhouxy.plusone.commons.constant.PatternConsts;
|
||||||
import xyz.zhouxy.plusone.commons.util.AssertTools;
|
import xyz.zhouxy.plusone.commons.util.AssertTools;
|
||||||
import xyz.zhouxy.plusone.commons.util.StringTools;
|
import xyz.zhouxy.plusone.commons.util.StringTools;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Chinese2ndGenIDCardNumber
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
* 中国第二代居民身份证号
|
* 中国第二代居民身份证号
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||||
|
* @since 1.0
|
||||||
|
* @see xyz.zhouxy.plusone.commons.constant.PatternConsts#CHINESE_2ND_ID_CARD_NUMBER
|
||||||
*/
|
*/
|
||||||
@ValueObject
|
@ValueObject
|
||||||
@Immutable
|
@Immutable
|
||||||
public class Chinese2ndGenIDCardNumber extends IDCardNumber {
|
public class Chinese2ndGenIDCardNumber implements IDCardNumber, Serializable {
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
/** 省份编码 */
|
/** 省份编码 */
|
||||||
private final String provinceCode;
|
private final String provinceCode;
|
||||||
|
@ -52,7 +65,7 @@ public class Chinese2ndGenIDCardNumber extends IDCardNumber {
|
||||||
|
|
||||||
private Chinese2ndGenIDCardNumber(String value, String provinceCode, String cityCode, String countyCode,
|
private Chinese2ndGenIDCardNumber(String value, String provinceCode, String cityCode, String countyCode,
|
||||||
Gender gender, LocalDate birthDate) {
|
Gender gender, LocalDate birthDate) {
|
||||||
super(value);
|
this.value = value;
|
||||||
this.provinceCode = provinceCode;
|
this.provinceCode = provinceCode;
|
||||||
this.cityCode = cityCode;
|
this.cityCode = cityCode;
|
||||||
this.countyCode = countyCode;
|
this.countyCode = countyCode;
|
||||||
|
@ -60,13 +73,11 @@ public class Chinese2ndGenIDCardNumber extends IDCardNumber {
|
||||||
this.birthDate = birthDate;
|
this.birthDate = birthDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Pattern PATTERN = Pattern.compile("^(?<county>(?<city>(?<province>\\d{2})\\d{2})\\d{2})(?<birthDate>\\d{8})\\d{2}(?<gender>\\d)([\\dXx])$");
|
|
||||||
|
|
||||||
public static Chinese2ndGenIDCardNumber of(final String value) {
|
public static Chinese2ndGenIDCardNumber of(final String value) {
|
||||||
AssertTools.checkArgument(StringTools.isNotBlank(value), "二代居民身份证校验失败:号码为空");
|
AssertTools.checkArgument(StringTools.isNotBlank(value), "二代居民身份证校验失败:号码为空");
|
||||||
final String idNumber = value.toUpperCase();
|
final String idNumber = value.toUpperCase();
|
||||||
|
|
||||||
final Matcher matcher = Chinese2ndGenIDCardNumber.PATTERN.matcher(idNumber);
|
final Matcher matcher = PatternConsts.CHINESE_2ND_ID_CARD_NUMBER.matcher(idNumber);
|
||||||
AssertTools.checkArgument(matcher.matches(), () -> "二代居民身份证校验失败:" + value);
|
AssertTools.checkArgument(matcher.matches(), () -> "二代居民身份证校验失败:" + value);
|
||||||
|
|
||||||
final String provinceCode = matcher.group("province");
|
final String provinceCode = matcher.group("province");
|
||||||
|
@ -98,39 +109,53 @@ public class Chinese2ndGenIDCardNumber extends IDCardNumber {
|
||||||
// #region - reader methods
|
// #region - reader methods
|
||||||
// ================================
|
// ================================
|
||||||
|
|
||||||
|
@ReaderMethod
|
||||||
|
public String value() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReaderMethod
|
||||||
public String getProvinceCode() {
|
public String getProvinceCode() {
|
||||||
return provinceCode;
|
return provinceCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReaderMethod
|
||||||
public String getProvinceName() {
|
public String getProvinceName() {
|
||||||
return PROVINCE_CODES.get(this.provinceCode);
|
return PROVINCE_CODES.get(this.provinceCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReaderMethod
|
||||||
public String getFullProvinceCode() {
|
public String getFullProvinceCode() {
|
||||||
return Strings.padEnd(this.provinceCode, 12, '0');
|
return Strings.padEnd(this.provinceCode, 12, '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReaderMethod
|
||||||
public String getCityCode() {
|
public String getCityCode() {
|
||||||
return cityCode;
|
return cityCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReaderMethod
|
||||||
public String getFullCityCode() {
|
public String getFullCityCode() {
|
||||||
return Strings.padEnd(this.cityCode, 12, '0');
|
return Strings.padEnd(this.cityCode, 12, '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReaderMethod
|
||||||
public String getCountyCode() {
|
public String getCountyCode() {
|
||||||
return countyCode;
|
return countyCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReaderMethod
|
||||||
public String getFullCountyCode() {
|
public String getFullCountyCode() {
|
||||||
return Strings.padEnd(this.countyCode, 12, '0');
|
return Strings.padEnd(this.countyCode, 12, '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReaderMethod
|
||||||
@Override
|
@Override
|
||||||
public Gender getGender() {
|
public Gender getGender() {
|
||||||
return gender;
|
return gender;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReaderMethod
|
||||||
@Override
|
@Override
|
||||||
public LocalDate getBirthDate() {
|
public LocalDate getBirthDate() {
|
||||||
return birthDate;
|
return birthDate;
|
||||||
|
@ -188,11 +213,18 @@ public class Chinese2ndGenIDCardNumber extends IDCardNumber {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return super.hashCode();
|
return Objects.hashCode(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
return super.equals(obj);
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (!(obj instanceof Chinese2ndGenIDCardNumber))
|
||||||
|
return false;
|
||||||
|
Chinese2ndGenIDCardNumber other = (Chinese2ndGenIDCardNumber) obj;
|
||||||
|
return Objects.equals(value, other.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 20241202095400L;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,42 +19,31 @@ package xyz.zhouxy.plusone.commons.model;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.Period;
|
import java.time.Period;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
import xyz.zhouxy.plusone.commons.util.AssertTools;
|
import xyz.zhouxy.plusone.commons.util.AssertTools;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 身份证号
|
* 身份证号
|
||||||
*/
|
*/
|
||||||
public abstract class IDCardNumber {
|
public interface IDCardNumber {
|
||||||
|
|
||||||
@Nonnull
|
static final char DEFAULT_REPLACED_CHAR = '*';
|
||||||
private final String value;
|
static final int DEFAULT_DISPLAY_FRONT = 1;
|
||||||
|
static final int DEFAULT_DISPLAY_END = 2;
|
||||||
|
|
||||||
private static final char DEFAULT_REPLACED_CHAR = '*';
|
String value();
|
||||||
private static final int DEFAULT_DISPLAY_FRONT = 1;
|
|
||||||
private static final int DEFAULT_DISPLAY_END = 2;
|
|
||||||
|
|
||||||
protected IDCardNumber(String value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final String getValue() {
|
|
||||||
return this.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据身份证号判断性别
|
* 根据身份证号判断性别
|
||||||
*/
|
*/
|
||||||
public abstract Gender getGender();
|
Gender getGender();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取出生日期
|
* 获取出生日期
|
||||||
*/
|
*/
|
||||||
public abstract LocalDate getBirthDate();
|
LocalDate getBirthDate();
|
||||||
|
|
||||||
/** 计算年龄 */
|
/** 计算年龄 */
|
||||||
public final int calculateAge() {
|
default int calculateAge() {
|
||||||
LocalDate now = LocalDate.now();
|
LocalDate now = LocalDate.now();
|
||||||
return Period.between(getBirthDate(), now).getYears();
|
return Period.between(getBirthDate(), now).getYears();
|
||||||
}
|
}
|
||||||
|
@ -63,23 +52,19 @@ public abstract class IDCardNumber {
|
||||||
// #region - toString
|
// #region - toString
|
||||||
// ================================
|
// ================================
|
||||||
|
|
||||||
@Override
|
default String toDesensitizedString() {
|
||||||
public String toString() {
|
|
||||||
return toDesensitizedString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toDesensitizedString() {
|
|
||||||
return toDesensitizedString(DEFAULT_REPLACED_CHAR, DEFAULT_DISPLAY_FRONT, DEFAULT_DISPLAY_END);
|
return toDesensitizedString(DEFAULT_REPLACED_CHAR, DEFAULT_DISPLAY_FRONT, DEFAULT_DISPLAY_END);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toDesensitizedString(int front, int end) {
|
default String toDesensitizedString(int front, int end) {
|
||||||
return toDesensitizedString(DEFAULT_REPLACED_CHAR, front, end);
|
return toDesensitizedString(DEFAULT_REPLACED_CHAR, front, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toDesensitizedString(char replacedChar, int front, int end) {
|
default String toDesensitizedString(char replacedChar, int front, int end) {
|
||||||
|
final String value = value();
|
||||||
AssertTools.checkArgument(front >= 0 && end >= 0);
|
AssertTools.checkArgument(front >= 0 && end >= 0);
|
||||||
AssertTools.checkArgument((front + end) <= this.value.length(), "需要截取的长度不能大于身份证号长度");
|
AssertTools.checkArgument((front + end) <= value.length(), "需要截取的长度不能大于身份证号长度");
|
||||||
final char[] charArray = getValue().toCharArray();
|
final char[] charArray = value.toCharArray();
|
||||||
for (int i = front; i < charArray.length - end; i++) {
|
for (int i = front; i < charArray.length - end; i++) {
|
||||||
charArray[i] = replacedChar;
|
charArray[i] = replacedChar;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,13 +26,14 @@ import java.util.regex.Matcher;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import xyz.zhouxy.plusone.commons.constant.PatternConsts;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class Chinese2ndGenIDCardNumberTests {
|
public class Chinese2ndGenIDCardNumberTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testPattern() {
|
void testPattern() {
|
||||||
Matcher matcher = Chinese2ndGenIDCardNumber.PATTERN.matcher("11010520000101111X");
|
Matcher matcher = PatternConsts.CHINESE_2ND_ID_CARD_NUMBER.matcher("11010520000101111X");
|
||||||
assertTrue(matcher.matches());
|
assertTrue(matcher.matches());
|
||||||
for (int i = 0; i < matcher.groupCount(); i++) {
|
for (int i = 0; i < matcher.groupCount(); i++) {
|
||||||
log.info("{}: {}", i, matcher.group(i));
|
log.info("{}: {}", i, matcher.group(i));
|
||||||
|
@ -42,7 +43,7 @@ public class Chinese2ndGenIDCardNumberTests {
|
||||||
@Test
|
@Test
|
||||||
void test() {
|
void test() {
|
||||||
Chinese2ndGenIDCardNumber idCardNumber = Chinese2ndGenIDCardNumber.of("11010520000101111X");
|
Chinese2ndGenIDCardNumber idCardNumber = Chinese2ndGenIDCardNumber.of("11010520000101111X");
|
||||||
assertEquals("11010520000101111X", idCardNumber.getValue());
|
assertEquals("11010520000101111X", idCardNumber.value());
|
||||||
assertEquals(LocalDate.of(2000, 1, 1), idCardNumber.getBirthDate());
|
assertEquals(LocalDate.of(2000, 1, 1), idCardNumber.getBirthDate());
|
||||||
assertEquals(Gender.MALE, idCardNumber.getGender());
|
assertEquals(Gender.MALE, idCardNumber.getGender());
|
||||||
assertEquals("110105", idCardNumber.getCountyCode());
|
assertEquals("110105", idCardNumber.getCountyCode());
|
||||||
|
|
Loading…
Reference in New Issue