Spring Validation 使用笔记

   最早在传统 Spring MVC 项目里,因为前端对接数据都是后端程序员自己对接的,入参很明确,后端的参数校验自然可有可无,主要看项目的安全要求和工期要求。因此后端参数校验虽然很早就用,但是断断续续,不甚了了。

   这几年,项目基本都是前后端分离模式,后端必要的参数校验自然不可少。每次使用,总是要在网上查找相应注解;同时有些不常用用法或奇怪 BUG 在做完后没及时总结,再一次遇到才后悔莫及。

   因此,开一篇专门的笔记,来记录常用的注解和用法以供工作中查阅,希望能坚持逐渐完善吧。


一、常用注解

注解 作用
@Null 验证对象是否为 null
@NotNull 验证对象是否不为 null, 无法查检长度为 0 的字符串
@NotBlank 字符串不为 null,并且字符串 trim()以后 length 要大于 0
@NotEmpty 集合或字符串不为空
@AssertTrue Boolean 对象是否为 true
@AssertFalse Boolean 对象是否为 false
@Size(min=, max=) 验证对象(Array, Collection , Map, String)长度是否在给定的范围之内
@Length(min=, max=) 验证字符串长度介于 min 和 max 之间
@Past 验证 Date 和 Calendar 对象是否在当前时间之前,验证成立的话被注释的元素一定是一个过去的日期
@PastOrPresent 过去或者现在
@Future 验证 Date 和 Calendar 对象是否在当前时间之后 ,验证成立的话被注释的元素一定是一个将来的日期
@FutureOrPresent 将来或者现在
@Min 验证 Number 和 String 对象是否大等于指定的值
@Max 验证 Number 和 String 对象是否小等于指定的值
@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过 BigDecimal 定义的最大值的字符串表示 . 小数 存在精度
@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过 BigDecimal 定义的最小值的字符串表示 . 小数 存在精度
@Digits(integer=,fraction=) 数字格式检查。integer 指定整数部分的最大长度,fraction 指定小数部分的最大长度
@Positive 数字,正数
@PositiveOrZero 数字,正数或 0
@Negative 数字,负数
@NegativeOrZero 数字,负数或 0
@Range(min=, max=) 被指定的元素必须在合适的范围内
@Pattern(regex=) 字符串必须匹配正则表达式
@Valid 嵌套验证、级联验证,如对象属性

二、校验方式

  1. 在 Controller 方法参数前加 @Valid 注解
    a) 此处,@Valid 可以换成 @Validated;这两个有一些细节差别,待后期使用中完善吧;
    b) @Valid 位置也可以放置在方法上或类上,产生的验证范围会发生变化,习惯放于参数前,更灵活;
    c) 在验证参数后面加 BindingResult bindingResult,bindingResult 会自动接收错误信息。
  2. 手动校验
    a) 如果我们的数据不是来自接口传值,没有通过 Controller 层,但是又希望验证 Bean 的参数有效性,那么可以通过手动调用 ValidatorFactory 来进行校验;
    b) 示例如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // Bean 验证器
    ValidatorFactory vf = Validation.buildDefaultValidatorFactory();
    Validator validator = vf.getValidator();
    // 校验的业务对象:demo,Bean 类型:Demo
    Set<ConstraintViolation<Demo>> checkSet = validator.validate(demo);
    if (CollectionUtils.isNotEmpty(checkSet)) {
    // Bean 验证不通过
    throw new ServiceException(checkSet.stream().map(ConstraintViolation::getMessage).collect(Collectors.joining(",")));
    }

三、问题记录

  1. 级联验证
    a) 在 Bean 中存在对象属性或集合属性,需要级联验证对象中的属性时,需在属性上加“@Valid”注解,之前犯过傻,记录一下;
    b) 示例如下:

    1
    2
    3
    4
    5
    public class DemoDto {

    @Size(min = 1, message = " 集合为空 ")
    @Valid
    private List<Detail> list;
  2. List 集合参数验证
    a) 可能遇到如下情况,保存一组数据,所以入参是对象集合,示例如下:
    b) 这种情况,想要验证集合非空及对象的属性有效性,常规方式是无效的;
    c) 参照网上的解决方式(未验证),既然集合在对象里可以级联验证,那么我们自定义一个集合类,实现 List 接口,示例如下:

    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 ValidatorList<E> implements List<E> {
    @Valid
    private List<E> list;
    /**
    * 关键
    * @return
    */
    public List<E> getList() {
    return list;
    }
    /**
    * 关键
    * @return
    */
    public void setList(List<E> list) {
    this.list = list;
    }
    public ValidatorList() {
    this.list = new ArrayList<E>();
    }
    public ValidatorList(List<E> list) {
    this.list = list;
    }
    }

    // 使用新集合类接收参数
    // 控制器
    @RequestMapping(value = "/save", method = RequestMethod.POST)
    @ResponseBody
    public int save(@Validated @RequestBody ValidList<SaveDto> list, BindingResult bindingResult) {
    // 省略业务代码
    }