目標
自定義一個用于校驗 身份證號碼
格式的注解@IdCard
,能夠和現(xiàn)有的 Validation
參數(shù)校驗機制兼容,使用方式和其他校驗注解保持一致(使用 @Valid
注解接口參數(shù))。
本文使用原生方式實現(xiàn)校驗邏輯,校驗規(guī)則的實現(xiàn)較為基礎;Hutool工具提供了更加完善的校驗工具,可以考慮使用其來實現(xiàn)校驗邏輯。
使用 Hutool 身份證號碼格式校驗工具,實現(xiàn)校驗邏輯,參考博客如下:
《身份證號碼,格式校驗:@IdCard(Validation + Hutool)》
校驗邏輯
有效格式
符合國家標準。
公民身份號碼按照GB11643-1999《公民身份號碼》國家標準編制,由18位數(shù)字組成:前6位為行政區(qū)劃代碼,第7至14位為出生日期碼,第15至17位為順序碼,第18位為校驗碼。
嚴格校驗
本文采用的校驗方式,采用嚴格校驗,第18位校驗碼
,只能為數(shù)字
或大寫X
,小寫x
無法通過校驗。
不校驗非空
身份證號碼注解,校驗的是格式
;不校驗是否為空(null 或 空字符串)。如果身份證號碼為空,此注解校驗是可以通過的;
是否校驗非空
,要根據(jù)業(yè)務邏輯
來確定;如果業(yè)務邏輯需要校驗非空,則使用注解 @NotEmpty
。
核心代碼
需要定義的內容包含三個部分:
- 注解
@IdCard
- 校驗器
IdCardValidator
- 校驗工具類
IdCardUtil
注解:@IdCard
package com.example.core.validation.idcard;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 身份證號碼。字符串必須是格式正確的身份證號碼。
* <p>
* {@code null} 或 空字符串,是有效的(能夠通過校驗)。
* <p>
* 支持的類型:字符串
*
* @author songguanxun
* @since 1.0
*/
@Target({FIELD})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = IdCardValidator.class)
public @interface IdCard {
/**
* @return the error message template
*/
String message() default "身份證號碼,格式錯誤";
/**
* @return the groups the constraint belongs to
*/
Class<?>[] groups() default {};
/**
* @return the payload associated to the constraint
*/
Class<? extends Payload>[] payload() default {};
}
校驗器:IdCardValidator
package com.example.core.validation.idcard;
import com.example.core.util.IdCardUtil;
import org.springframework.util.ObjectUtils;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
* 身份證號碼,格式校驗器
*/
public class IdCardValidator implements ConstraintValidator<IdCard, String> {
@Override
public void initialize(IdCard constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation);
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (ObjectUtils.isEmpty(value)) {
return true;
}
return IdCardUtil.isValid(value);
}
}
校驗工具類
package com.example.core.util;
/**
* 身份證號碼,校驗工具類
*/
public class IdCardUtil {
// 每位加權因子
private static final int[] power = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
/**
* 是格式正確的身份證號碼
*/
public static boolean isValid(String idCard) {
// null ,為假
if (idCard == null) {
return false;
}
// 非18位,為假
if (idCard.length() != 18) {
return false;
}
// 獲取前17位
String idCard17 = idCard.substring(0, 17);
// 獲取第18位
String idCard18Code = idCard.substring(17, 18);
// 前17位,不全部為數(shù)字,為假
if (!isDigital(idCard17)) {
return false;
}
char[] c = idCard17.toCharArray();
int[] bit = convertCharToInt(c);
int sum17 = getPowerSum(bit);
// 將和值與11取模得到余數(shù)進行校驗碼判斷
String checkCode = getCheckCodeBySum(sum17);
if (null == checkCode) {
return false;
}
// 將身份證的第18位,與算出來的校碼進行匹配,不相等就為假
return idCard18Code.equals(checkCode);
}
/**
* 數(shù)字驗證
*/
private static boolean isDigital(String str) {
return str != null && !str.isEmpty() && str.matches("^[0-9]*$");
}
/**
* 將字符數(shù)組轉為整型數(shù)組
*/
private static int[] convertCharToInt(char[] c) throws NumberFormatException {
int[] a = new int[c.length];
int k = 0;
for (char temp : c) {
a[k++] = Integer.parseInt(String.valueOf(temp));
}
return a;
}
/**
* 將身份證的每位和對應位的加權因子相乘之后,再得到和值
*/
private static int getPowerSum(int[] bit) {
if (power.length != bit.length) {
return 0;
}
int sum = 0;
for (int i = 0; i < bit.length; i++) {
for (int j = 0; j < power.length; j++) {
if (i == j) {
sum = sum + bit[i] * power[j];
}
}
}
return sum;
}
/**
* 將和值與11取模得到余數(shù)進行校驗碼判斷
*
* @return 校驗位
*/
private static String getCheckCodeBySum(int sum17) {
String checkCode = null;
switch (sum17 % 11) {
case 10:
checkCode = "2";
break;
case 9:
checkCode = "3";
break;
case 8:
checkCode = "4";
break;
case 7:
checkCode = "5";
break;
case 6:
checkCode = "6";
break;
case 5:
checkCode = "7";
break;
case 4:
checkCode = "8";
break;
case 3:
checkCode = "9";
break;
case 2:
checkCode = "X";
break;
case 1:
checkCode = "0";
break;
case 0:
checkCode = "1";
break;
}
return checkCode;
}
}
使用
@IdCard
放在需要校驗格式的 身份證號碼
字段上。
package com.example.web.response.model.param;
import com.example.core.validation.idcard.IdCard;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(name = "新增用戶Param")
public class UserAddParam {
// 其他字段
@IdCard
@Schema(description = "身份證號碼", example = "110101202301024130")
private String idCard;
}
校驗效果
校驗工具類,單元測試
package com.example;
import com.example.core.util.IdCardUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
@Slf4j
public class IdCardTest {
@Test
void test() {
test("110101202301024130");
test("11010120230102857X");
test("11010120230102857x");
test("110101202301024130啊啊啊啊");
}
private void test(String idCard) {
log.info("是否為身份證號碼格式:{} = {}", idCard, IdCardUtil.isValid(idCard));
}
}
接口測試
校驗結果為 成功
校驗結果為 失敗
文章來源:http://www.zghlxwxcb.cn/news/detail-726362.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-726362.html
到了這里,關于身份證號碼,格式校驗:@IdCard(Validation + 原生實現(xiàn)校驗邏輯)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!