非Controller控制层参数校验怎么办

news/2024/9/24 14:22:55/

文章目录

  • 看源码
    • Validator
  • 实操
    • 依赖Spring 容器
    • 不依赖Spring 容器
  • 总结

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。

上篇文章中我们介绍了如何自定义Springboot参数约束注解和约束校验器,默认情况下,Springboot中的参数校验都是在Controller控制层完成的,那如果我们想要在非Controller控制层 进行参数校验要怎么办呢?本文将介绍非Controller控制层 参数校验的方法。

看源码

从上篇文章中我们知道Spring提供了JSR-303 的一个变种 @Validated ,下面我们看一下 @Validated 的部分源码。

Validator

看注释官方是让我们去看看Validator#validate() 方法,官方让我看我们就去看呗,索性直接看Validator 源码:

public interface Validator {<T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups);<T> Set<ConstraintViolation<T>> validateProperty(T object,String propertyName,Class<?>... groups);<T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType,String propertyName,Object value,Class<?>... groups);BeanDescriptor getConstraintsForClass(Class<?> clazz);<T> T unwrap(Class<T> type);ExecutableValidator forExecutables();
}

Validator是做什么用的呢?

Validator 接口 定义了用于执行验证的方法,用于验证对象的字段值是否符合指定的约束条件。
它主要提供了以下几个核心方法:

  1. <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups)

    • 该方法用于验证给定对象是否符合指定的约束条件。
    • 参数 object是要验证的对象,参数 groups可选,表示验证组。
    • 返回一个 Set 集合,其中包含违反约束条件的 ConstraintViolation 对象。
  2. <T> Set<ConstraintViolation<T>> validateProperty(T object, String propertyName, Class<?>... groups)

    • 该方法用于验证给定对象的特定属性是否符合指定的约束条件。
    • 参数 object是要验证的对象,参数 propertyName是属性名,参数 groups可选,表示验证组。
    • 返回一个 Set 集合,其中包含违反约束条件的 ConstraintViolation 对象。
  3. <T> Set<ConstraintViolation<T>> validateValue(Class<T> beanType, String propertyName, Object value, Class<?>... groups)

    • 该方法用于验证给定属性值是否符合指定的约束条件,而不需要实际创建对象实例。
    • 参数 beanType是对象类型,参数 propertyName是属性名,参数 value是属性值,参数 groups可选,表示验证组。
    • 返回一个 Set 集合,其中包含违反约束条件的 ConstraintViolation 对象。

这些方法能够对 Java 对象进行全面的验证,从整个对象级别到单个属性值的验证,都可以通过 Validator 接口提供的方法来实现。

实操

从上面的介绍我们可以看到,实际上参数校验是通过 Validator 接口的实现类来验证的。 下面我们通过代码来看一下 Validator 接口怎么用?

先把我们的老演员拿出来,下面再校验就用它了。

@Data
public class UserBean {@NotBlankprivate String username;@Min(value = 18)private Integer age;
}

依赖Spring 容器

JSR 303 提供了 Validator 接口作为规范接口,用于实现数据校验功能。在实际应用中,我们并不需要自己从头开始实现这一接口,因为已经有官方参考实现——Hibernate Validator。Spring 框架作为广泛使用的Java开发框架,自然也遵循这一原则,它并没有重复造轮子,而是采用了 Hibernate Validator 的实现来支持校验功能。

因此,当我们使用 Spring 框架进行开发时,通常意味着我们可以直接利用 Spring 提供的集成,将 Validator 接口注入到我们的组件中,然后方便地使用它来进行数据校验。

下面来看下如何在Springboot中使用 Validator 接口。

@SpringBootTest
class SpringbootPracticeApplicationTests {@Resourceprivate Validator validator;@Testpublic void testValidator(){UserBean userBean = new UserBean();userBean.setAge(17);userBean.setUsername(null);Set<ConstraintViolation<UserBean>> constraintViolations = validator.validate(userBean);System.out.println("validate 校验对象属性:");System.out.println(constraintViolations);System.out.println();constraintViolations = validator.validateProperty(userBean, "age");System.out.println("validateProperty校验age属性是否合规:");System.out.println(constraintViolations);System.out.println();constraintViolations = validator.validateValue(UserBean.class , "age", 14 );System.out.println("validateValue校验age属性的值是否合规:");System.out.println(constraintViolations);}
}

测试结果:

validate 校验对象属性:
[ConstraintViolationImpl{interpolatedMessage='不能为空', propertyPath=username, rootBeanClass=class site.suncodernote.validation.UserBean, messageTemplate='{jakarta.validation.constraints.NotBlank.message}'}, 
ConstraintViolationImpl{interpolatedMessage='最小不能小于18', propertyPath=age, rootBeanClass=class site.suncodernote.validation.UserBean, messageTemplate='{jakarta.validation.constraints.Min.message}'}]validateProperty校验age属性是否合规:
[ConstraintViolationImpl{interpolatedMessage='最小不能小于18', propertyPath=age, rootBeanClass=class site.suncodernote.validation.UserBean, messageTemplate='{jakarta.validation.constraints.Min.message}'}]validateValue校验age属性的值是否合规:
[ConstraintViolationImpl{interpolatedMessage='最小不能小于18', propertyPath=age, rootBeanClass=class site.suncodernote.validation.UserBean, messageTemplate='{jakarta.validation.constraints.Min.message}'}]

从打印结果中可以发现具体是哪些字段约束不通过、具体的提示信息都有。

不依赖Spring 容器

JSR 303 是一种规范,意味着它 不依赖Spring 容器 ,能用Java的地方都可以用它,那如果我们在非Spring框架的项目中怎么使用它呢?

其实,最主要的是能获取到 Validator 接口的实现,然后就可以进行验证了。 Validator 接口的实现可以通过如下代码获取,前提是要引入 Hibernate Validator 的依赖或者自己重新造轮子实现Validator 接口。

public class ValidationUtils {public static Validator getValidator(){ValidatorFactory factory = Validation.buildDefaultValidatorFactory();return factory.getValidator();}
}
/*** @author 公众号-索码理(suncodernote)*/
public class ValidatorTest {public static void main(String[] args) {Validator validator = ValidationUtils.getValidator();UserBean userBean = new UserBean();userBean.setAge(17);userBean.setUsername(null);Set<ConstraintViolation<UserBean>> constraintViolations = validator.validate(userBean);System.out.println("validate 校验对象属性:");System.out.println(constraintViolations);System.out.println();constraintViolations = validator.validateProperty(userBean, "age");System.out.println("validateProperty校验age属性是否合规:");System.out.println(constraintViolations);System.out.println();constraintViolations = validator.validateValue(UserBean.class , "age", 14 );System.out.println("validateValue校验age属性的值是否合规:");System.out.println(constraintViolations);}
}

打印结果:

23:57:10.700 [main] INFO org.hibernate.validator.internal.util.Version -- HV000001: Hibernate Validator 8.0.1.Final
validate 校验对象属性:
[ConstraintViolationImpl{interpolatedMessage='最小不能小于18', propertyPath=age, rootBeanClass=class site.suncodernote.validation.UserBean, messageTemplate='{jakarta.validation.constraints.Min.message}'}, 
ConstraintViolationImpl{interpolatedMessage='不能为空', propertyPath=username, rootBeanClass=class site.suncodernote.validation.UserBean, messageTemplate='{jakarta.validation.constraints.NotBlank.message}'}]validateProperty校验age属性是否合规:
[ConstraintViolationImpl{interpolatedMessage='最小不能小于18', propertyPath=age, rootBeanClass=class site.suncodernote.validation.UserBean, messageTemplate='{jakarta.validation.constraints.Min.message}'}]validateValue校验age属性的值是否合规:
[ConstraintViolationImpl{interpolatedMessage='最小不能小于18', propertyPath=age, rootBeanClass=class site.suncodernote.validation.UserBean, messageTemplate='{jakarta.validation.constraints.Min.message}'}]

可以看到 依赖Spring 容器不依赖Spring 容器 ,两者的调用结果都是相同的,不同之处就在于 Validator 的获取,前者直接从 Spring 容器 获取,后者需要通过工厂类获取,适用范围更广一点,在Spring框架中也能使用。

总结

本文介绍了在非Controller控制层参数校验的两种方法,不管是哪种获取方法只要能达到结果就行,不过建议使用后者,可以把后者封装成工具类,统一管理校验方法。


http://www.ppmy.cn/news/1437384.html

相关文章

分布式ID之雪花算法

1. Seata对雪花算法生成ID的改良 滑动验证页面 &#xff08;含代码&讲解&#xff09; Seata基于改良版雪花算法的分布式UUID生成器分析&#xff1a;时间戳和节点ID位置进行了调换。官网&#xff1a;Seata基于改良版雪花算法的分布式UUID生成器分析 | Apache Seata关于新版…

所有单片机使用的汇编语言是统一的吗?

在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「单片机的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01;这个问题应该从编译器&#xf…

Postman - 设置变量

场景&#xff1a; 比如你接口都有权限&#xff0c;访问需要每调一个接口都手动放token的值&#xff0c;这个时候就可以搞个全局的变量&#xff0c;只设置一次就可以了 1、设置变量 Environments -> Globals - > 设置key 、value 2、使用变量 {{你得变量名-key}} 3…

前端开发攻略---用原生JS在网页中也能实现语音识别

1、语音识别的过程 语音识别涉及三个过程&#xff1a;首先&#xff0c;需要设备的麦克风接收这段语音&#xff1b;其次&#xff0c;语音识别服务器会根据一系列语法 (基本上&#xff0c;语法是你希望在具体的应用中能够识别出来的词汇) 来检查这段语音&#xff1b;最后&#xf…

Spark-core面试知识点

Spark课程(web&#xff1a;默认值是8080&#xff0c;但是这个端口号容易被占用&#xff0c;顺势1&#xff1b;提交任务端口号&#xff1a;7077) 一、RDD RDD是spark最底层的核心抽象&#xff0c;叫做弹性分布式数据集。 特点&#xff1a;不可变&#xff0c;可分区&#xff0…

vi, vim,data,wc,系统常用命令-读书笔记(十)

vi 文本编辑器 基本上 vi 共分为三种模式&#xff0c;分别是“一般指令模式”、“编辑模式”与“命令行命令模式”。这三种模式的作用分别是&#xff1a; 一般指令模式&#xff08;command mode&#xff09;以 vi 打开一个文件就直接进入一般指令模式了&#xff08;这是默认的…

Unity构建详解(10)——Unity构建流程

【前言】 我们知道从源代码到可执行文件有四个步骤&#xff1a;预编译、编译、汇编、链接 预编译&#xff1a;处理源代码文件中的以“#”开始的各种预编译指令编译&#xff1a;通过语法语义分析等将源代码文件转为中间语言文件并进行优化&#xff0c;再生成汇编代码文件汇编&…

【Elasticsearch<一>✈️✈️】简单安装使用以及各种踩坑

目录 &#x1f378;前言 &#x1f37b;一、软件安装&#xff08;Windows版&#xff09; 1.1、Elasticsearch 下载 2.1 安装浏览器插件 3.1、安装可视化工具 Kibana 4.1、集成 IK 分词器 &#x1f37a;二、安装问题 &#x1f379;三、测试 IK 分词器 ​&#x1f377; 四、章…