自定义校验注解,优雅的实现手机号,身份证号的格式校验!

devtools/2024/11/15 0:09:10/

导读(皮一下)

为什么需要自定义校验注解

系统执行业务逻辑之前,会对输入数据进行校验,检测数据是否有效合法的。所以我们可能会写大量的if else等判断逻辑,特别是在不同方法出现相同的数据时,校验的逻辑代码反复出现,导致代码冗余阅读性和可维护性极差

  • 鉴于通用性和普遍性,Spring框架提供了validator组件,通过一些校验器,可以对一些数据进行统一的完整性和有效性等校验,即简单又好用。
  • JSR-303Java为Bean数据合法性校验提供的标准框架,它定义了一整套校验注解,可以标注在成员变量,属性方法等之上。
  • 但是这些通用的校验注解,并不能满足我们的所有需求,如电话号格式校验,身份证号格式校验…

常用的校验器

Java开发中,校验器(validator)是指用于数据验证的工具或库,它们帮助确保应用程序的数据符合预期的格式或规则。以下是一些常用的校验器库和框架:

名称描述
Bean Validation (JSR 303/349/380)Java平台的标准数据验证API,提供注解驱动的数据验证机制
Hibernate ValidatorBean Validation的参考实现,提供丰富的预定义注解,如@NotNull, @Size等
Spring ValidationSpring框架中的集成Bean Validation的包,提供额外的校验功能
Apache Commons Validator提供用于验证不同数据格式的工具,如电子邮件、URL、IP地址等
Google GuavaGuava库中的Strings类,用于简单的字符串校验
AssertJ一个断言库,用于编写更可读的单元测试,也常用于校验方法参数和对象状态
JSR 303/349/380注解包括@Null, @NotNull, @AssertTrue等,用于标注验证规则
自定义校验器开发者可以自定义校验注解和校验器类,满足特定的业务需求
Spring Boot Starter ValidationSpring Boot提供的验证启动器,集成了Hibernate Validator,简化配置
Lombok自动生成Getter、Setter、构造器等,可配合Bean Validation使用,减少样板代码

自定义校验注解

自定义校验注解通常分为如下几步:

  1. 配置验证框架: 确保项目中包含了Bean Validation API的相关依赖(pom依赖,有没有校验器的jar)
  2. 创建注解,使用@Constraint注解来声明这是一个约束注解,使用@Target@Retention注解来指定注解的作用目标和保留策略。
  3. 实现校验器: 创建一个类实现ConstraintValidator接口,这个类将包含实际的校验逻辑。需要重写initialize方法(初始化,基本不咋用到)和isValid方法,isValid方法用于执行具体的校验逻辑。
  4. 使用注解:在需要校验的字段或方法上使用自定义注解

自定义电话号格式校验注解

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;/*** 手机号校验注解*/
@Documented
@Constraint(validatedBy = PhoneNumberValidator.class)
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidPhoneNumber {String message() default "手机号格式不正确";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}
// 实现校验逻辑的类
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;public class PhoneNumberValidator implements ConstraintValidator<ValidPhoneNumber, String> {@Overridepublic void initialize(ValidPhoneNumber constraintAnnotation) {// 初始化方法,可以在这里进行一些初始化工作,但通常不需要实现}@Overridepublic boolean isValid(String phoneNumber, ConstraintValidatorContext context) {// 正则表达式,用于校验手机号格式String regex = "^1[3-9]\\d{9}$";return phoneNumber.matches(regex);}
}

使用方式:

public class User {@ValidPhoneNumber(message = "请输入正确的手机号")private String phone;// ...
}

自定义身份证号格式校验注解

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;@Documented
@Constraint(validatedBy = IDCardValidator.class)
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidIDCard {String message() default "身份证号码格式不正确";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;public class IDCardValidator implements ConstraintValidator<ValidIDCard, String> {private static final int ID_CARD_LENGTH_18 = 18;private static final String ID_CARD_REGEX_18 = "^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])\\d{3}([0-9]|X)$";private static final char[] VERIFY_CODE = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};private static final int[] WEIGHTS = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};@Overridepublic void initialize(ValidIDCard constraintAnnotation) {}@Overridepublic boolean isValid(String idCard, ConstraintValidatorContext context) {if (idCard == null || idCard.length() != ID_CARD_LENGTH_18) {return false;}if (!idCard.matches(ID_CARD_REGEX_18)) {return false;}// 验证18位身份证的校验码return validate18(idCard);}private boolean validate18(String idCard) {int sum = 0;for (int i = 0; i < 17; i++) {sum += Character.getNumericValue(idCard.charAt(i)) * WEIGHTS[i];}int mod = sum % 11;char checkCode = VERIFY_CODE[mod];return Character.toUpperCase(idCard.charAt(17)) == checkCode;}
}

使用方式:

import javax.validation.constraints.NotNull;
import javax.validation.Valid;public class Person {@NotNull(message = "姓名不能为空")private String name;@ValidIDCard(message = "身份证号码格式不正确")private String idCard;// ...
}


http://www.ppmy.cn/devtools/85576.html

相关文章

FOC笔记(一)电角度零点校准

当电机上电时&#xff0c;它处于位置的电角度未知。如果按上图U4&#xff08;100&#xff09;通电&#xff0c;也会让电角度为0,但是这样力量很大。 简单的方法是只控制d角度的磁场大小&#xff0c;转矩磁场q为0,生成一个定向磁场指向电角度为0。 foc->sin_sita 0;foc->…

MySQL、SqlServer、Oracle三大主流数据库实现分页查询的方法

在数据库管理系统&#xff08;DBMS&#xff09;中&#xff0c;分页查询是一种常见的需求&#xff0c;用于从大量数据中检索并展示一小部分数据给用户。不同的数据库系统提供了不同的方法来实现分页查询。下面将分别介绍MySQL、SQL Server和Oracle这三大主流数据库系统实现分页查…

mybatis批量插入、mybatis-plus批量插入、mybatis实现insertList、mybatis自定义实现批量插入

文章目录 一、mybatis新增批量插入1.1、引入依赖1.2、自定义通用批量插入Mapper1.3、把通用方法注册到mybatisplus注入器中1.4、实现InsertList类1.5、需要批量插入的dao层继承批量插入Mapper 二、可能遇到的问题2.1、Invalid bound statement 众所周知&#xff0c;mybatisplus…

【JavaScript】use strict

“use strict” 声明时&#xff0c;代码将会在严格模式下执⾏。严格模式包含了⼀些额外的规则和限制。 使⽤ “use strict” 的主要作⽤包括&#xff1a; 变量必须声明后再使⽤&#xff0c;不能通过不使⽤关键字创建全局变量不能通过 delete 操作符删除变量&#xff08;包括对…

Vue el-input 中 readonly和disabled的区别详解

在 Vue.js 的 Element UI 组件库中&#xff0c;el-input 是一个常用的输入框组件。readonly 和 disabled 是两个常见的属性&#xff0c;用于控制输入框的交互行为&#xff0c;但它们之间存在显著的差异。下面将详细解释这两个属性的区别。 readonly 定义&#xff1a;readonly…

Linux系列--shell编程一

一、Linux系统结构 一、内核层 内核是Linux系统的核心部分&#xff0c;它负责管理系统各种硬件设备、文件系统、内存管理和进程管理等核心任务。Linux内核设计了良好的模块化结构&#xff0c;可以动态地加载和卸载内核模块&#xff0c;这使得内核可以兼容各种不同的硬件设备和…

C++(week14): C++提高:(一)面向对象设计:设计原则、设计模式

文章目录 一、面向对象设计的概念4.统一建模语言&#xff1a;UML语言StartUML 二、类与类之间的关系0.总结(1)类与类的五种关系(2)区别(3)面向对象 vs 基于对象 1.继承 (泛化耦合)2.组合 (Composition)3.聚合 (Aggregation)4.关联(1)双向关联(2)单向关联 5.依赖 (Dependency) 三…

元器件基础学习笔记——二极管基础

一、二极管基础 二极管是用半导体材料(硅、硒、锗等)制成的一种电子器件&#xff0c;具有单向导电性&#xff0c;是现代电子技术的基石。它在电子电路中扮演着至关重要的角色&#xff0c;通过与电阻、电容、电感等元器件的合理连接&#xff0c;能够实现整流、检波、限幅、稳压等…