Spring Validation的校验顺序问题及解决过程

 更新时间:2026年01月09日 09:19:23   作者:她又在丛中笑  
本文主要介绍了使用@GroupSequence注解来解决接口入参校验顺序不稳定的问题,并提供了具体的实现步骤和代码示例

问题场景

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

@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")
    @GBDeviceSnValid
    private String deviceSn;


    @Valid // 让CommonDto类中的校验属性生效
    @GBChannelDuplicateValid
    @CollectionNotEmptyValid(message = "channels cannot be empty")
    private List<CommonDto> channels;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonDto{

    @GBChannelIdValid
    private 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中的校验属性就会失效,这是个大坑

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 基于Properties实现配置数据库驱动

    基于Properties实现配置数据库驱动

    这篇文章主要介绍了基于Properties实现配置数据库驱动,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • Mybatis velocity脚本的使用教程详解(推荐)

    Mybatis velocity脚本的使用教程详解(推荐)

    很多朋友不清楚在mybatis可以使用各种脚本语言来定义Mapper文件里面的动态SQL;目前mybatis支持的脚本语言有XML(默认的);Velocity和Freemarker三种。下面通过本文给大家介绍Mybatis velocity脚本的使用,一起看看吧
    2016-11-11
  • springboot实现https双向传输协议的示例代码

    springboot实现https双向传输协议的示例代码

    本文主要介绍了springboot实现https双向传输协议的示例代码,包含配置证书和私钥路径、调用请求方法等步骤,具有一定的参考价值,感兴趣的可以了解一下
    2025-03-03
  • Mybatis中特殊SQL的执行的实现示例

    Mybatis中特殊SQL的执行的实现示例

    本文主要介绍了Mybatis中特殊SQL的执行的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • JAVA中Spring Security示例及常见问题

    JAVA中Spring Security示例及常见问题

    文章概述Spring Security OAuth2与JWT模块的版本兼容性及迁移建议,强调2.5.x支持JDK8但已弃用,推荐新项目使用SpringAuthorizationServer(Spring Boot3.x+),并指出依赖冲突、配置示例及密钥安全注意事项,感兴趣的朋友一起看看吧
    2025-07-07
  • Java 中限制方法的返回时间最新方法

    Java 中限制方法的返回时间最新方法

    最近在研究 ChatGPT 的 API 调用,因为 ChatGPT 的 API 调用时间通常超过 30 秒,所以我们希望在程序中限制这个方法的执行时间,不要让方法花太长时间去执行了,今天通过本文给大家分享Java 中如何限制方法的返回时间,感兴趣的朋友跟随小编一起看看吧
    2023-05-05
  • Spring Boot 集成Dubbo框架实例

    Spring Boot 集成Dubbo框架实例

    本篇文章主要介绍了Spring Boot 集成Dubbo框架实例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • IDEA修改生成jar包名字的两种方法实现

    IDEA修改生成jar包名字的两种方法实现

    本文主要介绍了IDEA修改生成jar包名字的两种方法实现,通过简单的步骤,您可以修改项目名称并在打包时使用新的名称,具有一定的参考价值,感兴趣的可以了解下
    2023-08-08
  • Spring-data-JPA使用时碰到的问题以及解决方案

    Spring-data-JPA使用时碰到的问题以及解决方案

    这篇文章主要介绍了Spring-data-JPA使用时碰到的问题以及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • idea git未提交代码文件名字变色(图解)

    idea git未提交代码文件名字变色(图解)

    这篇文章主要介绍了idea git未提交代码文件名字变色,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-04-04

最新评论