Spring Validation的校验顺序问题解决方案

  • 问题场景
  • 原理剖析
  • 解决方法
    • 创建五个接口
    • 修改Controller控制层代码
    • 修改实体类代码
  • 整改结果
  • 后续问题
    • 问题原因
    • 解决方案

问题场景

测试发现对同一个接口调用多次时,返回的校验异常信息不同,经过问题追踪,入参实体类代码如下:

@Data
public class EditDevNameDto {@NotBlank(message = "deviceSn must not null")private String deviceSn;@NotBlank(message = "deviceName must not null")private String deviceName;
}

当这个接口入参的deviceSn和deviceName均为空值时,调用多次的话会出现两个msg错误信息循环返回的问题。

原理剖析

怀疑是调用接口时,校验注解的先后顺序是不确定的,所以,可能deviceSn先被校验,可能deviceName先被校验,那要解决这个问题就要规定校验的顺序才行。

解决方法

使用@GroupSequence注解实现顺序的稳定性。

创建五个接口

public interface GroupA {}public interface GroupB {}public interface GroupC {}public interface GroupD {}@GroupSequence({GroupA.class,GroupB.class,GroupC.class,GroupD.class})
public interface Group {}

修改Controller控制层代码

注意在入参中加入@Validated(Group.class)注解,其中要加入被@GroupSequence修饰的类对象。

    @PostMapping("/edit_device_name")public ExecuteResult editDevName(@RequestBody @Validated(Group.class) EditDevNameDto dev) {// -----逻辑代码return null;}

修改实体类代码

在实体类中使用校验注解中添加groups属性,顺序按照@GroupSequence类规定的顺序即可。

@Data
public class EditDevNameDto {@NotBlank(message = "deviceSn must not null", groups = {GroupA.class})private String deviceSn;@NotBlank(message = "deviceName must not null", groups = {GroupB.class})private String deviceName;
}

整改结果

当这个接口入参的deviceSn和deviceName均为空值时,频繁调用依然是按照先校验deviceSn,后校验deviceName的顺序进行参数校验。

后续问题

问题原因

解决了上面的问题,过了几天,又出现了解决校验顺序的问题,但是这次又不同于上一次,这次的Dto参数接收类有些复杂,代码如下:

@Data
public class UpdateInfoDto {@NotBlank(message = "deviceSn can not be empty")@GBDeviceSnValidprivate String deviceSn;@Valid // 让CommonDto类中的校验属性生效@GBChannelDuplicateValid@CollectionNotEmptyValid(message = "channels cannot be empty")private List<CommonDto> channels;
}@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonDto{@GBChannelIdValidprivate String id;@NotNull(message = "channelId must not be null")@PositiveOrZero(message = "channelId only Integer or zero")private Integer channelId;
}

以上代码中有两个类,共同组合成参数接收类,要纠正校验顺序混乱问题,还是需要用到一开始讲到的@GroupSequence注解,但是,有两个问题:

  1. Dto中还有一个对象类型的属性。
  2. 对象类型属性中的子属性(id、channelId)也要成功校验

解决方案

首先,为了让Dto中的对象类型的属性也能正常校验,需要添加@Valid注解;
然后,在对象类型属性中的子属性中也需要像文章前面所说的在校验注解中设置groups属性。
修改后的代码如下:

@Data
public class UpdateInfoDto {@NotBlank(message = "deviceSn can not be empty", groups = {GroupA.class})@GBDeviceSnValid(groups = {GroupA.class})private String deviceSn;@Valid // 让CommonDto类中的校验属性生效@GBChannelDuplicateValid(groups = {GroupB.class})@CollectionNotEmptyValid(message = "channels cannot be empty", groups = {GroupB.class})private List<CommonDto> channels;
}@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonDto{@GBChannelIdValid(groups = {GroupC.class})private String id;@NotNull(message = "channelId must not be null", groups = {GroupD.class})@PositiveOrZero(message = "channelId only Integer or zero", groups = {GroupD.class})private Integer channelId;
}

如果CommonDto中校验属性的注解不设置groups,CommonDto中的校验属性就会失效,这是个大坑

Spring Validation的校验顺序问题解决方案(建议读到最后,有大坑)相关推荐

  1. 【Spring】掌握 Spring Validation 数据校验

    个人简介:Java领域新星创作者:阿里云技术博主.星级博主.专家博主:正在Java学习的路上摸爬滚打,记录学习的过程~ 个人主页:.29.的博客 学习社区:进去逛一逛~ Spring Validati ...

  2. 基于Spring Validation自定义校验注解

    常用的原生校验注解有: @NotNull 所有对象判空 @NotBlank 字符串判空 @NotEmpty 集合判空 自定义校验注解实现方式: 引入依赖 如果spring-boot版本小于2.3.x, ...

  3. Spring Validation最佳实践及其实现原理,参数校验没那么简单!

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:六点半起床 juejin.im/post/685654110 ...

  4. Spring Validation 最佳实践及其实现原理,参数校验没那么简单!

    之前也写过一篇关于Spring Validation使用的文章,不过自我感觉还是浮于表面,本次打算彻底搞懂Spring Validation.本文会详细介绍Spring Validation各种场景下 ...

  5. Spring Validation 校验

    一.概述 在 Web 应用中,客户端提交数据之前都会进行数据的校验,比如用户注册时填写的邮箱地址是否符合规范.用户名长度的限制等等,不过这并不意味着服务端的代码可以免去数据验证的工作,用户也可能使用 ...

  6. js 强校验 弱校验_还在手写表单校验逻辑?试试spring validation吧

    Java识堂,一个高原创,高收藏,有干货的微信公众号,欢迎关注 前言 数据的校验是交互式网站一个不可或缺的功能,前端的js校验可以涵盖大部分的校验职责,如用户名唯一性,生日格式,邮箱格式校验等等常用的 ...

  7. 使用 Spring Validation 优雅地进行参数校验

    引言 不知道大家平时的业务开发过程中 controller 层的参数校验都是怎么写的?是否也存在下面这样的直接判断? public String add(UserVO userVO) {if(user ...

  8. Spring Validation校验

    本文来说下现在使用的比较多的Spring Validation校验框架. 文章目录 概述 校验注解 JSR-303包含的注解 Hibernate Validator扩展的注解 简单使用 引入依赖 re ...

  9. Spring Validation实现原理,参数校验没那么简单

    前言 本文会详细介绍Spring Validation各种场景下的最佳实践及其实现原理,死磕到底! 项目源码:spring-validation 简单使用 Java API规范(JSR303)定义了B ...

最新文章

  1. 【OpenCV 4开发详解】轮廓发现与绘制
  2. Linux的chattr与lsattr命令详解
  3. 【Leetcode | easy】回文数
  4. python与 积分
  5. mysql as join_mysql as 别名与 join 多表连接语法
  6. JQuery中使用Ajax赋值给全局变量失败异常的解决方法,jqueryajax
  7. 在Centos7 更改Docker默认镜像和容器的位置
  8. table中动态删除当前行
  9. [JS进阶] JS 之Blob 对象类型
  10. Android开发笔记(二十)顶部导航栏ActionBar
  11. java和ajax超时_java – 如何在不重置tomcat的会话超时的情况下执行经过身份验证的AJAX请求?...
  12. python扩展库不是用于科学计算的有_有没有可以并行计算的 Python 科学计算库?...
  13. JAVA IO - RandomAccessFile
  14. php 游戏开发swoole,用Swoole来写个联机对战游戏呀!(一)前言
  15. hdu 6437 - 最大费用流
  16. 时钟晶振电路EMC设计标准电路详解
  17. zz 一个Hash实例:Blizzard的MPQ文件
  18. Pycharm下载pytorch
  19. C++实现get与set
  20. 硬实时RTLinux?为Linux打实时preempt_rt补丁

热门文章

  1. 尚硅谷nginx学习
  2. 加密聊天应用依然安全
  3. MID-TERM EXAMINATION 1
  4. 【Visual Studio 2019 - Unknown override specifier error】Problems when compiling dbghelp.h
  5. 关于windows2008r2下access数据库网站报Microsoft OLE DB Provider for ODBC Drivers 错误 '80004005'
  6. 实现美团、饿了么购物车效果,并本地存储相关数据
  7. 来自1959《粉红色潜艇》的经典语录
  8. 多懂点SQL可以写出更好的接口
  9. 网络教育计算机和英语难度怎样,网络教育统考大学英语b难吗?
  10. 现阶段云计算的市场运用