Spring validation 分组校验用法
前言
在使用 Java Bean Validation
进行参数校验的时候,很多场景下的一个Req实体都是同时满足多个业务,但是可能在不同的业务场景下,参数校验有细微的差别。例如在新增用户和编辑用户的场景下,UserReq实体相同,但是编辑的时候用户ID是必填的。如果想要新增用户和编辑用户共用一个UserReq实体,就只能在id属性上去掉@NotNull注解,在编辑方法上手动判断,这样实际上比较麻烦,也不够优雅。
public class UserReq {
private Long id;
@NotEmpty(message="name 不能为空")
private String name;
@NotNull(message="age 不能为空")
private int age;
...
}
public class UserController{
public R create(@RequestBody @Valid UserReq userReq){
...
}
public R edit(@RequestBody @Valid UserReq userReq){
// 手动判断id
if(userReq.getId() == null){
throw new ServiceException(...)
}
...
}
}
如果能给id字段上打一个记号,标识出id字段只需要编辑时校验,新增的时候忽视掉就好了。
实现
实际上,@NotEmpty、@NotNull … 注解上有一个属性,叫做groups,用于指定一个验证分组。它允许你对同一个对象应用不同的验证规则,具体规则可以根据上下文的不同而有所不同。
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(NotNull.List.class)
@Documented
@Constraint(
validatedBy = {}
)
public @interface NotNull {
String message() default "{javax.validation.constraints.NotNull.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface List {
NotNull[] value();
}
}
于是我们可以定义不同的验证分组接口,用于标识不同的验证场景。例如:
public interface ValidGroup {
interface InsertGroup {
}
interface UpdateGroup {
}
interface DeleteGroup {
}
}
然后在Req实体的属性上标注出场景
public class UserReq {
@NotNull(message="id不能为空", groups = {UpdateGroup.class})
private Long id;
@NotEmpty(message="name不能为空", groups = {InsertGroup.class, UpdateGroup.class})
private String name;
@NotNull(message="age不能为空", groups = {InsertGroup.class, UpdateGroup.class})
private int age;
...
}
然后在Controller接口方法上制定验证的分组规则
public class UserController{
public R create(@RequestBody @Validated(ValidGroup.InsertGroup.class) UserReq userReq){
...
}
public R edit(@RequestBody @Validated(ValidGroup.UpdateGroup.class) UserReq userReq){
...
}
}
这样就实现参数的优雅校验了。