使用Spring Boot实现居民身份证合法性验证
在现代社会中,身份证号码的合法性验证是很多系统中不可或缺的一部分。身份证号码用于确认个人身份,其格式和校验机制各不相同。本文将介绍如何使用Spring Boot构建一个通用控制器,通过API来验证中国大陆、台湾、澳门和香港居民的身份证号码合法性。
代码概述
本文的核心代码是一个Spring Boot控制器CommonController
,它提供了一个API用于验证身份证号码的合法性。以下是该控制器的完整代码:
@SuppressWarnings("AlibabaUndefineMagicConstant")
@Tag(name = "通用控制器", description = "通用控制器")
@RestController
@RequestMapping("/common")
public class CommonController {@Autowiredprivate ICommonService commonService;/*** 每一位的权重*/private static final int[] WEIGHT = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};/*** 校验码对应表*/private static final char[] CHECK_CODE = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};/*** 正则表达式匹配澳门身份证号码*/private static final Pattern MACAU_ID_PATTERN = Pattern.compile("[1|5|7][0-9]{6}\\(?[0-9A-Z]\\)?");/*** 居民身份证合法性验证** @param idCard 身份证号码* @return ValidationResultModel*/@Operation(summary = "居民身份证合法性验证", description = "居民身份证合法性验证")@Parameter(name = "idCard", description = "居民身份证号码", required = true, in = ParameterIn.QUERY)@GetMapping("/validateID")public ApiResult<ValidationResultModel> validateIdCard(@RequestParam("idCard") String idCard) throws ParseException {IDCardType idCardType = determineIdCardType(idCard);switch (idCardType) {case MAINLAND:return validateMainlandId(idCard);case TAIWAN:return validateTaiwanId(idCard);case MACAU:return validateMacauId(idCard);case HONGKONG:return validateHongKongId(idCard);default:ValidationResultModel invalid = new ValidationResultModel();invalid.setValid(false);invalid.setMessage("身份证件号码无效,请仔细核对后重新输入!");return ApiResult.ok(invalid);}}private IDCardType determineIdCardType(String idCard) {if (idCard.matches("[1-9][0-9]{5}(19[0-9]{2}|20[0-9]{2})(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])[0-9]{3}[0-9Xx]")) {return IDCardType.MAINLAND;} else if (idCard.matches("[A-Z][0-9]{9}")) {return IDCardType.TAIWAN;} else if (idCard.matches("[1|5|7][0-9]{6}\\(?[0-9A-Z]\\)?")) {return IDCardType.MACAU;} else if (idCard.matches("[A-Z]{1,2}[0-9]{6}\\(?[0-9A]\\)?")) {return IDCardType.HONGKONG;} else {return IDCardType.UNKNOWN;}}enum IDCardType {MAINLAND,TAIWAN,MACAU,HONGKONG,UNKNOWN}private static char getCheckCode(String idCard17) {int sum = 0;for (int i = 0; i < 17; i++) {sum += (idCard17.charAt(i) - '0') * WEIGHT[i];}return CHECK_CODE[sum % 11];}public boolean validateTaiwanId(String id) {if (id == null || !id.matches("[A-Z][0-9]{9}")) {return false;}char letter = id.charAt(0);int letterValue = LETTER_TO_NUMBER_MAP.get(letter);int letter1 = letterValue / 10;int letter2 = letterValue % 10;int sum = letter1 + letter2 * 9;int[] weights = {8, 7, 6, 5, 4, 3, 2, 1};for (int i = 0; i < 8; i++) {sum += Character.getNumericValue(id.charAt(i + 1)) * weights[i];}sum += Character.getNumericValue(id.charAt(9));return sum % 10 == 0;}private static final Map<Character, Integer> LETTER_TO_NUMBER_MAP = new HashMap<>();static {LETTER_TO_NUMBER_MAP.put('A', 10);LETTER_TO_NUMBER_MAP.put('B', 11);LETTER_TO_NUMBER_MAP.put('C', 12);LETTER_TO_NUMBER_MAP.put('D', 13);LETTER_TO_NUMBER_MAP.put('E', 14);LETTER_TO_NUMBER_MAP.put('F', 15);LETTER_TO_NUMBER_MAP.put('G', 16);LETTER_TO_NUMBER_MAP.put('H', 17);LETTER_TO_NUMBER_MAP.put('J', 18);LETTER_TO_NUMBER_MAP.put('K', 19);LETTER_TO_NUMBER_MAP.put('L', 20);LETTER_TO_NUMBER_MAP.put('M', 21);LETTER_TO_NUMBER_MAP.put('N', 22);LETTER_TO_NUMBER_MAP.put('P', 23);LETTER_TO_NUMBER_MAP.put('Q', 24);LETTER_TO_NUMBER_MAP.put('R', 25);LETTER_TO_NUMBER_MAP.put('S', 26);LETTER_TO_NUMBER_MAP.put('T', 27);LETTER_TO_NUMBER_MAP.put('U', 28);LETTER_TO_NUMBER_MAP.put('V', 29);LETTER_TO_NUMBER_MAP.put('W', 30);LETTER_TO_NUMBER_MAP.put('X', 31);LETTER_TO_NUMBER_MAP.put('Y', 32);LETTER_TO_NUMBER_MAP.put('Z', 33);}public static boolean validateMacauId(String id) {if (id == null || !MACAU_ID_PATTERN.matcher(id).matches()) {return false;}int[] weights = {8, 7, 6, 5, 4, 3, 2, 1};int sum = 0;for (int i = 0; i < 7; i++) {char c = id.charAt(i);sum += Character.getNumericValue(c) * weights[i];}char checkChar = id.charAt(7);int checkCode;if (checkChar == 'A') {checkCode = 10;} else {checkCode = Character.getNumericValue(checkChar);}return (sum + checkCode) % 11 == 0;}public static boolean validateHongKongId(String id) {if (id == null || !id.matches("[A-Z]{1,2}[0-9]{6}\\(?[0-9A]\\)?")) {return false;}id = id.replace("(", "").replace(")", "");if (id.length() == 8) {id = " " + id;}if (id.length() != 9) {return false;}int[] weights = {9, 8, 7, 6, 5, 4, 3, 2, 1};int total = 0;for (int i = 0; i < 9; i++) {total += charToValue(id.charAt(i)) * weights[i];}int remainder = total % 11;char checkDigit = id.charAt(id.length() - 1);if (remainder == 0) {return checkDigit == '0';} else if (remainder == 1) {return Character.toUpperCase(checkDigit) == 'A';} else {return checkDigit == Character.forDigit(11 - remainder, 10);}}private static int charToValue(char c) {if (c == ' ') {return 36;} else if (Character.isLetter(c)) {return Character.toUpperCase(c) - 55;} else {return Character.getNumericValue(c);}}
}
功能解析
1. 主要组件
注解
@Tag
:用于Swagger文档生成,定义了控制器的名称和描述。@RestController
:表明该类是一个控制器,并且每个方法都会返回一个对象,这些对象会自动转换为JSON格式。@RequestMapping
:定义了基础路径为/common
,即所有的请求都以该
路径为前缀。
自动注入
@Autowired
:自动注入了一个服务接口ICommonService
,用于业务逻辑的处理。
2. 常量
身份证校验相关常量
WEIGHT
:大陆居民身份证每位数字的权重,用于校验码计算。CHECK_CODE
:校验码对照表,根据前17位的计算结果获取校验码。MACAU_ID_PATTERN
:用于匹配澳门身份证号码的正则表达式。
3. 方法
validateIdCard
- 接收一个身份证号码,并根据其类型调用相应的校验方法。
- 校验类型包括大陆、台湾、澳门、香港的身份证号码。
determineIdCardType
- 根据身份证号码的格式判断其类型(大陆、台湾、澳门、香港、未知)。
4. 身份证校验方法
getCheckCode
:计算大陆居民身份证前17位的校验码。validateTaiwanId
:校验台湾身份证号码是否合法。validateMacauId
:校验澳门身份证号码是否合法。validateHongKongId
:校验香港身份证号码是否合法。
详细说明
居民身份证合法性验证
大陆身份证
大陆居民身份证号码为18位数字,前17位为出生日期、地区代码等信息,第18位为校验码。校验码根据前17位数字计算得出:
private static char getCheckCode(String idCard17) {int sum = 0;for (int i = 0; i < 17; i++) {sum += (idCard17.charAt(i) - '0') * WEIGHT[i];}return CHECK_CODE[sum % 11];
}
台湾身份证
台湾身份证号码为10位,第一位为字母,表示地区,后9位为数字。校验时需要将字母转换为对应的数字,并根据特定权重计算总和:
public boolean validateTaiwanId(String id) {if (id == null || !id.matches("[A-Z][0-9]{9}")) {return false;}char letter = id.charAt(0);int letterValue = LETTER_TO_NUMBER_MAP.get(letter);int letter1 = letterValue / 10;int letter2 = letterValue % 10;int sum = letter1 + letter2 * 9;int[] weights = {8, 7, 6, 5, 4, 3, 2, 1};for (int i = 0; i < 8; i++) {sum += Character.getNumericValue(id.charAt(i + 1)) * weights[i];}sum += Character.getNumericValue(id.charAt(9));return sum % 10 == 0;
}
澳门身份证
澳门身份证号码为9位,前7位为数字,第8位为校验码。需要根据特定权重计算校验码:
public static boolean validateMacauId(String id) {if (id == null || !MACAU_ID_PATTERN.matcher(id).matches()) {return false;}int[] weights = {8, 7, 6, 5, 4, 3, 2, 1};int sum = 0;for (int i = 0; i < 7; i++) {char c = id.charAt(i);sum += Character.getNumericValue(c) * weights[i];}char checkChar = id.charAt(7);int checkCode;if (checkChar == 'A') {checkCode = 10;} else {checkCode = Character.getNumericValue(checkChar);}return (sum + checkCode) % 11 == 0;
}
香港身份证
香港身份证号码由8或9位组成,前1-2位为字母,后6位为数字,最后一位为校验码。需要根据特定权重计算校验码:
public static boolean validateHongKongId(String id) {if (id == null || !id.matches("[A-Z]{1,2}[0-9]{6}\\(?[0-9A]\\)?")) {return false;}id = id.replace("(", "").replace(")", "");if (id.length() == 8) {id = " " + id;}if (id.length() != 9) {return false;}int[] weights = {9, 8, 7, 6, 5, 4, 3, 2, 1};int total = 0;for (int i = 0; i < 9; i++) {total += charToValue(id.charAt(i)) * weights[i];}int remainder = total % 11;char checkDigit = id.charAt(id.length() - 1);if (remainder == 0) {return checkDigit == '0';} else if (remainder == 1) {return Character.toUpperCase(checkDigit) == 'A';} else {return checkDigit == Character.forDigit(11 - remainder, 10);}
}
总结
本文介绍了如何使用Spring Boot构建一个通用控制器,通过API来验证中国大陆、台湾、澳门和香港居民的身份证号码合法性。通过具体的代码示例,详细解释了不同地区身份证号码的校验逻辑。希望这篇文章对您在实际开发中有所帮助。