Java Bean Validation 不适用Spring的情况下自定义validation注解

Java Bean Validation(也称为 JSR 380,为 Bean Validation 2.0 规范)提供了一套基本的注解,用于定义和验证 Java Bean 的属性。例如:

@NotNull:属性不能为空
@Size:字符串、集合或数组的大小有约束
@Min 和 @Max:数值的最小值和最大值
@Pattern:字符串必须匹配正则表达式
等等
这些注解是由 Bean Validation 规范定义的,可以通过例如 Hibernate Validator 的实现来使用。

0. Maven 依赖

        <dependency><groupId>jakarta.validation</groupId><artifactId>jakarta.validation-api</artifactId></dependency><dependency><groupId>org.hibernate.validator</groupId><artifactId>hibernate-validator</artifactId></dependency>

1. 定义一个注解接口

@Constraint(validatedBy = RegexValidator.class)
@Target({ ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface RegexValidation {String message() default "Invalid value";String pattern();Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};

解析

类注解
@Constraint(validatedBy = RegexValidator.class)
@Target({ ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface RegexValidation {
@Constraint(validatedBy = RegexValidator.class):
标记这个注解作为一个验证注解。
validatedBy 属性指定了用于实际验证的类,这里是 RegexValidator.class。这意味着会有一个 RegexValidator 类来实现对这个注解的验证逻辑。
@Target({ ElementType.FIELD, ElementType.ANNOTATION_TYPE }):
这个元注解指定了 @RegexValidation 可以应用的程序元素类型。
ElementType.FIELD:表示这个注解能用于字段上。
ElementType.ANNOTATION_TYPE:表示这个注解可以用在其他注解上(元注解)。
@Retention(RetentionPolicy.RUNTIME):
这个元注解指定了 @RegexValidation 的保留策略。
RetentionPolicy.RUNTIME:表示注解将在运行时保留,可以通过反射进行读取。
定义注解的属性
String message() default "Invalid value";
message():
定义验证失败时的默认错误消息。
default "Invalid value":提供了一个默认值 "Invalid value"。
String pattern();
pattern():
定义一个字符串类型的属性,用于存储正则表达式模式。
没有默认值,所以这是一个必须属性,使用注解时必须提供。
Class<?>[] groups() default {};
groups():
用于分组验证,这使得注解可以在不同的验证组中使用。
默认是一个空数组。
Class<? extends Payload>[] payload() default {};
payload():
提供了负载信息的一种方式,可以用于传递元数据给约束。
默认是一个空数组。
整个注解定义总结
@RegexValidation 注解是一个自定义的验证注解,允许你对字段进行正则表达式匹配验证。该注解需要一个 pattern 属性来指定要匹配的正则表达式,并且通过 message 属性自定义验证失败时的错误信息。

2. 定义一个验证器

public class RegexValidator implements ConstraintValidator<RegexValidation, String> {private Pattern pattern;@Overridepublic void initialize(RegexValidation constraintAnnotation) {this.pattern = Pattern.compile(constraintAnnotation.pattern());}@Overridepublic boolean isValid(String string, ConstraintValidatorContext context) {if (string == null || string.isBlank()) {return true;}Matcher matcher = pattern.matcher(string);StringBuilder invalidChars = new StringBuilder();while (matcher.find()) {invalidChars.append(matcher.group());}if (invalidChars.length() > 0) {context.disableDefaultConstraintViolation();context.buildConstraintViolationWithTemplate(String.format("Invalid characters found: \"%s\"", invalidChars)).addConstraintViolation();return false;}return true;}
}

解析:

RegexValidator 类的作用是基于自定义注解 @RegexValidation 对字符串进行正则表达式匹配验证。其核心逻辑是初始化时编译正则表达式,然后验证时检查输入字符串是否完全匹配该正则模式,若存在不匹配字符则记录并返回验证失败。此过程实现了灵活且详细的输入验证,非常适合用于需要复杂输入约束的场景。

3. 定义一个组合注解类

@Constraint(validatedBy = {})
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@NotBlank(message = "Name must not be blank")
@Length(min = 3, max = 256, message = "Name length must be between 3 and 256 characters")
@SafeHtml
@RegexValidation(pattern = "[\\x{0001f300}-\\x{0001f64f}]|[\\x{0001f680}-\\x{0001f6ff}<>#%]")
public @interface LongName {String message() default "Invalid name";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};}

解析

这个注解结合了多个验证器来对目标字段进行综合验证。逐行解析这个注解的定义,有助于理解它是如何工作的,以及它在实际使用中可以提供哪些功能。注解定义部分
@Constraint(validatedBy = {})
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {}):这一行表明这是一个验证注解。
validatedBy 属性指定了需要用哪个验证器类来实现这个注解的验证逻辑。在这里,它是一个空数组 {},表示不指定特定的验证器类。实际上,验证的逻辑由注解内部包含的其他注解来实现。
@Target({ ElementType.FIELD }):该元注解描述了 @LongName 可以被应用到程序元素的类型上。
ElementType.FIELD 表示这个注解只能用在字段上。
@Retention(RetentionPolicy.RUNTIME):该元注解描述了 @LongName 的生命周期。
RetentionPolicy.RUNTIME 表示这个注解将在运行时保留,因此可以通过反射机制读取注解信息。
验证注解部分
@NotBlank(message = "Name must not be blank")
@Length(min = 3, max = 256, message = "Name length must be between 3 and 256 characters")
@SafeHtml
@RegexValidation(pattern = "[\\x{0001f300}-\\x{0001f64f}]|[\\x{0001f680}-\\x{0001f6ff}<>#%]")
@NotBlank(message = "Name must not be blank"):表示被注解的字段不能为空白字符串。
如果验证失败,会显示消息 "Name must not be blank"。
@Length(min = 3, max = 256, message = "Name length must be between 3 and 256 characters"):验证字符串长度需要在 3256 个字符之间。
如果长度不符合,会显示消息 "Name length must be between 3 and 256 characters"。
@SafeHtml:表示被注解的字段必须是安全的 HTML 内容。这个注解通常会用来防止跨站脚本(XSS)攻击。
@RegexValidation(pattern = "[\\x{0001f300}-\\x{0001f64f}]|[\\x{0001f680}-\\x{0001f6ff}<>#%]"):自定义一个正则表达式验证:只能包含特定的 Unicode 范围字符和某些标点符号。
应用的正则表达式模式为 "[\\x{0001f300}-\\x{0001f64f}]|[\\x{0001f680}-\\x{0001f6ff}<>#%]"。
组合注解定义的属性部分
public @interface LongName {String message() default "Invalid name";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};}
String message() default "Invalid name";:
提供默认的错误消息,尽管这个信息对组合注解本身没有太大意义,因为每个具体注解都有自己的错误消息。
Class<?>[] groups() default {};:
用于分组验证。
Class<? extends Payload>[] payload() default {};:
用于传递支付信息。
总结
@LongName 是一个组合注解,它结合了多个标准验证注解(例如 @NotBlank, @Length, @SafeHtml and @RegexValidation)的功能。这个组合注解对于需要进行多种综合验证的场景非常有用,使代码更加简洁和可读。同时,组合注解可以减少重复代码,提高开发效率。

4. 实体类字段中注解的使用

public class User {@LongNameprivate String name;// getters 和 setters
}

name 字段将会受到四个不同注解的联合验证:@NotBlank, @Length, @SafeHtml, 和 @RegexValidation。这简化了代码,将多重验证集中在一个地方声明。此外,组合注解提高了代码的可读性和维护性。

5. Spring 注解的优势

Spring 框架的优势
Spring 框架在Bean Validation的基础上进行了很多增强和扩展,为开发者提供了更多的便利和功能:

更强的依赖注入和配置管理:

Spring 框架提供了功能强大且易于使用的依赖注入容器,帮助你轻松管理对象的创建和依赖。
自动校验:

Spring MVC 和 Spring Data 可以自动与 Bean Validation 集成。例如,你可以在控制器方法中直接使用 @Valid 注解,使得请求参数在进入控制器方法之前就被验证。
@PostMapping(“/users”)
public ResponseEntity createUser(@Valid @RequestBody User user) {
// 如果 user 无效,Spring 会自动返回 400 错误代码
return ResponseEntity.ok(userService.save(user));
}
简化的配置:

Spring Boot 通过自动配置大大简化了 Bean Validation 的集成,可以快速上手,并且减少了繁琐的配置过程。
国际化 (i18n) 支持:

Spring 提供了强大的国际化支持,可以轻松地为不同的地区和语言配置验证消息。
高级功能和扩展:

通过自定义注解和验证器类,Spring 框架可以更灵活地满足复杂的业务需求。例如,可以将自定义验证逻辑注入到服务中来实现高级验证逻辑。
@Component
public class CustomValidator implements ConstraintValidator<CustomConstraint, String> {
@Override
public void initialize(CustomConstraint constraintAnnotation) {
}

@Override
public boolean isValid(String value, ConstraintValidatorContext context) {return "specialValue".equals(value);
}

}
与其他Spring模块的深度集成:

Spring 框架与 Spring Security、Spring Data、Spring Cloud 等其他模块紧密集成,这意味着你的验证逻辑可以更加一致和集中管理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/1651.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Elasticsearch ES|QL 地理空间索引加入纽约犯罪地图

可以根据地理空间数据连接两个索引。在本教程中&#xff0c;我将向你展示如何通过混合邻里多边形和 GPS 犯罪事件坐标来创建纽约市的犯罪地图。 安装 如果你还没有安装好自己的 Elasticsearch 及 Kibana 的话&#xff0c;请参考如下的链接来进行安装。 如何在 Linux&#xff0…

分布式缓存redis

分布式缓存redis 1 redis单机&#xff08;单节点&#xff09;部署缺点 &#xff08;1&#xff09;数据丢失问题&#xff1a;redis是内存存储&#xff0c;服务重启可能会丢失数据 &#xff08;2&#xff09;并发能力问题&#xff1a;redis单节点&#xff08;单机&#xff09;部…

【ArcGIS初学】产生随机点计算混淆矩阵

混淆矩阵&#xff1a;用于比较分类结果和地表真实信息 总体精度(overall accuracy) :指对角线上所有样本的像元数(正确分类的像元数)除以所有像元数。 生产者精度(producers accuracy) &#xff1a;某类中正确分类的像元数除以参考数据中该类的像元数(列方向)&#xff0c;又称…

C++ STL之容器介绍(vector、list、set、map)

1 STL基本概念 C有两大思想&#xff0c;面向对象和泛型编程。泛型编程指编写代码时不必指定具体的数据类型&#xff0c;而是使用模板来代替实际类型&#xff0c;这样编写的函数或类可以在之后应用于各种数据类型。而STL就是C泛型编程的一个杰出例子。STL&#xff08;Standard …

GitLab本地服务器配置ssh和克隆项目

1. 本地安装好git git链接&#xff1a;https://git-scm.com/downloads/win 无脑点击下一步安装即可,打开Git Bash命令终端如下&#xff1a; 2. 配置本地用户名和邮箱 git config --global user.name "你的名字" git config --global user.email "你的邮箱&quo…

【Unity高级】一文了解Unity 中的条件编译(附所有指令)

一、Unity中的条件编译 Unity 对 C# 语言的支持包括使用指令&#xff0c;这些指令允许您根据是否定义了某些脚本符号&#xff0c;选择性地包含或排除代码的编译。有关这些指令在 C# 中如何工作的更多信息&#xff0c;请参阅微软关于 C# 预处理器指令 的文档。 &#xff08;一…

主数据系统建设模式分析

很多企业在长期的信息化建设和使用过程中&#xff0c;或多或少的存在数据一致性问题&#xff0c;这类问题导致了大量的数据手工梳理、清洗的工作&#xff0c;对于系统的对接以及统计分析造成了极大的不便&#xff0c;因此信息化部门的管理者迫切的想通过主数据项目来解决目前的…

Redis是单线程还是多线程?

大家好&#xff0c;我是锋哥。今天分享关于【Redis是单线程还是多线程&#xff1f;】面试题。希望对大家有帮助&#xff1b; Redis是单线程还是多线程&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Redis是 单线程 的。 尽管Redis的处理是单线程的&a…

UML系列之Rational Rose笔记一:用例图

好久没有更新笔记了&#xff1b;最近想整理下近期掌握的UML软件建模的知识笔记&#xff1b; 包括但不限于Rational Rose&#xff1b;Drawio&#xff1b;EA&#xff1b;PowerDesigner&#xff1b;Visio&#xff1b;StarUML&#xff1b;Software等软件的使用&#xff1b;UML软件…

熵权法(变异系数法)

熵权法(变异系数法) 一种客观赋权方法&#xff0c;它根据指标的变异程度来确定指标的权重&#xff0c;变异程度越大&#xff0c;说明该指标所包含的信息量越大&#xff0c;相应的权重也就越大。以下是熵权法的详细介绍&#xff1a; 概率与信息量的关系 概率P(x)越小,信息量I(…

基于当前最前沿的前端(Vue3 + Vite + Antdv)和后台(Spring boot)实现的低代码开发平台

项目是一个基于当前最前沿的前端技术栈&#xff08;Vue3 Vite Ant Design Vue&#xff0c;简称Antdv&#xff09;和后台技术栈&#xff08;Spring Boot&#xff09;实现的低代码开发平台。以下是对该项目的详细介绍&#xff1a; 一、项目概述 项目名称&#xff1a;lowcode-s…

JAVA:利用 RabbitMQ 死信队列实现支付超时场景的技术指南

1、简述 在支付系统中&#xff0c;订单支付的超时自动撤销是一个非常常见的业务场景。通常用户未在规定时间内完成支付&#xff0c;系统会自动取消订单&#xff0c;释放相应的资源。本文将通过利用 RabbitMQ 的 死信队列&#xff08;Dead Letter Queue, DLQ&#xff09;来实现…

逻辑测试题

https://blog.csdn.net/qq_39081315/article/details/121393597 先生成一个点&#xff0c;每生成一个点判断距离&#xff0c;角度&#xff0c;满足加入存点的容器&#xff0c;直到容器大小为4。 随机生成点&#xff1a; 分区域&#xff1a;最大距离20&#xff0c;以20为正方形…

图解Git——分支开发工作流《Pro Git》

分支开发工作流 由于分支管理的便捷&#xff0c; 才衍生出这些典型的工作模式&#xff0c;你可以根据项目实际情况选择。 1. 长期分支 适用于持续开发和发布周期长的项目。常见的长期分支包括&#xff1a; master&#xff1a;只保留稳定的代码&#xff0c;通常用于生产环境。…

IOS界面传值-OC

1、页面跳转 由 ViewController 页面跳转至 NextViewController 页面 &#xff08;1&#xff09;ViewController ViewController.h #import <UIKit/UIKit.h>interface ViewController : UIViewControllerend ViewController.m #import "ViewController.h" …

【Spring Boot 应用开发】-04-01 自动配置-数据源-连接池

资源关闭 还记得上一节中的这段代码么&#xff1f; try {if (resultSet ! null) resultSet.close();if (preparedStatement ! null) preparedStatement.close();if (connection ! null) connection.close(); } catch (SQLException e) {e.printStackTrace(); }这是我们在查询…

BUUCTF:misc刷题记录4(会持续更新的)

目录 爱因斯坦 ningen 做题总结&#xff1a; 爱因斯坦 下载解压后&#xff0c;得到一张图片。 老套路&#xff0c;还是先查看一下图片基本属性。只看到这串信息&#xff0c;不知道有啥用。 然后用010进行查看 发现图片里面隐藏了一个压缩包&#xff0c;压缩包里面有个flag.t…

Open FPV VTX开源之嵌入式OSD配置

Open FPV VTX开源之嵌入式OSD配置 1. 源由2. 安装3. 配置步骤一&#xff1a;备份/etc/telemetry.conf步骤二&#xff1a;修改/etc/telemetry.conf步骤三&#xff1a;配置时区步骤四&#xff1a;重启摄像头 4. 实测5. 参考资料 1. 源由 穿越机模拟图传延迟通常在10ms左右。 最…

JavaScript动态渲染页面爬取之Splash

Splash是一个 JavaScript渲染服务,是一个含有 HTTP API的轻量级浏览器,它还对接了 Python 中的 Twisted 库和 OT库。利用它&#xff0c;同样可以爬取动态渲染的页面。 功能介绍 利用 Splash&#xff0c;可以实现如下功能&#xff1a; 异步处理多个网页的渲染过程:获取渲染后…

HTTP详解——HTTP基础

HTTP 基本概念 HTTP 是超文本传输协议 (HyperText Transfer Protocol) 超文本传输协议(HyperText Transfer Protocol) HTTP 是一个在计算机世界里专门在 两点 之间 传输 文字、图片、音视频等 超文本 数据的 约定和规范 1. 协议 约定和规范 2. 传输 两点之间传输&#xf…