Spring Validation的校驗順序問題及解決過程
問題場景
測試發(fā)現(xiàn)對同一個接口調(diào)用多次時,返回的校驗異常信息不同,經(jīng)過問題追蹤,入?yún)嶓w類代碼如下:
@Data
public class EditDevNameDto {
@NotBlank(message = "deviceSn must not null")
private String deviceSn;
@NotBlank(message = "deviceName must not null")
private String deviceName;
}
當這個接口入?yún)⒌膁eviceSn和deviceName均為空值時,調(diào)用多次的話會出現(xiàn)兩個msg錯誤信息循環(huán)返回的問題。
原理剖析
懷疑是調(diào)用接口時,校驗注解的先后順序是不確定的,所以,可能deviceSn先被校驗,可能deviceName先被校驗,那要解決這個問題就要規(guī)定校驗的順序才行。
解決方法
使用@GroupSequence注解實現(xiàn)順序的穩(wěn)定性。
創(chuàng)建五個接口
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控制層代碼
注意在入?yún)⒅屑尤隌Validated(Group.class)注解,其中要加入被@GroupSequence修飾的類對象。
@PostMapping("/edit_device_name")
public ExecuteResult editDevName(
@RequestBody @Validated(Group.class) EditDevNameDto dev) {
// -----邏輯代碼
return null;
}
修改實體類代碼
在實體類中使用校驗注解中添加groups屬性,順序按照@GroupSequence類規(guī)定的順序即可。
@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;
}
整改結(jié)果
當這個接口入?yún)⒌膁eviceSn和deviceName均為空值時,頻繁調(diào)用依然是按照先校驗deviceSn,后校驗deviceName的順序進行參數(shù)校驗。
后續(xù)問題
問題原因
解決了上面的問題,過了幾天,又出現(xiàn)了解決校驗順序的問題,但是這次又不同于上一次,這次的Dto參數(shù)接收類有些復(fù)雜,代碼如下:
@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;
}
以上代碼中有兩個類,共同組合成參數(shù)接收類,要糾正校驗順序混亂問題,還是需要用到一開始講到的@GroupSequence注解,但是,有兩個問題:
- Dto中還有一個對象類型的屬性。
- 對象類型屬性中的子屬性(id、channelId)也要成功校驗
解決方案
首先,為了讓Dto中的對象類型的屬性也能正常校驗,需要添加@Valid注解;
然后,在對象類型屬性中的子屬性中也需要像文章前面所說的在校驗注解中設(shè)置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中校驗屬性的注解不設(shè)置groups,CommonDto中的校驗屬性就會失效,這是個大坑。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
- javax.validation在Spring?Boot請求中使用方式
- spring中的參數(shù)校驗技術(shù):jakarta.validation使用詳解
- SpringBoot @ConfigurationProperties + Validation實現(xiàn)啟動期校驗解決方案
- Spring Validation數(shù)據(jù)校驗詳解
- SpringBoot利用validation實現(xiàn)數(shù)據(jù)校驗完整指南
- 基于Spring Validation實現(xiàn)全局參數(shù)校驗異常處理的示例詳解
- 如何在Spring Boot 項目中自定義 Validation 注解
相關(guān)文章
Java網(wǎng)絡(luò)編程TCP實現(xiàn)聊天功能
這篇文章主要為大家詳細介紹了Java網(wǎng)絡(luò)編程TCP實現(xiàn)聊天功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-07-07
SpringBoot源碼閱讀之spring.factories的加載機制詳解
Spring Boot通過`spring.factories`文件實現(xiàn)自動裝配,該文件位于`META-INF`目錄下,Spring Boot在啟動時會讀取該文件并實例化其中配置的實現(xiàn)類2025-11-11

