- JSR303的使用
- 分组校验
- 自定义校验规则
一般在项目开发中,对数据准确性的校验必不可少,除了前端对数据进行校验,后端也要对数据进行校验。 JSR303的使用
JSR303采用注解的形式进行数值校验,使用起来很方便,实体类需校验的字段上添加注解即可,一个字段可有多个注解;其中,message就是当数据校验错误时的默认报错信息。
@NotEmpty(message = "姓名不合法")
private String name;
在请求参数中@RequestBody注解前添加@Valid,并紧跟在校验参数的后面声明参数BindingResult result,通过 BindingResult 的实例方法来获取校验失败的字段信息等。
@RequestMapping("/param")
public String param(@Valid @RequestBody User user, BindingResult result) {
Map map = new HashMap<>();
if (result.hasErrors()) {
result.getFieldErrors().forEach((item) -> {
String defaultMessage = item.getDefaultMessage();
// 获取错误属性的字段
String field = item.getField();
map.put(field, defaultMessage);
});
}
String s = JSON.toJSONString(map);
return s;
}
}
但我们一般不会在接口中直接进行处理这种参数校验错误,而是选择在 @ControllerAdvice 注解修饰的异常处理类中进行处理。
@Slf4j
//@ResponseBody
//@ControllerAdvice(basePackages = "com.zouzou.controller")
@RestControllerAdvice(basePackages = "com.zouzou.controller")
public class ExceptinonControllerAdvice {
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public String handlevalidException(MethodArgumentNotValidException e) {
Map map = new HashMap<>();
log.error("数据校验出现问题{},异常类型:{}",e.getMessage(), e.getClass());
BindingResult bindingResult = e.getBindingResult();
bindingResult.getFieldErrors().forEach((item) -> {
String field = item.getField();
String defaultMessage = item.getDefaultMessage();
map.put(field, defaultMessage);
});
return JSON.toJSONString(map);
}
@ExceptionHandler(value = Throwable.class)
public String handleThrowable(Throwable e) {
log.error("错误:", e.getMessage());
return JSON.toJSONString(e);
}
}
分组校验
JSR303可以进行分组校验,通过接口中请求参数注解中的类型来判断属于哪一分组,从而执行哪一校验规则。校验注解从@Valid转变为了@Validated,后者可以表明分组类型。
在使用分组校验时,需要创建多个分组的接口,它们起到标记的作用。
注意:想要使用分组校验必须在校验注解上增加 group 属性来表明都在那些分组下,该校验规则生效;并且当有一个校验注解使用了 group 属性时,其余未使用group属性的注解不生效。
public interface AddGroup {
}
public interface DeleteGrooup {
}
public interface UpdateGroup {
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@NotEmpty(message = "姓名不合法", groups = {UpdateGroup.class, DeleteGroup.class})
@Null(message = "新增不能指定", groups = {AddGroup.class})
private Long id;
@NotEmpty(message = "姓名不合法") // 在分组校验中,该注解由于没有使用 group 属性,所以不会生效。
private String name;
private Integer age;
private Date birthday;
private Integer status;
}
@RequestMapping("/param")
public String param(@Validated({AddGroup.class}) @RequestBody User user) {
return "666";
}
自定义校验规则
JSR303校验还可以进行自定义规则进行校验。
- 创建自定义校验的注解。
@documented
@Constraint(validatedBy = { ListValueConstraintValidator.class })
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
String message() default "{com.zouzou.demo.valid.ListValue.message}";
Class>[] groups() default { };
Class extends Payload>[] payload() default { };
int[]values() default { };
}
- 创建ConstraintValidator的实现类,其中泛型是注解类型和校验值类型。
public class ListValueConstraintValidator implements ConstraintValidator{ private Set set = new HashSet<>(); @Override public void initialize(ListValue constraintAnnotation) { int[] values = constraintAnnotation.values(); Arrays.stream(values) .forEach((e) -> set.add(e)); } @Override public boolean isValid(Integer value, ConstraintValidatorContext context) { return set.contains(value); } }
- 将自定义注解与ConstraintValidator实现类进行关联,表示使用该方法进行校验。
- 若需要给出默认信息,在ValidationMessages.properties文件中写下默认信息。
com.zouzou.demo.valid.ListValue.message=必须提交指定的值
通过以上四步就可以使用自定义的校验注解了。



