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

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

看源码

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

Validator

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

java 复制代码
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 接口怎么用?

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

java 复制代码
@Data
public class UserBean {

    @NotBlank
    private String username;

    @Min(value = 18)
    private Integer age;
}

依赖Spring 容器

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

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

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

java 复制代码
@SpringBootTest
class SpringbootPracticeApplicationTests {
	@Resource
    private Validator validator;

	@Test
    public 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);
    }
}

测试结果:

java 复制代码
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 接口。

java 复制代码
public class ValidationUtils {

    public static Validator getValidator(){
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        return factory.getValidator();
    }
}
java 复制代码
/**
 * @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);
    }
}

打印结果:

java 复制代码
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控制层参数校验的两种方法,不管是哪种获取方法只要能达到结果就行,不过建议使用后者,可以把后者封装成工具类,统一管理校验方法。

相关推荐
计算机学姐3 分钟前
基于Asp.net的驾校管理系统
vue.js·后端·mysql·sqlserver·c#·asp.net·.netcore
欢乐少年19042 小时前
SpringBoot集成Sentry日志收集-3 (Spring Boot集成)
spring boot·后端·sentry
夏天的味道٥3 小时前
使用 Java 执行 SQL 语句和存储过程
java·开发语言·sql
冰糖码奇朵4 小时前
大数据表高效导入导出解决方案,mysql数据库LOAD DATA命令和INTO OUTFILE命令详解
java·数据库·sql·mysql
好教员好5 小时前
【Spring】整合【SpringMVC】
java·spring
浪九天6 小时前
Java直通车系列13【Spring MVC】(Spring MVC常用注解)
java·后端·spring
堕落年代6 小时前
Maven匹配机制和仓库库设置
java·maven
功德+n6 小时前
Maven 使用指南:基础 + 进阶 + 高级用法
java·开发语言·maven
uhakadotcom6 小时前
Apache CXF 中的拒绝服务漏洞 CVE-2025-23184 详解
后端·面试·github
uhakadotcom6 小时前
CVE-2025-25012:Kibana 原型污染漏洞解析与防护
后端·面试·github