SpringBoot Validation
Validation
使用springboot的validation进行参数校验。
引入依赖
1 |
|
注解
在validation中定义了一系列约束(constraint)注解。
注解 | 功能 |
---|---|
@NotNull | 不能为Null,可以为空 |
@Null | 必须为null |
@NotBlank | 字符串不能为null,trim()后不能为"",至少有一个非空白字符 |
@NotEmpty | 不能为null,集合,数组,mao等size不能为0,字符串可以是空白字符 |
@Max(value) | 注解元素须是数值类型,不支持float,double,最大不超过该值 |
@Min(value) | 注解元素须是数值类型,不支持float,double,最小不小于该值 |
@Positive | 判断数字是否为正数 |
@PositiveOrZero | 判断正数或零 |
@Negative | 判断数字是否为负数 |
@NegativeOrZero | 判断负数或零 |
@Digits(integer,fraction) | 必须为数字,且整数位数和小数位数必须在指定范围 |
@Size(min,max) | 字符串长度,或集合,数组,map等size必须在指定范围内, |
字符串必须是email格式 | |
@Length(min,max) | 注解对象只能是字符串,字符串长度必须在指定范围 |
@AssertFalse | 可以为null,不为null必须为false |
@AssertTrue | 可以为null,不为null必须为true |
@Past | 注解元素须为日期时间,判断是否是过去的日期 |
@PastOrPresent | 判断日期是否是过去或现在 |
@Future | 注解元素须为日期时间,判断是否是未来的日期 |
@FutureOrPresent | 判断日期是否是未来或现在 |
@Pattern(value) | 判断是否符合正则表达式 |
@Valid和@Validated
@Valid
可以添加在方法参数,方法返回,成员变量,普通方法,构造方法上,表示需要进行约束校验。
@Validated
可以添加在类,方法参数,普通方法上,进行约束校验,支持分组校验。
一般来说,这两个都放在要加校验的方法参数前。
两者容易搞混。
它们的区别有:
@Valid
可以递归校验,即如果A类中有一个B类变量,而B类中也有约束注解,那么在检查A类约束时,会自动检查B类中的成员变量,而@Validated
不会检查@Validated
可以分组校验,而@Valid
不行
一般来说,在控制器方法参数前使用@Validated
,在实体类的复杂对象前,使用@Valid
。
例如,实体类User中有一个Address变量:
1 |
|
1 |
|
在控制器方法中可以这样写:
1 |
|
就会递归校验User和Address的成员变量约束注解。
异常处理
校验参数后,会将校验结果发到一个BindingResult
类中,如果出现错误,会抛出异常,所以需要手动处理异常。
可以这样处理,在控制器方法中处理:
1 |
|
如果使用这种处理方法,需要在每个控制器方法中都这样写,冗余很高,因此一般不使用这种方法。
全局异常处理
往往是创建一个全局异常类来集中处理所有异常。
使用@ControllerAdvice
和@RestControllerAdvicce
来注解全局异常处理类。
使用@ExceptionHandler(class)
放在方法上,来指定要处理的异常类。
1 |
|
在使用@Validated
和@Valid
注解校验参数出错后,会抛出MethodArgumentNotValidException
异常,它是BindException
的子类。
可以直接处理MethodArgumentNotValidException
,也可以处理BindException
。一般是将错误信息以统一的json的格式返回给前端。
## 分组校验
很多时候,在校验参数时,有不同的情况。例如在新增用户时,用户名不能为空,但是在修改用户信息时,用户名可以为空。
因此,分组校验就是针对相同的参数或对象,在不同情况下使用不同的校验规则。
首先定义两个分组接口Create和Update,继承Default接口。
继承Default不是必须的,如果继承了Default,那么@Validated(value=Create.class)的校验范畴就是Create和Default;如果没有继承Default,那么@Validated(value=Create.class)的校验范畴只有Create,只有手动指定Default:@Validated(value={Create.class,Default.class}),校验范畴才是Create和Default
1 |
|
1 |
|
在实体类中,给参数加校验注解时,指定所属分组。
1 |
|
当没有指定分组时,默认是Default分组,因此成员变量address的groups可以不写。
然后在控制器方法中启动校验时,使用@Validated
的value
属性指定校验分组。
1 |
|
在上述这种情况下,隶属于Create和Default组的校验设置,都会触发校验。
其他情况同理。
自定义约束
开发自定义约束需要两步:
- 编写自定义约束的注解
- 编写自定义约束的校验器ConstraintValidator
以开发一个枚举校验为例。
首先创建自定义约束注解:
1 |
|
其中@Constraint(validatedBy = EnumConstraintValidator.class)
指定了使用EnumConstraintValidator类校验该注解。
value是自定义的成员变量,其他三个是所有约束注解都要有的成员变量。
message是检验出错的默认输出信息。
groups是分组信息,payload不用管。
然后创建EnumConstraintValidator类:
1 |
|
继承了ConstraintValidator<A,T>
接口,A表示自定义约束注解,T表示参数值的类型。有两个方法。
在初始化时,可传入注解中的value变量数组,然后在isValid
方法中,将实际输入与value数组中的值一一比较,如果匹配成功,返回true,否则返回false。