当前位置: 首页 > news >正文

身份证号码,格式校验:@IdCard(自定义注解)

目标

自定义一个用于校验 身份证号码 格式的注解@IdCard,能够和现有的 Validation 兼容,使用方式和其他校验注解保持一致(使用 @Valid 注解接口参数)。

校验逻辑

有效格式

符合国家标准。

公民身份号码按照GB11643-1999《公民身份号码》国家标准编制,由18位数字组成:前6位为行政区划代码,第7至14位为出生日期码,第15至17位为顺序码,第18位为校验码。

严格校验

本文采用的校验方式,采用严格校验,第18位校验码,只能为数字大写X小写x无法通过校验。

不校验非空

身份证号码,校验的是格式;不校验是否为空(null 或 空字符串)。如果身份证号码为空,直接通过校验;

核心代码

需要定义的内容包含三个部分:

  1. 注解@ZipCode
  2. 校验器ZipCodeValidator
  3. 校验工具类 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> {@Overridepublic void initialize(IdCard constraintAnnotation) {ConstraintValidator.super.initialize(constraintAnnotation);}@Overridepublic 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位,不全部为数字,为假if (!isDigital(idCard17)) {return false;}char[] c = idCard17.toCharArray();int[] bit = convertCharToInt(c);int sum17 = getPowerSum(bit);// 将和值与11取模得到余数进行校验码判断String checkCode = getCheckCodeBySum(sum17);if (null == checkCode) {return false;}// 将身份证的第18位,与算出来的校码进行匹配,不相等就为假return idCard18Code.equals(checkCode);}/*** 数字验证*/private static boolean isDigital(String str) {return str != null && !str.isEmpty() && str.matches("^[0-9]*$");}/*** 将字符数组转为整型数组*/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取模得到余数进行校验码判断** @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 {@Testvoid test() {test("110101202301024130");test("11010120230102857X");test("11010120230102857x");test("110101202301024130啊啊啊啊");}private void test(String idCard) {log.info("是否为身份证号码格式:{} = {}", idCard, IdCardUtil.isValid(idCard));}}

在这里插入图片描述

接口测试

校验结果为 成功

在这里插入图片描述
在这里插入图片描述

校验结果为 失败

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

相关文章:

身份证号码,格式校验:@IdCard(自定义注解)

目标 自定义一个用于校验 身份证号码 格式的注解IdCard&#xff0c;能够和现有的 Validation 兼容&#xff0c;使用方式和其他校验注解保持一致&#xff08;使用 Valid 注解接口参数&#xff09;。 校验逻辑 有效格式 符合国家标准。 公民身份号码按照GB11643&#xff0d;…...

【Java】instanceof 关键字

instanceof 通过返回一个布尔值来指出&#xff0c;某个对象是否是某个特定类或者是该特定类的子类的一个实例。 如果 object 是class 的一个实例&#xff0c;则 instanceof 运算符返回 true&#xff0c;如果 object 不是指定类的一个实例&#xff0c;或者object 是null, 则返回…...

Android 13.0 recovery出厂时正在清理字体大小的修改

1.前言 在13.0的系统rom定制化开发中,在系统中recovery模块也是系统中比较重要的模块,比如恢复出厂设置,recovery ota升级,清理缓存等等, 在一些1080p的设备,但是density只是240这样的设备,会在恢复出厂设置的时候,显示的字体有点小,产品要求需要将正在清理的字体调大…...

京东商品数据:8月京东环境电器行业数据分析

8月份&#xff0c;环境电器大盘市场整体下滑。鲸参谋数据显示&#xff0c;8月京东平台环境电器的大盘将近570万&#xff0c;环比下滑约29%&#xff0c;同比下滑约10%&#xff1b;销售额为25亿&#xff0c;环比下滑约23%&#xff0c;同比下滑约8%。 *数据源于鲸参谋-行业趋势分析…...

elasticsearch(ES)分布式搜索引擎04——(数据聚合,自动补全,数据同步,ES集群)

目录 1.数据聚合1.1.聚合的种类1.2.DSL实现聚合1.2.1.Bucket聚合语法1.2.2.聚合结果排序1.2.3.限定聚合范围1.2.4.Metric聚合语法1.2.5.小结 1.3.RestAPI实现聚合1.3.1.API语法1.3.2.业务需求1.3.3.业务实现 2.自动补全2.1.拼音分词器2.2.自定义分词器2.3.自动补全查询2.4.实现…...

webdriver.Chrome()没反应

今天学习爬虫安装selenium之后刚开始webdriver.Chrome()正常 后面运行突然卡在这一步了 百度发现是版本不匹配 我们下载旧版本的chrome Download Google Chrome 95.0.4638.69 for Windows - Filehippo.com 禁用chrome的自动更新 打开文件所在位置 点击Google文件夹 右键up…...

java html转word、pdf(包含图片)

html转word maven依赖 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.14</version> </dependency> <dependency><groupId>org.jsoup</groupId><artifactId>…...

不容易解的题10.10

5.最长回文子串 5. 最长回文子串 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/longest-palindromic-substring/?envTypelist&envIdZCa7r67M给一个字符串&#xff0c;让我们找最长回文子串 这题不用说&#xff0c;回文子串那一定是连续的&#…...

淘宝天猫店铺所有商品数据接口,淘宝API接口

获取淘宝店铺所有商品数据接口的步骤如下&#xff1a; 获取授权&#xff1a;使用 OAuth 2.0 协议对应用进行授权&#xff0c;以便能够访问店铺的商品信息。获取店铺信息&#xff1a;使用淘宝 API 的 taobao.shop.get 接口&#xff0c;传入店铺的 user_id 参数&#xff0c;获取…...

Prometheus和grafana安装配置手册

1.简介 本文档为prometheus和grafana安装配置手册&#xff0c;prometheus和grafana的内容、和操作过程&#xff0c;详细介绍了服务监控配置、dashboard配置、告警配置等操作。 2.部署说明 Prometheus基于Golang编写&#xff08;需要安装&#xff09;&#xff0c;编译后的软件…...

从零开始探索C语言(十一)----共用体和位域

文章目录 1. 共用体1.1 定义共用体1.2 访问共用体成员 2. 位域2.1 位域声明2.2 位域的定义和位域变量的说明2.3 位域的使用2.4 位域小结 1. 共用体 共用体是一种特殊的数据类型&#xff0c;允许您在相同的内存位置存储不同的数据类型。您可以定义一个带有多成员的共用体&#…...

【数据结构】算法的时间复杂度

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 一.算法时间复杂度定义 二.大O阶渐近表示法 &#x1f38f;大O阶渐近表示法的定义 &#x1f38f;推导大O阶方法 三.常见的时间复杂度 &#x1f4cc;常数阶 &#x…...

Qt作业五

1、思维导图 https://www.zhixi.com/view/9e899ee0 2、作业 #include <iostream>using namespace std;class Animal { private:string name; public:Animal(){}Animal(string n):name(n){}virtual void perform()0; };class Lion:public Animal { public:void perform…...

【面试】pc寄存器题

目录 1.使用pc寄存器存储字节码指令地址有什么作用&#xff1f;&#xff08;为什么使用pc寄存器记录当前线程的执行地址&#xff1f;&#xff09;2.pc寄存器为什么被设定为线程私有的&#xff1f; 1.使用pc寄存器存储字节码指令地址有什么作用&#xff1f;&#xff08;为什么使…...

ARM按键中断实验

设置按键中断&#xff0c;按键1按下&#xff0c;LED亮&#xff0c;再按一次&#xff0c;灭 按键2按下&#xff0c;蜂鸣器响。再按一次&#xff0c;不响 按键3按下&#xff0c;风扇转&#xff0c;再按一次&#xff0c;风扇停 src/do_irq.c #include "key_it.h" ex…...

C#的值类型和引用类型

不得不说c#的类型系统设计有点意思&#xff0c;不同的编程语言对于类型的设计各有取舍。 值类型&#xff1a; 当我们将一个int类型的值赋值到另一个int类型的值时&#xff0c;它实际上是创建了一个完全不同的副本。换句话说&#xff0c;如果你改变了其中某一个的值&#xff0…...

YOLOv7改进:极简的神经网络模型 VanillaNet---VanillaBlock助力检测,实现暴力涨点 | 华为诺亚2023

💡💡💡本文属于原创独家改进:极简模块VanillaBlock,以极简主义的设计为理念,网络中仅仅包含最简单的卷积计算,去掉了残差和注意力模块,二次创新引入到YOLOv7中取得了不俗的效果。 极简模块VanillaBlock | 亲测在多个数据集实现涨点; 收录: YOLOv7高阶自研专…...

对验证码的识别爆破

声明&#xff1a;该系列文章首发于公众号&#xff1a;Y1X1n安全&#xff0c;转载请注明出处&#xff01;本公众号所分享内容仅用于每一个爱好者之间的技术讨论及教育目的&#xff0c;所有渗透及工具的使用都需获取授权&#xff0c;禁止用于违法途径&#xff0c;否则需自行承担&…...

LeetCode【15】三数之和

题目&#xff1a; 解析&#xff1a; 参考&#xff1a;https://zhuanlan.zhihu.com/p/111715985 代码&#xff1a; public static List<List<Integer>> threeSum(int[] nums) {// 先排序Arrays.sort(nums);List<List<Integer>> result new ArrayLis…...

Gossip协议是什么

Gossip协议是什么 Gossip protocol 也叫 Epidemic Protocol (流行病协议), 是基于流行病传播方式的节点或者进程之间信息交换的协议, 也被叫做流言算法, 八卦算法、疫情传播算法等等. 说到 Gossip 协议, 就不得不提著名的六度分隔理论. 简单地说, 你和任何一个陌生人之间所间…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)

船舶制造装配管理现状&#xff1a;装配工作依赖人工经验&#xff0c;装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书&#xff0c;但在实际执行中&#xff0c;工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...