一、Bean Validation 和 Hibernate Validation

前者是数据校验的一套规范,是接口,没有实现

而后者是此规范的参考实现,并对前者进行了扩展。

二、传统方式的参数校验

2.1、创建一个Java Bean

定义各属性的校验规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Data
public class Person {
private Long id;
/**
* 不为null且不为空白字符串(""、" ")
*/
private String name;
/**
* 在1-800之间
*/
private Integer age;
/**
* 符合邮箱格式
*/
private String email;
/**
* 符合手机格式
*/
private String phone;
/**
* 必须在当前日期之前
*/
private LocalDateTime birthday;
}

2.2、创建一个测试类,使用传统方式进行校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/***
* 在此方法中,使用传统方式校验bean
* @param person
*/
public static void valid(Person person) {
//校验name
String name = person.getName();
if(name == null || "".equals(name) || "".equals(name.trim())) {
throw new RuntimeException("name不符合校验规则!");
}
//校验年龄属性
Integer age = person.getAge();
if(age < 1 || age > 800) {
throw new RuntimeException("年龄属性不符合校验规则!");
}
//校验邮箱属性
String email = person.getEmail();
String emailReg = "^[a-z0-9A-Z]+[- | a-z0-9A-Z . _]+@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\\\.)+[a-z]{2,}$";
if(!email.matches(emailReg)) {
throw new RuntimeException("邮箱不符合格式!");
}
...
}

2.3、弊端

  1. 代码复用率低,代码的可维护性会随着校验规则的增多而降低,且这种参数校验方法看起来有点笨拙。
  2. 对于一些复杂的校验规则,难以实现。

三、常用的校验约束注解

3.1、Bean Validation 中内置的约束

1、@Null

被注释的元素必须为 null

2、@NotNull

被注解的元素必须不为 null

3、@NotEmpty

被注释的 集合 (size > 0)

被注释的字符串 不为空且 不等于空串

4、@AssertTrue

被注释的元素必须为true

5、@AssertFalse

被注释的元素必须为false

6、@Min(value)

被注释的元素必须为一个数字,且值必须大于等于value

7、@Max(value)

被注释的元素必须为一个数字,且值必须小于等于value

8、@DecimalMin(value)

被注释的元素必须是一个数字,其值必须大于等于指定的最小值

9、@DecimalMax(value)

被注释的元素必须是一个数字,其值必须小于等于指定的最大值

10、@Size(max,min)

被注释的元素的大小必须在指定的范围内

11、@Digits(integer,fraction)

被注释的元素的大小必须是一个数字,其值必须在可接受的范围内

12、@Past

被注释的元素必须是一个过去的日期

13、@Future

被注释的元素必须是一个将来的日期

14、@Pattern(value)

被注释的元素必须符合指定的正则表达式

15、@Email

被注释的元素必须为电子邮箱地址

3.2、Hibernate Validator 附加的约束

1、@Length

被注释的字符串大小必须在指定的范围内

2、@Range

被注释的元素必须在合适的范围内

3、@URL

被注释的元素必须为一个 url

四、Spring Boot中配合统一异常处理类进行参数校验

4.1、引入相关依赖

在 Spring Boot 2.2.1.RELEASE 版本中,spring-boot-starter-web 中包含了 spring-boot-starter-validation 的相关依赖,所以无需额外引入

image-20210405151508096

4.2、创建 Bean

在Bean属性上添加参数校验规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Data
public class UserDTO {
@NotBlank(message = "用户名不能为空!")
private String userName;
@NotBlank(message = "手机号不能为空!")
@Pattern(regexp = "^((13[0-9])|(14[5-9])|(15([0-3]|[5-9]))|(16[6-7])|(17[1-8])|(18[0-9])|(19[1|3])|(19[5|6])|(19[8|9]))\\d{8}$",message = "手机号不合格式")
private String mobile;

@Email(message = "邮箱不合法")
@NotBlank(message = "邮箱不能为空!")
private String email;

@Min(value = 1,message = "年龄必须在1-800之间")
@Max(value = 800,message = "年龄必须在1-800之间")
private Integer age;
}

4.3、创建统一返回结果

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
@Data
@ApiModel(value = "全局统一返回结果")
public class R {

@ApiModelProperty(value = "是否成功")
private Boolean success;

@ApiModelProperty(value = "返回码")
private Integer code;

@ApiModelProperty(value = "返回消息")
private String message;

@ApiModelProperty(value = "返回数据")
private Map<String, Object> data = new HashMap<String, Object>();

public R(){}

public static R ok(){
R r = new R();
r.setSuccess(ResultCodeEnum.SUCCESS.getSuccess());
r.setCode(ResultCodeEnum.SUCCESS.getCode());
r.setMessage(ResultCodeEnum.SUCCESS.getMessage());
return r;
}

public static R error(){
R r = new R();
r.setSuccess(ResultCodeEnum.UNKNOWN_REASON.getSuccess());
r.setCode(ResultCodeEnum.UNKNOWN_REASON.getCode());
r.setMessage(ResultCodeEnum.UNKNOWN_REASON.getMessage());
return r;
}

public static R setResult(ResultCodeEnum resultCodeEnum){
R r = new R();
r.setSuccess(resultCodeEnum.getSuccess());
r.setCode(resultCodeEnum.getCode());
r.setMessage(resultCodeEnum.getMessage());
return r;
}

public R success(Boolean success){
this.setSuccess(success);
return this;
}

public R message(String message){
this.setMessage(message);
return this;
}

public R code(Integer code){
this.setCode(code);
return this;
}

public R data(String key, Object value){
this.data.put(key, value);
return this;
}

public R data(Map<String, Object> map){
this.setData(map);
return this;
}
}

4.4、创建统一异常处理类,对参数校验结果进行封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public R handleValidationExceptions(MethodArgumentNotValidException methodArgumentNotValidException) {
Map<String, Object> errors = new HashMap<>();
methodArgumentNotValidException.getBindingResult().getAllErrors().stream().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
return R.error().data(errors);
}
}

4.5、创建Controller

在参数列表的对象前使用@Validated注解,开启校验

1
2
3
4
5
6
7
8
9
@RestController
@RequestMapping("/userDto")
public class UserDTOController {
@PostMapping("/add")
public R addUser(@RequestBody @Validated UserDTO userDTO) {
System.out.println(userDTO);
return R.ok().data("user",userDTO);
}
}

使用Swagger进行测试

image-20210405152901568

点击 execute ,查看结果

image-20210405152922769

五、校验组

校验组可以对需要校验的字段进行分类,即为每个字段提供不同的校验规则。校验组只需定义简单的接口即可。

比如说,在更新UserDTO时,我们可以让传入的UserDTO对象的某些属性为空,但ID不为空,此时我们可以使用教研组进行区分

5.1、为UserDTO添加ID属性,并创建校验组

1、创建两个校验组

  • 保存校验组,在保存方法中起作用
1
2
public interface SaveGroup {
}
  • 更新校验组,在更新方法中起作用
1
2
public interface UpdateGroup {
}

2、为UserDTO添加ID属性

1
2
@NotBlank(message = "传入id不能为空!",groups = UpdateGroup.class)
private Long id;

3、为其他属性的校验规则添加校验组

这里需要注意,对于格式的校验(手机号、邮箱)可以不添加校验组,因为无论是添加操作还是更新操作都要求传入的参数必须符合格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Data
public class UserDTO {
@NotNull(message = "传入id不能为空!",groups = UpdateGroup.class)
private Long id;


@NotBlank(message = "用户名不能为空!",groups = SaveGroup.class)
private String userName;

@NotBlank(message = "手机号不能为空!",groups = SaveGroup.class)
@Pattern(regexp = "^((13[0-9])|(14[5-9])|(15([0-3]|[5-9]))|(16[6-7])|(17[1-8])|(18[0-9])|(19[1|3])|(19[5|6])|(19[8|9]))\\d{8}$",message = "手机号不合格式")
private String mobile;

@Email(message = "邮箱不合法")
@NotBlank(message = "邮箱不能为空!",groups = SaveGroup.class)
private String email;

@Min(value = 1,message = "年龄必须在1-800之间",groups = SaveGroup.class)
@Max(value = 800,message = "年龄必须在1-800之间",groups = SaveGroup.class)
private Integer age;
}

5.2、在Controller方法体的@Validated注解中指定校验组

1、在添加方法中指定校验组为 SaveGroup

1
2
3
4
5
@PostMapping("/add")
public R addUser(@RequestBody @Validated(value = SaveGroup.class) UserDTO userDTO) {
System.out.println(userDTO);
return R.ok().data("user",userDTO);
}

打开 Swagger 进行测试

image-20210405154444542

查看结果,发现只对 SaveGroup 校验组的属性进行校验,由于 id 属性不属于 SaveGroup ,所以不会对id属性进行校验

image-20210405154457791

2、新增一个Update方法,指定校验组为 UpdateGroup

1
2
3
4
5
@PutMapping("/edit")
public R editUser(@RequestBody @Validated(value = UpdateGroup.class) UserDTO userDTO) {
System.out.println(userDTO);
return R.ok().data("user",userDTO);
}

打开Swagger,进行测试

image-20210405155002199

查看结果,可以看到当前方法只对 UpdateGroup 组的属性进行了校验

image-20210405155031414

六、对传入的简单参数进行校验

6.1、编写一个简单的查询方法(根据姓名查询)

对传入的姓名进行校验

1
2
3
4
5
6
7
@GetMapping("/getByName/{name}")
public R getByName(@PathVariable("name") @NotBlank(message = "传入的姓名不能为空!") String name) {
System.out.println("传入的参数为:" + name);
UserDTO userDTO = new UserDTO();
userDTO.setUserName(name);
return R.ok().data("user",userDTO);
}

6.2、在Controller上添加@Validated注解

对传入的简单参数进行校验时,需要将@Validated注解添加在控制器上。

1
2
3
4
5
6
@Validated
@RestController
@RequestMapping("/userDto")
public class UserDTOController {

}

6.3、测试

打开Swagger进行测试

image-20210405160342849

这个时候抛出的异常为 ConstraintViolationException 异常

image-20210405160431445

6.4、对 ConstraintViolationException 进行处理

由于上面抛出的异常是我们没有进行捕获的异常,所以我们需要在统一异常处理类中对参数校验结果进行封装

1
2
3
4
5
6
@ExceptionHandler(ConstraintViolationException.class)
public R handleConstraintViolationException(ConstraintViolationException exs) {
Map<String, Object> errors = new HashMap<>();
exs.getConstraintViolations().forEach(err -> errors.put(err.getPropertyPath().toString(), err.getMessage()));
return R.error().data(errors);
}

6.5、再次进行测试

使用swagger进行测试

image-20210405161339916

查看结果

image-20210405161402333

七、嵌套校验

当一个bean中存在另外一个Bean属性时,我们可以使用嵌套校验,只需要在bean属性上添加 @Valid 注解即可

7.1、创建一个 Card 实体类

并添加参数校验规则

1
2
3
4
5
6
7
8
@Data
public class Card {
@NotNull(message = "卡号不能为空!")
private Long cardId;

@NotBlank(message = "手机号不能为空")
private String phone;
}

7.2、为UserDTO创建一个Card属性

并在该属性上添加@Valid注解,进行嵌套校验

1
2
3
@NotNull(message = "卡信息不能为空!")
@Valid
private Card card;

7.3、测试

这里需要先去掉 添加 方法中的校验组限制

image-20210405162535573

查看结果

image-20210405162550469

八、自定义校验注解

创建一个用于校验手机号是否合法的注解

8.1、创建一个注解 @Phone

这个注解只能加在字段上

其中 @Constraint(validatedBy = PhoneValidator.class) 表明这个注解修饰的属性将被哪个类完成校验

1
2
3
4
5
6
7
8
9
10
11
12
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
// 说明当前注解将被哪个类完成校验
@Constraint(validatedBy = PhoneValidator.class)
public @interface Phone {

String message() default "传入的手机号码格式有误";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};
}

8.2、创建 PhoneValidator

这个类用于校验 @Phone 注解修饰的属性,需要实现 ConstraintValidator<K,V> 接口

其中泛型 K 表示这个类需要校验的注解,而泛型 V 表示注解修饰属性的类(如果要校验的属性是String类型的手机号,就填入String)

重写 isValid 方法,这个方法用于校验并返回结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/***
* 校验类需要实现ConstraintValidator接口。
* 接口使用了泛型,需要指定两个参数,第一个自定义注解类,第二个为需要校验的数据类型。
* isValid就是校验方法
*/
public class PhoneValidator implements ConstraintValidator<Phone,String> {
public static final String PHONE_REGEX = "^((13[0-9])|(14[5-9])|(15([0-3]|[5-9]))|(16[6-7])|(17[1-8])|(18[0-9])|(19[1|3])|(19[5|6])|(19[8|9]))\\d{8}$";
@Override
public boolean isValid(String phone, ConstraintValidatorContext constraintValidatorContext) {
if(phone == null || "".equals(phone) || "".equals(phone.trim())) {
return false;
}
return Pattern.matches(phone,PHONE_REGEX);
}
}

8.3、测试自定义的校验注解

1、为UserDTO创建一个phone属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Data
public class UserDTO {
@NotNull(message = "传入id不能为空!")
private Long id;


@NotBlank(message = "用户名不能为空!")
private String userName;

@Email(message = "邮箱不合法")
@NotBlank(message = "邮箱不能为空!")
private String email;

@Min(value = 1,message = "年龄必须在1-800之间")
@Max(value = 800,message = "年龄必须在1-800之间")
private Integer age;

@Phone(message = "传入的手机号不合法!")
private String phone;
}

8.2、使用Swagger进行测试

当传入的 phone 不合法时

image-20210405165647918

结果

image-20210405165703945

传入的 phone 为null时

image-20210405170057370

结果

image-20210405170108082

九、@Valid 和 @Validated的区别

9.1、使用位置

  • @Validated:可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上
  • @Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上

9.2、是否支持分组校验

  • @Validated支持分组校验

使用注解的value属性指定校验组,校验组可以有多个

1
2
3
4
5
6
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Validated {
Class<?>[] value() default {};
}
  • @Valid不支持分组

在controller层的方法的要校验的参数上添加@Valid注解,并且需要传入 BindingResult 对象,用于获取校验失败情况下的反馈信息

9.3、@Validated支持多个模型对象的校验

在方法参数列表中,如果有多个Bean对象需要校验,那么可以在每个Bean对象前添加@Validated注解

9.4、嵌套校验

如果一个Bean中含有另外一个Bean属性,那么可以在内部Bean属性上添加@Valid注解来开启嵌套查询。

而@Validated不能添加在属性上,所以不能开启嵌套校验

9.5、校验方法入参

在使用@NotNull验证方法入参时,需要在控制器类上添加@Validated注解开启校验

十、谷粒商城使用 validation 进行后端校验

10.1、在 Brand 实体类上的属性上添加校验注解

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@TableName("pms_brand")
@ApiModel(value = "Brand对象")
@EqualsAndHashCode(callSuper = false)
public class Brand implements Serializable {
private static final long serialVersionUID = 1L;

/**
* 品牌id
*/
@TableId(value = "brand_id",type = IdType.AUTO)
@ApiModelProperty(value = "品牌id")
private Long brandId;
/**
* 品牌名
*/
@NotBlank(message = "品牌名不能为空!")
@ApiModelProperty(value = "品牌名")
private String name;
/**
* 品牌logo地址
*/
@NotEmpty(message = "Logo不能为空!")
@URL(message = "Logo必须是一个合法的 URL 地址")
@ApiModelProperty(value = "品牌logo地址")
private String logo;
/**
* 介绍
*/
@NotBlank(message = "品牌介绍不能为空!")
@ApiModelProperty(value = "介绍")
private String description;
/**
* 显示状态[0-不显示;1-显示]
*/
@NotNull(message = "显示状态不能为空!")
@Min(value = 0,message = "显示状态必须为0 或 1")
@Max(value = 1,message = "显示状态必须为0 或 1")
@TableLogic(value = "1",delval = "0")
@ApiModelProperty(value = "显示状态[0-不显示;1-显示]")
private Integer showStatus;
/**
* 检索首字母
*/
@NotBlank(message = "检索首字母不能为空!")
@Pattern(regexp = "/^[a-zA-Z]$/",message = "检索首字母必须是一个字母")
@ApiModelProperty(value = "检索首字母")
private String firstLetter;
/**
* 排序
*/
@NotNull(message = "排序不能为空!")
@Min(value = 0, message = "排序必须大于等于0")
@ApiModelProperty(value = "排序")
private Integer sort;

}

10.2、统一异常处理

  • 需要在 Controller 方法需要校验的对象前使用 @Valid 注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RestControllerAdvice(basePackages = "com.hzx.grain")
public class GrainMallExceptionControllerAdvice {
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public R handleNotValidException(MethodArgumentNotValidException e) {
BindingResult bindingResult = e.getBindingResult();
Map<String, String> errorMap = new HashMap<>();
bindingResult.getFieldErrors().forEach((fieldError) -> {
errorMap.put(fieldError.getField(), fieldError.getDefaultMessage());
});
return R.error(ResultCodeEnum.NOT_VALID_EXCEPTION.getCode(), ResultCodeEnum.NOT_VALID_EXCEPTION.getMsg()).put("data",errorMap);
}
@ExceptionHandler(value = Exception.class)
public R handleException(Exception e) {
return R.error(ResultCodeEnum.UN_KNOW_EXCEPTION.getCode(), ResultCodeEnum.UN_KNOW_EXCEPTION.getMsg());
}
}

10.3、添加分组校验

在进行新增品牌对象时,不能指定 ID ,在修改时必须携带 ID

1、创建两个校验组,分别为 AddGroupUpdateGroup

只需要创建两个空接口即可

1
2
3
public interface AddGroup/UpdateGroup {

}

2、修改实体类

由于新增、修改都需要指定品牌名,所以为品牌 name 分组时需要指定两个分组,即修改校验组和新增校验组。

没有指定校验组的注解不会生效,所以我们需要为所有属性添加校验组

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@TableName("pms_brand")
@ApiModel(value = "Brand对象")
@EqualsAndHashCode(callSuper = false)
public class Brand implements Serializable {
private static final long serialVersionUID = 1L;

/**
* 品牌id
*/
@NotNull(message = "修改时必须指定ID",groups = UpdateGroup.class)
@Null(message = "新增时不能指定 ID",groups = AddGroup.class)
@TableId(value = "brand_id",type = IdType.AUTO)
@ApiModelProperty(value = "品牌id")
private Long brandId;
/**
* 品牌名
*/
@NotBlank(message = "品牌名不能为空!",groups = {UpdateGroup.class, AddGroup.class})
@ApiModelProperty(value = "品牌名")
private String name;
/**
* 品牌logo地址
*/
@NotEmpty(message = "Logo不能为空!",groups = {AddGroup.class})
@URL(message = "Logo必须是一个合法的 URL 地址",groups = {UpdateGroup.class, AddGroup.class})
@ApiModelProperty(value = "品牌logo地址")
private String logo;
/**
* 介绍
*/
@NotBlank(message = "品牌介绍不能为空!",groups = {AddGroup.class})
@ApiModelProperty(value = "介绍")
private String description;
/**
* 显示状态[0-不显示;1-显示]
*/
@NotNull(message = "显示状态不能为空!",groups = {AddGroup.class})
@Min(value = 0,message = "显示状态必须为0 或 1",groups = {UpdateGroup.class, AddGroup.class})
@Max(value = 1,message = "显示状态必须为0 或 1",groups = {UpdateGroup.class, AddGroup.class})
@TableLogic(value = "1",delval = "0")
@ApiModelProperty(value = "显示状态[0-不显示;1-显示]")
private Integer showStatus;
/**
* 检索首字母
*/
@NotBlank(message = "检索首字母不能为空!",groups = {AddGroup.class})
@Pattern(regexp = "/^[a-zA-Z]$/",message = "检索首字母必须是一个字母",groups = {UpdateGroup.class, AddGroup.class})
@ApiModelProperty(value = "检索首字母")
private String firstLetter;
/**
* 排序
*/
@NotNull(message = "排序不能为空!",groups = {AddGroup.class})
@Min(value = 0, message = "排序必须大于等于0",groups = {UpdateGroup.class, AddGroup.class})
@ApiModelProperty(value = "排序")
private Integer sort;

}

3、修改 Controller

将原来的 @Valid 换为 @Validated 注解,然后在注解中指定此 Controller 接口使用的校验组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 保存
*/
@PostMapping("save")
@ApiOperation("保存品牌信息")
public R save(@Validated({AddGroup.class}) @RequestBody Brand brand){
brandService.save(brand);
return R.ok();
}

/**
* 修改
*/
@PostMapping("update")
@ApiOperation("更新品牌信息")
public R update(@Validated({UpdateGroup.class}) @RequestBody Brand brand){
brandService.updateStatus(brand);
return R.ok();
}

10.4、自定义校验注解

1、创建自定义注解

这个注解用于校验 showStatus ,其中 showStatus 不能为空,且只能为 0 或 1

1
2
3
4
5
6
7
8
9
10
@Documented
@Constraint(validatedBy = {AllowValuesValidator.class})
@Target( {ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE} )
public @interface AllowValues {
String message() default "{com.hzx.grain.common.valid.AllowValues.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
// 可以包含的值
int[] values() default { };
}

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
public class AllowValuesValidator implements ConstraintValidator<AllowValues, Integer> {
private Set<Integer> set = new HashSet<>();


/**
* 初始化方法
* @param constraintAnnotation
*/
@Override
public void initialize(AllowValues constraintAnnotation) {
int[] values = constraintAnnotation.values();
for (int value : values) {
set.add(value);
}
}

/***
* 判断是否校验成功
* @return
*/
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
return set.contains(value);
}
}

3、添加自定义注解

1
2
3
4
5
6
7
8
/**
* 显示状态[0-不显示;1-显示]
*/
@NotNull(message = "状态不能为空!",groups = {AddGroup.class})
@AllowValues(values = {0,1},groups = {UpdateGroup.class, AddGroup.class})
@TableLogic(value = "1",delval = "0")
@ApiModelProperty(value = "显示状态[0-不显示;1-显示]")
private Integer showStatus;

4、测试