From 1c98d05302f25842032640edc1a53eb131ae9fd7 Mon Sep 17 00:00:00 2001 From: ZhouXY108 Date: Fri, 29 Nov 2024 18:24:41 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20Chinese2ndGenIDCardNumber?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/Chinese2ndGenIDCardNumber.java | 86 +++++++++++++------ .../plusone/commons/model/IDCardNumber.java | 59 ++++++++++--- .../model/Chinese2ndGenIDCardNumberTests.java | 5 +- 3 files changed, 105 insertions(+), 45 deletions(-) diff --git a/src/main/java/xyz/zhouxy/plusone/commons/model/Chinese2ndGenIDCardNumber.java b/src/main/java/xyz/zhouxy/plusone/commons/model/Chinese2ndGenIDCardNumber.java index c6ad7a7..7fe9fdc 100644 --- a/src/main/java/xyz/zhouxy/plusone/commons/model/Chinese2ndGenIDCardNumber.java +++ b/src/main/java/xyz/zhouxy/plusone/commons/model/Chinese2ndGenIDCardNumber.java @@ -18,17 +18,23 @@ package xyz.zhouxy.plusone.commons.model; import java.time.LocalDate; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; +import com.google.errorprone.annotations.Immutable; + +import xyz.zhouxy.plusone.commons.annotation.ValueObject; +import xyz.zhouxy.plusone.commons.util.AssertTools; +import xyz.zhouxy.plusone.commons.util.StringTools; /** * 中国第二代居民身份证号 */ +@ValueObject +@Immutable public class Chinese2ndGenIDCardNumber extends IDCardNumber { /** 省份编码 */ @@ -42,35 +48,55 @@ public class Chinese2ndGenIDCardNumber extends IDCardNumber { /** 出生日期 */ private final LocalDate birthDate; - public static final Pattern PATTERN = Pattern.compile("^(((\\d{2})\\d{2})\\d{2})(\\d{8})\\d{2}(\\d)([\\dXx])$"); private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd"); - private Chinese2ndGenIDCardNumber(String idNumber) { - super(idNumber, PATTERN, "Invalid ID number"); + private Chinese2ndGenIDCardNumber(String value, String provinceCode, String cityCode, String countyCode, + Gender gender, LocalDate birthDate) { + super(value); + this.provinceCode = provinceCode; + this.cityCode = cityCode; + this.countyCode = countyCode; + this.gender = gender; + this.birthDate = birthDate; + } + + public static final Pattern PATTERN = Pattern.compile("^(?(?(?\\d{2})\\d{2})\\d{2})(?\\d{8})\\d{2}(?\\d)([\\dXx])$"); + + public static Chinese2ndGenIDCardNumber of(final String value) { + AssertTools.checkArgument(StringTools.isNotBlank(value), "二代居民身份证校验失败:号码为空"); + final String idNumber = value.toUpperCase(); + + final Matcher matcher = Chinese2ndGenIDCardNumber.PATTERN.matcher(idNumber); + AssertTools.checkArgument(matcher.matches(), () -> "二代居民身份证校验失败:" + value); + + final String provinceCode = matcher.group("province"); + AssertTools.checkArgument(Chinese2ndGenIDCardNumber.PROVINCE_CODES.containsKey(provinceCode)); + + final String cityCode = matcher.group("city"); + final String countyCode = matcher.group("county"); + + final Gender gender; + final LocalDate birthDate; try { - final Matcher matcher = getMatcher(); - this.provinceCode = matcher.group(3); - this.cityCode = matcher.group(2); - this.countyCode = matcher.group(1); + // 出生日期 + final String birthDateStr = matcher.group("birthDate"); + birthDate = LocalDate.parse(birthDateStr, DATE_FORMATTER); // 性别 - final String genderStr = matcher.group(5); - final int genderIndex = Integer.parseInt(genderStr); - this.gender = genderIndex % 2 == 0 ? Gender.FEMALE : Gender.MALE; - - // 出生日期 - final String birthDateStr = matcher.group(4); - this.birthDate = LocalDate.parse(birthDateStr, DATE_FORMATTER); + final int genderCode = Integer.parseInt(matcher.group("gender")); + gender = genderCode % 2 == 0 ? Gender.FEMALE : Gender.MALE; } - catch (DateTimeParseException e) { + catch (Exception e) { throw new IllegalArgumentException(e); } + + return new Chinese2ndGenIDCardNumber(idNumber, provinceCode, cityCode, countyCode, gender, birthDate); } - public static Chinese2ndGenIDCardNumber of(String idNumber) { - return new Chinese2ndGenIDCardNumber(idNumber); - } + // ================================ + // #region - reader methods + // ================================ public String getProvinceCode() { return provinceCode; @@ -110,15 +136,9 @@ public class Chinese2ndGenIDCardNumber extends IDCardNumber { return birthDate; } - @Override - public int hashCode() { - return super.hashCode(); - } - - @Override - public boolean equals(Object obj) { - return super.equals(obj); - } + // ================================ + // #endregion - reader methods + // ================================ /** * 省份代码表 @@ -165,4 +185,14 @@ public class Chinese2ndGenIDCardNumber extends IDCardNumber { .put("91", "国外") .build(); } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj); + } } diff --git a/src/main/java/xyz/zhouxy/plusone/commons/model/IDCardNumber.java b/src/main/java/xyz/zhouxy/plusone/commons/model/IDCardNumber.java index f6e3114..361e0cc 100644 --- a/src/main/java/xyz/zhouxy/plusone/commons/model/IDCardNumber.java +++ b/src/main/java/xyz/zhouxy/plusone/commons/model/IDCardNumber.java @@ -18,29 +18,29 @@ package xyz.zhouxy.plusone.commons.model; import java.time.LocalDate; import java.time.Period; -import java.util.function.Supplier; -import java.util.regex.Pattern; import javax.annotation.Nonnull; +import xyz.zhouxy.plusone.commons.util.AssertTools; + /** * 身份证号 */ -public abstract class IDCardNumber extends ValidatableStringRecord { +public abstract class IDCardNumber { - protected IDCardNumber(@Nonnull String idNumber, @Nonnull Pattern pattern) - throws IllegalArgumentException{ - super(idNumber, pattern); + @Nonnull + private final String value; + + private static final char DEFAULT_REPLACED_CHAR = '*'; + private static final int DEFAULT_DISPLAY_FRONT = 1; + private static final int DEFAULT_DISPLAY_END = 2; + + protected IDCardNumber(String value) { + this.value = value; } - protected IDCardNumber(@Nonnull String idNumber, @Nonnull Pattern pattern, - @Nonnull String errorMessage) { - super(idNumber, pattern, errorMessage); - } - - protected IDCardNumber(@Nonnull String idNumber, @Nonnull Pattern pattern, - @Nonnull Supplier errorMessage) { - super(idNumber, pattern, errorMessage); + public final String getValue() { + return this.value; } /** @@ -58,4 +58,35 @@ public abstract class IDCardNumber extends ValidatableStringRecord { LocalDate now = LocalDate.now(); return Period.between(getBirthDate(), now).getYears(); } + + // ================================ + // #region - toString + // ================================ + + @Override + public String toString() { + return toDesensitizedString(); + } + + public String toDesensitizedString() { + return toDesensitizedString(DEFAULT_REPLACED_CHAR, DEFAULT_DISPLAY_FRONT, DEFAULT_DISPLAY_END); + } + + public String toDesensitizedString(int front, int end) { + return toDesensitizedString(DEFAULT_REPLACED_CHAR, front, end); + } + + public String toDesensitizedString(char replacedChar, int front, int end) { + AssertTools.checkArgument(front >= 0 && end >= 0); + AssertTools.checkArgument((front + end) <= this.value.length(), "需要截取的长度不能大于身份证号长度"); + final char[] charArray = getValue().toCharArray(); + for (int i = front; i < charArray.length - end; i++) { + charArray[i] = replacedChar; + } + return String.valueOf(charArray); + } + + // ================================ + // #endregion - toString + // ================================ } diff --git a/src/test/java/xyz/zhouxy/plusone/commons/model/Chinese2ndGenIDCardNumberTests.java b/src/test/java/xyz/zhouxy/plusone/commons/model/Chinese2ndGenIDCardNumberTests.java index 7002115..ddeeda6 100644 --- a/src/test/java/xyz/zhouxy/plusone/commons/model/Chinese2ndGenIDCardNumberTests.java +++ b/src/test/java/xyz/zhouxy/plusone/commons/model/Chinese2ndGenIDCardNumberTests.java @@ -40,9 +40,9 @@ public class Chinese2ndGenIDCardNumberTests { } @Test - void test() throws CloneNotSupportedException { + void test() { Chinese2ndGenIDCardNumber idCardNumber = Chinese2ndGenIDCardNumber.of("11010520000101111X"); - assertEquals("11010520000101111X", idCardNumber.value()); + assertEquals("11010520000101111X", idCardNumber.getValue()); assertEquals(LocalDate.of(2000, 1, 1), idCardNumber.getBirthDate()); assertEquals(Gender.MALE, idCardNumber.getGender()); assertEquals("110105", idCardNumber.getCountyCode()); @@ -66,7 +66,6 @@ public class Chinese2ndGenIDCardNumberTests { Chinese2ndGenIDCardNumber.of("11010520002101111X"); } catch (IllegalArgumentException e) { - log.error(e.getMessage(), e); assertTrue(e.getCause() instanceof DateTimeParseException); } }