spring数据校验
数据校验
概述
在开发中,会存在参数校验的情况,如:注册时,校验用户名不能为空、用户名长度不超过20个字符,手机号格式合法等。如果使用普通方式,会将校验代码和处理逻辑耦合在一起,在需要新增一种校验时,也需要修改很多地方。
spring validation允许通过注解的方式来定义校验规则,把校验和业务分离开。它其实就是对Hibernate Validation进一步的封装。
spring中的校验方式
- 通过实现
org.springframework.validation.Validator接口,然后在代码中调用这个类。 - 按照Bean Validation方式进行校验(通过注解方式)。
- 基于方法实现校验。
通过Validator接口实现校验
实现步骤
1、依赖引入
<dependency><groupId>org.hibernate.validator</groupId><artifactId>hibernate-validator</artifactId><version>8.0.1.Final</version>
</dependency><dependency><groupId>org.glassfish</groupId><artifactId>jakarta.el</artifactId><version>5.0.0-M1</version>
</dependency>
2、创建实体类
public class Person {private String name;private Integer age;public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}
}
3、编写校验类
public class PersonValidator implements Validator {/*** 此方法用来表示此校验用在哪个类型上* @param clazz* @return*/@Overridepublic boolean supports(Class<?> clazz) {return Person.class.equals(clazz);}/*** 此方法是设置校验逻辑的地点,其中ValidatorUtils,是Spring封装的工具类。帮助快速实现校验* @param target* @param errors*///校验规则@Overridepublic void validate(Object target, Errors errors) {//name不能为空ValidationUtils.rejectIfEmpty(errors, "name", "name Empty", "name is null");//age不能小于0,不能大于200Person p = (Person)target;if (p.getAge() <= 0){errors.rejectValue("age", "age.value.error", "age<0");} else if (p.getAge() >= 200) {errors.rejectValue("age", "age.value.error.max", "age>200");}}
}
4、测试
@Test
public void testValidation(){//创建Person对象Person person = new Person();person.setAge(30);person.setName(null);//创建person对应对象DataBinder binder = new DataBinder(person);//设置校验器binder.setValidator(new PersonValidator());//调用方法、执行校验binder.validate();//输出校验结果BindingResult result = binder.getBindingResult();System.out.println("result.getAllErrors() = " + result.getAllErrors());
}
/*
* Empty.name,name Empty.java.lang.String,name Empty]; arguments []; default message [name is null]]
* */
Bean Validation注解实现
使用Bean Validation校验方式,需要使用到
javax.validation.ValidatorFactory和javax.validation.Validator注入到容器中,spring默认有一个实现类LocalValidatorFacoryBean,它实现了上面Bean Validation中的接口,并且也实现了org.springframeworkvalidation.Validator接口。
实现步骤
1、创建配置类,配置LocalValidatorFactoryBean
@Configuration
@ComponentScan("com.louis.testvalidationtwo")
public class ValidationConfig {@Beanpublic LocalValidatorFactoryBean validator(){return new LocalValidatorFactoryBean();}
}
2、创建实体类
定义属性,生成get、set方法,在属性上面使用注解设置校验规则。
public class User {@NotNullprivate String name;@Min(0)@Max(200)private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
3、创建校验器
①使用原生的校验器
@Service
public class MyValidationOne {//使用原生的校验器@Autowiredprivate Validator validator;public boolean testValidator(User user){Set<ConstraintViolation<User>> validate = validator.validate(user);return validate.isEmpty();}
②使用spring中的validation
@Service
public class MyValidationTwo {//使用spring中的validation@Autowiredprivate Validator validator;public List testValidatorTwo(User user){BindException bindException = new BindException(user, user.getName());validator.validate(user, bindException);List<ObjectError> allErrors = bindException.getAllErrors();return allErrors;}
}
4、测试
使用方式①
@Test
public void testValidator(){ApplicationContext context = new AnnotationConfigApplicationContext(ValidationConfig.class);MyValidationOne validationOne = context.getBean(MyValidationOne.class);User user = new User();boolean result = validationOne.testValidator(user);System.out.println("result = " + result);/*result = false*/
}
使用方式②
@Test
public void testValidatorTwo(){ApplicationContext context = new AnnotationConfigApplicationContext(ValidationConfig.class);MyValidationTwo validationTwo = context.getBean(MyValidationTwo.class);User user = new User();List result = validationTwo.testValidatorTwo(user);System.out.println("result = " + result);/*Object name must not be null*/
}
常用注解
| 注解 | 说明 |
|---|---|
@NotNull | 限制必须不为空 |
@NotEmpty | 只作用于字符串类型,字符串不为空,且长度不为0 |
@NotBlank | 只作用于字符串类型,字符串不为空且trim()后也并不为空 |
@DecimalMax(value) | 限制必须为一个不大于指定值的数字,小数存在精度 |
@DecimalMin(value) | 限制必须为一个不小于指定值的数字,小数存在精度 |
@Max(value) | 限制必须为一个不大于指定值的数字 |
@Min(value) | 限制必须为一个不小于指定值的数字 |
@Pattern(value) | 限制必须符合指定的正则表达式 |
@Size(max, min) | 限制字符串长度必须在min到max之间 |
@Email | 验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式 |
基于方法实现校验
实现步骤
1、创建配置类
@Configuration
@ComponentScan("com.louis.validationbymethod")
public class ValidationConfig {@Beanpublic MethodValidationPostProcessor validationPostProcessor(){return new MethodValidationPostProcessor();}
}
2、创建实体类
使用注解设置校验规则
public class User {@NotNullprivate String name;@Max(200)@Min(0)private int age;@NotBlank(message = "手机号不能为空")@Pattern(regexp = "^1(3|4|5|7|8)\\d{9}$", message = "手机号格式错误")private String phone;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}
}
3、编写校验器
@Service
@Validated
public class MyService {public String testMethod(@NotNull @Valid User user){return user.toString();}
}
4、测试
@Test
public void testValidationByMethod(){ApplicationContext context = new AnnotationConfigApplicationContext(ValidationConfig.class);MyService service = context.getBean(MyService.class);service.testMethod(new User());/*testMethod.arg0.phone: 手机号不能为空, testMethod.arg0.name: 不能为null*/
}
实现自定义校验
实现步骤
1、自定义校验注解
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {CannotHaveBlankValidator.class})//表示指定校验器的类,实现真正的校验器规则
public @interface CannotHaveBlank {//默认的出现错误的提示信息String message() default "不能包含空格";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface List {CannotHaveBlank[] value();}
}
2、编写校验规则
public class CannotHaveBlankValidator implements ConstraintValidator<CannotHaveBlank, String> {@Overridepublic boolean isValid(String value, ConstraintValidatorContext context) {if(value != null &&value.contains(" ")){//获取默认提示信息String defaultConstraintMessageTemplate = context.getDefaultConstraintMessageTemplate();System.out.println("default message:"+defaultConstraintMessageTemplate);//禁用默认提示信息context.disableDefaultConstraintViolation();//设置提示语context.buildConstraintViolationWithTemplate("can not constrains blank").addConstraintViolation();return false;}return false;}
}
3、创建实体类
public class User {@NotNullprivate String name;@Max(200)@Min(0)private int age;@NotBlank(message = "手机号不能为空")@Pattern(regexp = "^1(3|4|5|7|8)\\d{9}$", message = "手机号格式错误")private String phone;@CannotHaveBlankprivate String message;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}
}
4、测试
//使用基于方法实现校验的校验器
public class TestValidationByMethod {@Testpublic void testValidationByMethod(){ApplicationContext context = new AnnotationConfigApplicationContext(ValidationConfig.class);MyService service = context.getBean(MyService.class);User user = new User();user.setAge(30);user.setName("Louie");user.setPhone("18111111111");user.setMessage("L o u i s");service.testMethod(user);
/*default message:不能包含空格
jakarta.validation.ConstraintViolationException: testMethod.arg0.message: can not constrains blank*/}
}
相关文章:
spring数据校验
数据校验 概述 在开发中,会存在参数校验的情况,如:注册时,校验用户名不能为空、用户名长度不超过20个字符,手机号格式合法等。如果使用普通方式,会将校验代码和处理逻辑耦合在一起,在需要新增一…...
因材施教,有道发布“子曰”教育大模型,落地虚拟人口语教练等六大应用
因材施教的教育宗旨下,大模型浪潮中,网易有道凭借其对教育场景的深入理解和对商业化的理性思考,为行业树立了垂直大模型的典范。 7月26日,教育科技公司网易有道举办了“powered by 子曰”教育大模型应用成果发布会。会上重磅推出了…...
golang waitgroup
案例 WaitGroup 可以解决一个 goroutine 等待多个 goroutine 同时结束的场景,这个比较常见的场景就是例如 后端 worker 启动了多个消费者干活,还有爬虫并发爬取数据,多线程下载等等。 我们这里模拟一个 worker 的例子 package mainimport (…...
单列模式多学两遍
单例模式 单例模式(Singleton Pattern,也称为单件模式),使用最广泛的设计模式之一。其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。 定义单例类 ● 私有化它的构造函数,…...
Spring Cloud【SkyWalking网络钩子Webhooks、SkyWalking钉钉告警、SkyWalking邮件告警】(十六)
目录 分布式请求链路追踪_SkyWalking网络钩子Webhooks 分布式请求链路追踪_SkyWalking钉钉告警 分布式请求链路追踪_SkyWalking邮件告警 分布式请求链路追踪_SkyWalking网络钩子Webhooks Wbhooks网络钩子 Webhok可以简单理解为是一种Web层面的回调机制。告警就是一个事件&a…...
【力扣每日一题】2023.7.25 将数组和减半的最少操作次数
目录 题目: 示例: 分析: 代码运行结果: 题目: 示例: 分析: 题目给我们一个数组,我们每次可以将任意一个元素减半,问我们操作几次之后才可以将整个数组的和减半&…...
Docker-Compose 轻松搭建 Grafana+InfluxDb 实用 Jmeter 监控面板
目录 前言: 1、背景 2、GranfanaInfluxDB 配置 2.1 服务搭建 2.2 配置 Grafana 数据源 2.3 配置 Grafana 面板 3、Jmeter 配置 3.1 配置 InfluxDB 监听器 3.2 实际效果 前言: Grafana 和 InfluxDB 是两个非常流行的监控工具,它们可…...
异构线程池的c++实现方案
概要 通常线程池是同质的,每个线程都可以执行任意的task(每个线程中的task顺序执行),如下图所示: 但本文所介绍的线程和task之间有绑定关系,如A task只能跑在A thread上(因此称为异构线程池&am…...
Python实现抽象工厂模式
抽象工厂模式是一种创建型设计模式,用于创建一系列相关或依赖对象的家族,而无需指定具体类。在Python中,可以通过类和接口的组合来实现抽象工厂模式。 下面是一个简单的Python实现抽象工厂模式的示例: # 抽象产品接口 class Abs…...
@vue/cli安装
vue/cli安装 1、全局安装vue/cli包2、查看是否成功 1、全局安装vue/cli包 yarn global add vue/cli2、查看是否成功 vue -V...
用友全版本任意文件上传漏洞复现
声明 本文仅用于技术交流,请勿用于非法用途 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。 文章作者拥有对此文章的修改和解释权。如欲转载或传播此文章,…...
程序员面试系列,MySQL常见面试题?
原文链接 一、索引相关的面试题 (1)索引失效的情况有哪些 在MySQL查询时,以下情况可能会导致索引失效,无法使用索引进行高效的查询: 数据类型不匹配:如果查询条件中的数据类型与索引列的数据类型不匹配&…...
前端Web实战:从零打造一个类Visio的流程图拓扑图绘图工具
前言 大家好,本系列从Web前端实战的角度,给大家分享介绍如何从零打造一个自己专属的绘图工具,实现流程图、拓扑图、脑图等类Visio的绘图工具。 你将收获 免费好用、专属自己的绘图工具前端项目实战学习如何从0搭建一个前端项目等基础框架项…...
2023牛客暑期多校第二场部分题解
索引 ABCDEFGHIK A 队友开的题,说是其实就是问能不能用若干个数异或出来某个数。 应该就是线性基板子,然后他写了一下就过了。 B 一开始看没什么人过不是很敢开,结果到后面一看题——这不是最大权闭合子图板子吗??…...
20230724将真我Realme手机GT NEO3连接到WIN10的电脑的步骤
20230724将真我Realme手机GT NEO3连接到WIN10的电脑的步骤 2023/7/24 23:23 缘起:因为找使用IMX766的手机,找到Realme手机GT NEO3了。 同样使用IMX766的还有:Redmi Note12Pro 5G IMX766 旗舰影像 OIS光学防抖 OLED柔性直屏 8GB256GB时光蓝 现…...
黑马 pink h5+css3+移动端前端
网页概念 网页是网站的一页,网页有很多元素组成,包括视频图片文字视频链接等等,以.htm和.html后缀结尾,俗称html文件 HTML 超文本标记语言,描述网页语言,不是编程语言,是标记语言,有标签组成 超文本指的是不光文本,还有图片视频等等标签 常用浏览器 firefox google safari…...
Docker的七项优秀实践
众所周知,作为一个文本文档,Dockerfile包含了用户创建镜像的所有命令和说明。Docker可以通过读取Dockerfile中指令的方式,去自动构建镜像。因此,大家往往认为编写Dockerfile理应非常简单,只需从互联网上选择一个示例&a…...
【数据结构】24王道考研笔记——图
六、图 目录 六、图定义及基本术语图的定义有向图以及无向图简单图以及多重图度顶点-顶点间关系连通图、强连通图子图连通分量强连通分量生成树生成森林边的权、带权网/图特殊形态的图 图的存储及基本操作邻接矩阵邻接表法十字链表邻接多重表分析对比图的基本操作 图的遍历广度…...
zabbix钉钉报警
登录钉钉客户端,创建一个群,把需要收到报警信息的人员都拉到这个群内. 然后点击群右上角 的"群机器人"->"添加机器人"->"自定义", 记录该机器人的webhook值。 添加机器人 在钉钉群中,找到只能群助手 添加机器人 选择自定义机…...
Spring 源码解读
1、Spring 的结构组成 1.1、核心类介绍 Spring 中有两个最核心的类 1 DefaultListableBeanFactory XmlBeanFactory 继承自 DefaultListableBeanFactory,而DefaultListableBeanFactory 是整个 bean加载的核心部分,是 Spring 注册及加载 bean 的默认实现…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...
uniapp 实现腾讯云IM群文件上传下载功能
UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中,群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS,在uniapp中实现: 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...
【UE5 C++】通过文件对话框获取选择文件的路径
目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 ,这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器,右键点击 .uproject 文件,选择 "Generate Visual Studio project files",重…...
结构化文件管理实战:实现目录自动创建与归类
手动操作容易因疲劳或疏忽导致命名错误、路径混乱等问题,进而引发后续程序异常。使用工具进行标准化操作,能有效降低出错概率。 需要快速整理大量文件的技术用户而言,这款工具提供了一种轻便高效的解决方案。程序体积仅有 156KB,…...
