Spring Boot下@Valid和@Validated的区别【源码级】

Spring Boot项目里对于接口参数校验,可以使用javax.validation.constraints包下的注解来优雅的校验。比如参数长度、是否为null甚至可以使用正则表达式来校验参数格式,以及校验不通过返回的提示信息都可以通过注解进行配置,实在是方便的很。

但是本人在开发中遇到了这么几个问题:

  • 某一次SpringBoot版本升级后,启动项目提示我没有·javax.validation·的依赖,一开始导入了javax.validation-validation-api仍旧不能启动,后来导入了hibernate-validator的依赖就可以了。为什么?
  • 有的文章说,使用这个校验器要在controller上加@Validated注解,同时接口参数里也要加才能使用,really?
  • @Valid是javax包下的注解,而@Validated是Spring的注解,在Spring Boot项目里得使用后者才行。确定?

基于以上几个问题,我翻阅了不少资料,debug好几轮源码才找到了答案,有兴趣得伙伴可以跟着我一起来看看。


Spring Boot 2.3

2.3版本的SpringBoot将不再依赖javax.validation的包,所以,开发人员需要自行导入依赖,官方推荐的是使用自家的这个依赖。

Validation Starter no longer included in web starters
As of #19550, Web and WebFlux starters do not depend on the validation starter by default anymore. If your application is using validation features,
for example you find that javax.validation.* imports are not being resolved, you’ll need to add the starter yourself.
For Maven builds, you can do that with the following:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

看下这个dependency的依赖关系
在这里插入图片描述
它其实还是依赖了hibernate校验器的包,毕竟它是一个成熟的工具了,Spring当然是取其精华,不再自己搞一套了。
值得注意的是,这个jakarta.validation又是什么鬼?怎么和javax.validation不一样呢。打开这个包看看,其实是一样的。
在这里插入图片描述

javax.validation-validation-api

这个包其实就是一个api的包,里边包含了所有的注解及接口,但是没有实现,所以若是只导入了这个依赖,是不行滴

        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>2.0.1.Final</version>
        </dependency>

再往深想一步,为什么不行?

先看一下这个包里边最重要的一个类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();
}

接着参数校验肯定是在执行接口Handler前做掉的,也就是将参数封装成对象后,要进行参数校验,在这一步肯定会有类似校验器的东西(即Validator的实现类)去执行具体的参数校验

我们debug源码看看,源码只列出核心部分,多余内容都用省略号表示

Spring MVC的请求分发

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   
	...
	// Actually invoke the handler.
	mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
	...
}

一直往下走,走到参数校验的位置

@Nullable
    public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
   
       ...
        if (bindingResult == null) {
   
            WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
            if (binder.getTarget() != null) {
   
                if (!mavContainer.isBindingDisabled(name)) {
   
                    this.bindRequestPara
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值