@Validated分组校验及扩展

一、介绍

springBoot项目中,我们往往要对参数进行校验,如果在代码中进行,就会显得很杂乱冗余

我在以前有介绍过@Valid注解的使用和扩展,点击传送门进行查看

但上面这篇文章整理相关的知识点有局限性,主要体现在以下方面

  • 没有分组校验

  • 没有嵌套校验

  • 校验都是针对一个字段的,没有多个字段之间关联的校验;比如说开始日期必须小于结束日期

故此,得使用@Validated来进行完善校验。

二、使用

1)分组校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.banmoon.test.controller;

import com.banmoon.test.dto.ResultData;
import com.banmoon.test.obj.request.ValidGroupRequest;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* 分组校验
*
* @author banmoon
*/
@Validated
@RestController
@RequestMapping("/valid")
public class ValidController {

@GetMapping("/group/save")
public ResultData<Void> groupSave(@Validated({ValidGroupRequest.DefaultGroup.class,
ValidGroupRequest.SaveGroup.class}) ValidGroupRequest request) {
return ResultData.success();
}

@GetMapping("/group/update")
public ResultData<Void> groupUpdate(@Validated({ValidGroupRequest.DefaultGroup.class,
ValidGroupRequest.UpdateGroup.class}) ValidGroupRequest request) {
return ResultData.success();
}

}

请求类ValidGroupRequest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.banmoon.test.obj.request;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Null;

/**
* 分組校验请求-入参
*
* @author banmoon
*/
@Data
@NoArgsConstructor
@ApiModel("分組校验请求-入参")
public class ValidGroupRequest {

public interface DefaultGroup {
}

public interface SaveGroup {
}

public interface UpdateGroup {
}

@NotNull(message = "ID不能为空", groups = UpdateGroup.class)
@ApiModelProperty("ID")
private Integer id;

@NotBlank(message = "姓名不能为空", groups = DefaultGroup.class)
@ApiModelProperty("姓名")
private String name;

@Null(message = "性别不能修改", groups = UpdateGroup.class)
@NotNull(message = "性别不能为空", groups = SaveGroup.class)
@ApiModelProperty("性别,1=男,2=女")
private Integer sex;
}

分别请求两个接口,且里面的都不满足

调用/valid/group/save 调用/valid/group/update
image-20230130210459666 image-20230130210854549

在开发中,我不太喜欢这种公用一个请求类的写法。

以为这样每一个需要校验的字段,都需要加上一个group,会写很多很麻烦

这样我还不如,复制粘贴再写一个请求类,从而达到分组的校验效果

2)嵌套校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.banmoon.test.controller;

import com.banmoon.test.dto.ResultData;
import com.banmoon.test.obj.request.ValidBatchSaveRequest;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;

/**
* Valid 校验
*
* @author banmoon
*/
@Validated
@RestController
@RequestMapping("/valid")
public class ValidController {

@PostMapping("/batchSave")
public ResultData<Void> batchSave(@NotEmpty(message = "参数不能为空") @RequestBody List<@Valid ValidBatchSaveRequest> request) {
return ResultData.success();
}

@DeleteMapping("/batchDelete")
public ResultData<Void> batchDelete(@NotEmpty(message = "参数不能为空") @RequestBody List<@NotNull(message = "id不能为空") Integer> idList) {
return ResultData.success();
}

}

对应的请求类,ValidBatchSaveRequest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.banmoon.test.obj.request;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

/**
* @author banmoon
*/
@Data
@NoArgsConstructor
@ApiModel("嵌套校验-入参")
public class ValidBatchSaveRequest {

@NotBlank(message = "姓名不能为空")
@ApiModelProperty("姓名")
private String name;

@NotNull(message = "性别不能为空")
@ApiModelProperty("性别,1=男,2=女")
private Integer sex;
}

请求/valid/batchSave时,两种情况

当外部的List校验失败时 内部的类校验失败时
image-20230130220434638 image-20230130220342548

请求/valid/batchDelete时,也是两种情况

当外部的List校验失败时 内部的包装类校验失败时
image-20230130220614265 image-20230130220546107

如果请求类中还有其它的,需要校验的实体类,则在上面打上一个@Valid注解即可

由于List集合有点特殊,它需要在指定泛型的地方打上@Valid,这样才可以对集合中的每一个对象进行校验

3)多字段联动校验

如何进行多字段之间的联动校验,就像开头讲到的那个例子一样,开始日期必须小于结束日期

这样如何使用@Valid进行联动校验呢,我们只需要这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.banmoon.test.controller;

import com.banmoon.test.dto.ResultData;
import com.banmoon.test.obj.request.ValidFieldRelevanceRequest;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

/**
* Valid 校验
*
* @author banmoon
*/
@Validated
@RestController
@RequestMapping("/valid")
public class ValidController {

@PostMapping("/fieldRelevance")
public ResultData<Void> fieldRelevance(@Valid ValidFieldRelevanceRequest request) {
return ResultData.success();
}

}

重点是里面这个校验注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.banmoon.test.obj.request;

import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.NotNull;
import java.util.Date;

/**
* 字段关联校验
*
* @author banmoon
*/
@Data
@NoArgsConstructor
@ApiModel("字段关联校验-入参")
public class ValidFieldRelevanceRequest {

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@NotNull(message = "开始时间不能为空")
@ApiModelProperty("开始时间")
private Date beginDate;

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@NotNull(message = "结束时间不能为空")
@ApiModelProperty("结束时间")
private Date endDate;

@AssertTrue(message = "结束时间必须大于开始时间")
@ApiModelProperty(hidden = true)
public boolean getValid() {
return this.beginDate.compareTo(endDate) < 0;
}
}

请求查看效果

image-20230131200736598

三、最后

我是半月,你我一同共勉!!!