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 7fe9fdc..d43fa6f 100644 --- a/src/main/java/xyz/zhouxy/plusone/commons/model/Chinese2ndGenIDCardNumber.java +++ b/src/main/java/xyz/zhouxy/plusone/commons/model/Chinese2ndGenIDCardNumber.java @@ -16,26 +16,39 @@ package xyz.zhouxy.plusone.commons.model; +import java.io.Serializable; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.Map; +import java.util.Objects; 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.ReaderMethod; 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.StringTools; /** + * Chinese2ndGenIDCardNumber + * + *

* 中国第二代居民身份证号 + *

+ * + * @author ZhouXY + * @since 1.0 + * @see xyz.zhouxy.plusone.commons.constant.PatternConsts#CHINESE_2ND_ID_CARD_NUMBER */ @ValueObject @Immutable -public class Chinese2ndGenIDCardNumber extends IDCardNumber { +public class Chinese2ndGenIDCardNumber implements IDCardNumber, Serializable { + + private final String value; /** 省份编码 */ private final String provinceCode; @@ -52,7 +65,7 @@ public class Chinese2ndGenIDCardNumber extends IDCardNumber { private Chinese2ndGenIDCardNumber(String value, String provinceCode, String cityCode, String countyCode, Gender gender, LocalDate birthDate) { - super(value); + this.value = value; this.provinceCode = provinceCode; this.cityCode = cityCode; this.countyCode = countyCode; @@ -60,13 +73,11 @@ public class Chinese2ndGenIDCardNumber extends IDCardNumber { 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); + final Matcher matcher = PatternConsts.CHINESE_2ND_ID_CARD_NUMBER.matcher(idNumber); AssertTools.checkArgument(matcher.matches(), () -> "二代居民身份证校验失败:" + value); final String provinceCode = matcher.group("province"); @@ -98,39 +109,53 @@ public class Chinese2ndGenIDCardNumber extends IDCardNumber { // #region - reader methods // ================================ + @ReaderMethod + public String value() { + return value; + } + + @ReaderMethod public String getProvinceCode() { return provinceCode; } + @ReaderMethod public String getProvinceName() { return PROVINCE_CODES.get(this.provinceCode); } + @ReaderMethod public String getFullProvinceCode() { return Strings.padEnd(this.provinceCode, 12, '0'); } + @ReaderMethod public String getCityCode() { return cityCode; } + @ReaderMethod public String getFullCityCode() { return Strings.padEnd(this.cityCode, 12, '0'); } + @ReaderMethod public String getCountyCode() { return countyCode; } + @ReaderMethod public String getFullCountyCode() { return Strings.padEnd(this.countyCode, 12, '0'); } + @ReaderMethod @Override public Gender getGender() { return gender; } + @ReaderMethod @Override public LocalDate getBirthDate() { return birthDate; @@ -188,11 +213,18 @@ public class Chinese2ndGenIDCardNumber extends IDCardNumber { @Override public int hashCode() { - return super.hashCode(); + return Objects.hashCode(value); } @Override 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; } 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 361e0cc..76dcf1a 100644 --- a/src/main/java/xyz/zhouxy/plusone/commons/model/IDCardNumber.java +++ b/src/main/java/xyz/zhouxy/plusone/commons/model/IDCardNumber.java @@ -19,42 +19,31 @@ package xyz.zhouxy.plusone.commons.model; import java.time.LocalDate; import java.time.Period; -import javax.annotation.Nonnull; - import xyz.zhouxy.plusone.commons.util.AssertTools; /** * 身份证号 */ -public abstract class IDCardNumber { +public interface IDCardNumber { - @Nonnull - private final String value; + static final char DEFAULT_REPLACED_CHAR = '*'; + static final int DEFAULT_DISPLAY_FRONT = 1; + static final int DEFAULT_DISPLAY_END = 2; - 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; - } - - public final String getValue() { - return this.value; - } + String value(); /** * 根据身份证号判断性别 */ - public abstract Gender getGender(); + Gender getGender(); /** * 获取出生日期 */ - public abstract LocalDate getBirthDate(); + LocalDate getBirthDate(); /** 计算年龄 */ - public final int calculateAge() { + default int calculateAge() { LocalDate now = LocalDate.now(); return Period.between(getBirthDate(), now).getYears(); } @@ -63,23 +52,19 @@ public abstract class IDCardNumber { // #region - toString // ================================ - @Override - public String toString() { - return toDesensitizedString(); - } - - public String toDesensitizedString() { + default String toDesensitizedString() { 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); } - 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 + end) <= this.value.length(), "需要截取的长度不能大于身份证号长度"); - final char[] charArray = getValue().toCharArray(); + AssertTools.checkArgument((front + end) <= value.length(), "需要截取的长度不能大于身份证号长度"); + final char[] charArray = value.toCharArray(); for (int i = front; i < charArray.length - end; i++) { charArray[i] = replacedChar; } 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 ddeeda6..40bd5dc 100644 --- a/src/test/java/xyz/zhouxy/plusone/commons/model/Chinese2ndGenIDCardNumberTests.java +++ b/src/test/java/xyz/zhouxy/plusone/commons/model/Chinese2ndGenIDCardNumberTests.java @@ -26,13 +26,14 @@ import java.util.regex.Matcher; import org.junit.jupiter.api.Test; import lombok.extern.slf4j.Slf4j; +import xyz.zhouxy.plusone.commons.constant.PatternConsts; @Slf4j public class Chinese2ndGenIDCardNumberTests { @Test void testPattern() { - Matcher matcher = Chinese2ndGenIDCardNumber.PATTERN.matcher("11010520000101111X"); + Matcher matcher = PatternConsts.CHINESE_2ND_ID_CARD_NUMBER.matcher("11010520000101111X"); assertTrue(matcher.matches()); for (int i = 0; i < matcher.groupCount(); i++) { log.info("{}: {}", i, matcher.group(i)); @@ -42,7 +43,7 @@ public class Chinese2ndGenIDCardNumberTests { @Test void test() { Chinese2ndGenIDCardNumber idCardNumber = Chinese2ndGenIDCardNumber.of("11010520000101111X"); - assertEquals("11010520000101111X", idCardNumber.getValue()); + assertEquals("11010520000101111X", idCardNumber.value()); assertEquals(LocalDate.of(2000, 1, 1), idCardNumber.getBirthDate()); assertEquals(Gender.MALE, idCardNumber.getGender()); assertEquals("110105", idCardNumber.getCountyCode());