Spring MVC 级联对象参数校验

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
注册配置 MSE Nacos/ZooKeeper,118元/月
简介: 【6月更文挑战第6天】在 Spring MVC 的使用过程中,我们会发现很多非常符合直觉的功能特性,但往往我们会习惯这种「被照顾得很好」的开发方式,依靠直觉去判断很多功能特性的用法。

相关文章:Spring MVC 是如何对对象参数进行校验的

在上述的这篇文章里,介绍了我们常用的 Spring MVC 的对象参数校验,是怎么完成校验的过程的,这篇来介绍一个更深入的问题。因为上篇中介绍的过程,适用于对象中的属性都是常用的 Java 数据类型,比如基本数据类型或者字符串等,如果这个对象中包含一个其它类型的参数,会怎么样呢?

比如这样的类型:

@Data
public class User{
   

    @Size(min = 6, max = 20)
    private String username;

    private Avatar avatar;

    @Data
    public static class Avatar{
   

        @NotNull
        private String imageUrl;

    }

}

在 User 类型中,有一个 Avatar 类型的属性,Avatar 类型中有一个 String 类型的属性 imageUrl 需要校验非空。

在上一篇中,最后介绍了执行校验过程的 AbstractMessageConverterMethodProcessor 类中的 validateIfApplicable 方法,在这个方法中,最后对符合要求的参数对象执行校验的是:

binder.validate(validationHints);

其具体执行的代码,可以在 ValidatorImpl 类的 validate 方法中找到。

@Override
public final <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) {
   
   Contracts.assertNotNull( object, MESSAGES.validatedObjectMustNotBeNull() );
   sanityCheckGroups( groups );

   @SuppressWarnings("unchecked")
   Class<T> rootBeanClass = (Class<T>) object.getClass();
   BeanMetaData<T> rootBeanMetaData = beanMetaDataManager.getBeanMetaData( rootBeanClass );

   if ( !rootBeanMetaData.hasConstraints() ) {
   
      return Collections.emptySet();
   }

   BaseBeanValidationContext<T> validationContext = getValidationContextBuilder().forValidate( rootBeanClass, rootBeanMetaData, object );

   ValidationOrder validationOrder = determineGroupValidationOrder( groups );
   BeanValueContext<?, Object> valueContext = ValueContexts.getLocalExecutionContextForBean(
         validatorScopedContext.getParameterNameProvider(),
         object,
         validationContext.getRootBeanMetaData(),
         PathImpl.createRootPath()
   );

   return validateInContext( validationContext, valueContext, validationOrder );
}

在这里,会根据要校验的对象的类型,构建一个 BeanMetaData 类型的元信息,这个元信息中包含了需要做校验的字段和校验相关的信息。在构建 BeanMetaData 的过程中,会判断是否需要对成员字段进行级联校验,判断的方式就是这个字段是否被 @Valid 修饰(注意不是 @Validated)。级联校验的过程,与宿主对象的校验过程大体相同。

因此,文章开头的写法,Spring 不会去校验 Avatar 中的 imageUrl 是否合法,如果需要让这个校验生效,则需要给 avatar 属性增加 @Valid 注解:

@Valid
private Avatar avatar;

这样才会对 avatar 中的 imageUrl 进行校验。

在 Spring MVC 的使用过程中,我们会发现很多非常符合直觉的功能特性,比如将请求参数绑定到 Controller 的方法参数,或者直接返回一个 Java 对象就可以完成 JSON 数据的转换等等。但往往我们会习惯这种「被照顾得很好」的开发方式,依靠直觉去判断很多功能特性的用法。

如果遇到类似的问题,运行结果不符合开发时的预期,最好的方式就是搞懂其中的原理,从原理中寻找最佳地解决方式。

目录
相关文章
|
20天前
|
JSON 前端开发 Java
spring mvc Rest风格
spring mvc Rest风格
16 0
|
5天前
|
前端开发 Java 应用服务中间件
我以为我对Spring MVC很了解,直到我遇到了...
所有人都知道Spring MVC是是开发的,却鲜有人知道Spring MVC的理论基础来自于1978 年提出MVC模式的一个老头子,他就是Trygve Mikkjel Heyerdahl Reenskaug,挪威计算机科学家,名誉教授。Trygve Reenskaug的MVC架构思想早期用于图形用户界面(GUI) 的软件设计,他对MVC是这样解释的。MVC 被认为是解决用户控制大型复杂数据集问题的通用解决方案。最困难的部分是为不同的架构组件想出好的名字。模型-视图-编辑器是第一个。
我以为我对Spring MVC很了解,直到我遇到了...
|
14天前
|
前端开发 Java Spring
Spring MVC中使用ModelAndView传递数据
Spring MVC中使用ModelAndView传递数据
|
21天前
|
运维 Java 关系型数据库
Spring运维之boot项目bean属性的绑定读取与校验
Spring运维之boot项目bean属性的绑定读取与校验
23 2
|
21天前
|
安全 前端开发 Java
挑战5分钟内基于Springboot+SpringMVC+Mybatis-plus快速构建web后端三层架构
挑战5分钟内基于Springboot+SpringMVC+Mybatis-plus快速构建web后端三层架构
24 1
|
7天前
|
XML 前端开发 Java
Spring Boot与Spring MVC的区别和联系
Spring Boot与Spring MVC的区别和联系
|
10天前
|
Java 微服务 Spring
微服务04---服务远程调用,根据订单id查询订单功能,根据id查询订单的同时,把订单所属的用户信息一起返回,Spring提供了一个工具RestTemplate,Bean写在对象前面,以后可以在任何地
微服务04---服务远程调用,根据订单id查询订单功能,根据id查询订单的同时,把订单所属的用户信息一起返回,Spring提供了一个工具RestTemplate,Bean写在对象前面,以后可以在任何地
|
17天前
|
XML Java 数据库
Spring5系列学习文章分享---第五篇(事务概念+特性+案例+注解声明式事务管理+参数详解 )
Spring5系列学习文章分享---第五篇(事务概念+特性+案例+注解声明式事务管理+参数详解 )
13 0
序-Servlet和SpringMVC的联系和区别-配置路径先想好使用的使用的方法,然后匹配的需要的技术
序-Servlet和SpringMVC的联系和区别-配置路径先想好使用的使用的方法,然后匹配的需要的技术
|
18天前
|
JSON 前端开发 数据格式
SpringMVC的数据响应-直接回写json字符串
SpringMVC的数据响应-直接回写json字符串