@Validated和@Valid对比

Spring Validation验证框架对参数的验证机制提供了@Validated(Spring's JSR-303规范,是标准JSR-303的一个变种),javax提供了@Valid(标准JSR-303规范),配合BindingResult可以直接提供参数验证结果。

在检验Controller的入参是否符合规范时,使用@Validated或者@Valid在基本验证功能上没有太多区别。但是在分组、注解地方、嵌套验证等功能上两个有所不同。

分组

@Validated:提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制,可参考高效使用hibernate-validator校验框架

@Valid:作为标准JSR-303规范,不支持分组的功能。

注解地方

@Validated:可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上。

@Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上。

两者是否能用于成员属性(字段)上直接影响能否提供嵌套验证的功能。

SpringMvc接口参数校验原理

springmvc接口方法中注有@Validated或@Valid参数是如何校验的呢?怎么就能把参数绑定之后的校验结果给到BindingResult实例呢?

@RestController
public class TestController {
@RequestMapping("/xxx/yyy")
public void test1(@Validated Test test, BindingResult bindingResult) {
doSomething();
} @RequestMapping("/yyy/zzz")
public void test1(@Valid Test test, BindingResult bindingResult) {
doSomething();
}
}

其实如果你对springmvc的方法参数解析器(HandlerMethodArgumentResolver)了解一些,就应该知道参数校验这块肯定是在对应的方法参数解析器里执行的。如下是@RequestBody注解对应的参数解析器(RequestResponseBodyMethodProcessor)。

直接定位到resolveArgument这个方法,很明显,该方法是根据参数类型找到支持的消息转换器(Message Converter),然后从request body中读取信息,最后转换成对应的参数实体。

WebDataBinder主要是完成对象属性校验的。如果你熟悉@ModelAttribute注解对应的方法参数解析器(ModelAttributeMethodProcessor),是先通过WebDataBinder进行入参属性绑定,然后再进行校验。

注意,本文的重点代码来了。

简单说一下validateIfApplicable方法的逻辑,遍历当前参数methodParam所有的注解,如果注解是@Validated或注解的名字以‘Valid’开头,则使用WebDataBinder对象执行校验逻辑。

isBindExceptionRequired方法,说的通俗一点,就是要不要抛出异常。怎么判断呢?如果当前参数后面还有参数并且参数类型是Errors(BindingResult继承Errors)则不抛出异常。

最后会把BindingResult结果放到ModelAndViewContainer对象中保存起来,记住BindingResult.MODEL_KEY_PREFIX这个key prefix。

mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());

都说到这里了,BindingResult结果也已经拿到了,该怎么传递给方法中参数呢?会不会有BindingResult参数类型的参数解析器呢?咦,还真他娘的有呀。。。

看到ErrorsMethodArgumentResolver这个参数解析器的注释和源码,的确是针对BindingResult这种参数类型的。BindingResult.MODEL_KEY_PREFIX这个常量在这里出现了,在ModelAndViewContainer对象中拿到BindingResult对象。注意最后面抛出了一个IllegalStateException异常,也就是在ModelAndViewContainer对象中没有找到BindingResult对象的时候才会抛出这个异常,什么情况找不到?

@RequestMapping("/xxx/yyy")
public void test1(BindingResult bindingResult, @Validated @RequestBody Test test) {
doSomething();
}

上述写法就会出现IllegalStateException异常。因为springmvc解析参数的时候是按照顺序, 所以BindingResult类型的参数一定要放在校验实体的后面。

@Validated方法级校验

注意:方法级别的入参有可能是各种平铺的参数、也可能是一个或者多个对象。

下面这个例子就是@Validated注解方法级的校验demo,不过需要配合MethodValidationPostProcessor这个后置处理器使用,需要我们手动注册一下。

@Validated(Default.class)
public interface HelloService {
Object hello(@NotNull @Min(10) Integer id, @NotNull String name);
} public class HelloServiceImpl implements HelloService {
@Override
public Object hello(Integer id, String name) {
return null;
}
}

简单说一下MethodValidationPostProcessor。

Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true);
this.advisor = new DefaultPointcutAdvisor(pointcut, createMethodValidationAdvice(this.validator)); protected Advice createMethodValidationAdvice(Validator validator) {
return (validator != null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor());
}

validatedAnnotationType变量默认是就是@Validated注解类型,所以创建的切面Pointcut对象是切入所有注有@Validated注解的类的所有方法。

Spring环境里创建动态代理核心指定一个或多个advisor,advisor由pointcut和advice组成,pointcut已经创建,advice实例即MethodValidationInterceptor。很明显,MethodValidationInterceptor专门用于处理方法级别的数据校验,包括入参校验和出参校验,本文就不详细说明了,感兴趣的可以直接参考一下源码。

SpringMvc @Validated注解执行原理的更多相关文章

  1. springmvc执行原理及自定义mvc框架

    springmvc是spring的一部分,也是一个优秀的mvc框架,其执行原理如下: (1)浏览器提交请求经web容器(比如tomcat)转发到中央调度器dispatcherServlet. (2)中 ...

  2. SpringMVC底层执行原理

    一个简单的HelloSpringMVC程序 先在web,xml中注册一个前端控制器(DispatcherServlet) <?xml version="1.0" encodi ...

  3. spring Mvc 执行原理 及 xml注解配置说明 (六)

    Spring MVC 执行原理 在 Spring Mvc 访问过程里,每个请求都首先经过 许多的过滤器,经 DispatcherServlet 处理; 一个Spring MVC工程里,可以配置多个的 ...

  4. 分享知识-快乐自己:SpringMVC 底层执行原理解析

    底层实现原理图: 观看底层代码: 1):打开 web.xml 文件  2):按住 Ctrl + 鼠标左键 进入底层查看源码   3):按住 Ctrl+o 找到对应的方法doDispatch   5): ...

  5. springmvc执行原理

    大家是否遇到过被面试官问了这样一句话:"来聊聊springmvc执行原理".是的,springmvc的执行流程是面试的高频点,今天我就来浅谈它! 一.下面通过一个简单的spring ...

  6. (4.1)Spring MVC执行原理和基于Java的配置过程

    一.Spring MVC执行原理和基于Java配置的配置过程 (一)Spring MVC执行过程,大致为7步. 所有的请求都会经过Spring的一个单例的DispacherServlet. Dispa ...

  7. SpringMVC的注解方式配置

    SpringMVC支持使用注解方式配置,比配置文件方式更加灵活易用,是SpringMVC使用的主流模式. 1.在配置文件中开启SpringMVC的注解 <!-- 开启包扫描 --> < ...

  8. Spring MVC执行原理和基于Java的配置过程

    一.Spring MVC执行原理和基于Java配置的配置过程 (一)Spring MVC执行过程,大致为7步. 所有的请求都会经过Spring的一个单例的DispacherServlet. Dispa ...

  9. springMVC的注解详解

    springmvc常用注解标签详解 1.@Controller 在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业 ...

随机推荐

  1. Django+Celery框架自动化定时任务开发

    本章介绍使用DjCelery即Django+Celery框架开发定时任务功能,在Autotestplat平台上实现单一接口自动化测试脚本.业务场景接口自动化测试脚本.App自动化测试脚本.Web自动化 ...

  2. Oracle Compute云快速搭建MySQL Keepalived高可用架构

    最近有个客户在测试Oracle Compute云,他们的应用需要使用MySQL数据库,由于是企业级应用一定要考虑高可用架构,因此有需求要在Oracle Compute云上搭建MySQL高可用集群.客户 ...

  3. 关于RN的热更新

    写点关于RN的热更新和RN版本升级后的强制更新.以及优化白屏问题 在APPDelegate中加载RN,一般的加载方式是:RCTRootView *rootView= [[RCTRootView all ...

  4. Ambari2.7.4+HDP3.1.4安装 Centos7离线安装

    一. Ambari等简单介绍 1.1Ambari Ambari是一种基于Web的工具,支持Apache Hadoop集群的创建 .管理和监控. Ambari已支持大多数Hadoop组件,包括HDFS. ...

  5. iOS技术提升方向

    技术维度: 认知维度:

  6. Python基础-两个乒乓球队进行比赛,各出三人。

    两个乒乓球队进行比赛,各出三人.甲队为a,b,c三人,乙队为x,y,z三人.已抽签决定比赛名单.有人向队员打听比赛的名单.a说他不和x比,c说他不和x,z比,请编程序找出三队赛手的名单. L1 = [ ...

  7. echarts 图点击事件

    有三种方式,介绍一下,大家学习哈 1.利用tooltip记录信息,使用zr 监听事件,进行事件处理. 这种方法是利用showTip方法或者tooltip的formatter函数记录选中的数据信息,并在 ...

  8. Canny检测算法与实现

    1.原理 图象边缘就是图像颜色快速变化的位置,对于灰度图像来说,也就是灰度值有明显变化的位置.图像边缘信息主要集中在高频段,图像锐化或检测边缘实质就是高通滤波.数值微分可以求变化率,在图像上离散值求梯 ...

  9. 实验二 Samba服务器配置

    实验二 实 验 基 本 信 息 实验名称:Samba服务器配置 实验时间:    年 月 日 实验地点: 实验目的: 了解Samba环境及协议 掌握Samba的工作原理 掌握主配置文件Samba.co ...

  10. MySQL 【常识与进阶】

    MySQL 事物 InnoDB事务原理 事务(Transaction)是数据库区别于文件系统的重要特性之一,事务会把数据库从一种一致性状态转换为另一种一致性状态. 在数据库提交时,可以确保要么所有修改 ...