环境准备:引入 spring-boot-starter-web 启动器依赖
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 33 34 35 36 37 38 39 40 41 42 43 44
| @Data @TableName("pms_brand") public class BrandEntity implements Serializable { private static final long serialVersionUID = 1L;
@TableId private Long brandId;
@NotBlank(message = "品牌名不能为空") private String name;
@NotBlank(message = "品牌logo地址不能为空") @URL(message = "品牌logo地址必须是一个合法的url地址") private String logo;
@NotBlank(message = "品牌介绍不能为空") private String descript;
@NotNull(message = "品牌状态不能为空") private Integer showStatus;
@NotBlank(message = "检索首字母不能为空") @Pattern(regexp = "^[a-zA-Z]$", message = "检索首字母必须在a-z或者A-Z范围内") private String firstLetter;
@NotNull private Integer sort;
}
|
如上使用 @NotBlank、@URL、@Pattern 等校验注解对实体类对应字段进行校验,要开启校验注解,还需要在映射方法入参前加上注解 @Valid,例如下述代码:
1 2 3 4 5
| @RequestMapping("/save") public R save(@Valid @RequestBody BrandEntity brand) { brandService.save(brand); return R.ok(); }
|
2. 分组校验
在一下特殊场合,可能需要进行分组校验,观察 BrandEntity 类 brandId 字段,当我们调用新增方法时,brandId 需要为空。在进行更新方法时,brandId 不能为空。为了实现这种分组校验效果,我们可以使用注解中的 groups 参数来实现。
2.1 实现分组接口
创建一个 AddGroup 和 UpdateGroup 接口,接口内不需要任何方法和属性,接口仅作为唯一标识使用。
2.2 声明分组
如下我们在 brandId 字段上使用多个分组,如下代码所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Data @TableName("pms_brand") public class BrandEntity implements Serializable { private static final long serialVersionUID = 1L;
@NotNull(message = "更新品牌时品牌id不能为空", groups = {UpdateGroup.class}) @Null(message = "新增品牌时品牌id必须为空", groups = {AddGroup.class}) @TableId private Long brandId; }
|
注意:开启分组后,原有没有指定分组的注解会失效,所以需要对使用校验注解的字段开启分组
2.3 开启分组
这里不再使用 @Valid 注解,而是使用 @Validated 注解,该注解支持指定校验分组,如下代码所示:
1 2 3 4 5 6 7 8 9 10
|
@RequestMapping("/save") public R save(@Validated(value = AddGroup.class) @RequestBody BrandEntity brand) { brandService.save(brand); return R.ok(); }
|
3. 自定义校验注解
@Pattern 注解只适用于字符串,目前 BrandEntity 中的 showStatus 字段仅接收 0 和 1 的整数,我们可以实现自定义校验注解来实现这种效果。
3.1 创建注解
其中 message 、groups 和 payload 为校验注解的三个基本方法,不可以缺少。values 方法则为自定义方法,表示传入的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
@Documented @Constraint(validatedBy = { ListValueConstraintValidator.class }) @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) @Retention(RUNTIME) public @interface ListValue {
String message() default "{com.atguigu.common.validate.ListValue.message}";
/** 分组 */ Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
int[] values() default { }; }
|
message 方法用于从默认名为 ValidationMessage.properties 的配置文件中读取自定义的提示信息,因此需要在 resources 文件夹下创建 ValidationMessage.properties 配置文件,内容如下:
1 2
| ## 自定义校验注解默认消息提示配置 com.atguigu.common.validate.ListValue.message=不合法的参数值
|
3.2 创建注解校验器
@Constraint 注解用于指定自定义校验器,@Constraint 注解内容如下所示:
其中 validateBy 方法指明传入的参数必须是 ConstraintValidator 接口的实现类,同时需要指明泛型,查看如下注释信息。第一个泛型表示自定义注解 ListValue 类型,第二个则是注解使用在的目标字段类型,由于我们使用自定义注解是作用在 BrandEntity 中的 Integer 类型的 showStatus 的字段上,因此第二个泛型为 Integer。
下面我们创建自定义注解校验器,代码如下所示:
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
|
public class ListValueConstraintValidator implements ConstraintValidator<ListValue, Integer> {
private Set<Integer> dataSet = new HashSet<>();
@Override public void initialize(ListValue constraintAnnotation) { int[] values = constraintAnnotation.values(); if (values != null) { for (int val : values) { dataSet.add(val); } } }
@Override public boolean isValid(Integer value, ConstraintValidatorContext context) { return dataSet.contains(value); } }
|
然后需要在 @ListValue 注解中指明使用的校验器即可,如:@Constraint(validatedBy = { ListValueConstraintValidator.class })
。
3.3 使用自定义注解
最后在 BrandEntity 的 showStatus 字段上使用 @ListValue 注解即可实现相应校验功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Data @TableName("pms_brand") public class BrandEntity implements Serializable {
@NotNull(message = "品牌状态不能为空", groups = {AddGroup.class, UpdateGroup.class, UpdateStatusGroup.class}) @ListValue(values = {0, 1}, groups = {AddGroup.class, UpdateGroup.class, UpdateStatusGroup.class}) private Integer showStatus;
}
|