springboot @valid与@validated的参数校验使用总结
好久没在这平台写博客了,最近整理了这东西,先给出总结
// @Valid只能用在controller,@Validated可以用在其他被spring管理的类上 // @Valid可以加在成员变量上(本人一般只有在嵌套查询的时候才会使用这个注解) // @Validated可以分组 // @Valid可以加在成员变量上,所以可以嵌套校验
以及我在总结时随便写的类(东西都在代码里,(*^▽^*))
@RestController @RequestMapping("/check") @Validated public class ParamCheckInController { @Autowired private ParamCheckInService paramCheckInService; @PostMapping("/postDemo") public Node postDemo(@RequestBody @Validated Node node) { return node; } @GetMapping("/getDemo") public Node getDemo(@Validated Node node) { paramCheckInService.test("a","b"); return node; } @GetMapping("/getDemo2") public String getDemo2( @NotEmpty String s) { return s; } @PostMapping("/groupDemo1") public Book groupDemo1(@RequestBody @Validated Book book) { return book; } @PostMapping("/groupDemo2") public Book groupDemo2(@RequestBody @Validated({InsertGroup.class,}) Book book) { return book; } @PostMapping("/groupDemo3") public Node groupDemo3(@RequestBody @Validated({InsertGroup.class,UpdateGroup.class}) Node node) {//还有啥@Validated分组是有序校验的之类,感觉没啥用 return node; } } @Data class Node implements Serializable { @NotBlank(message = "名称不能为空") private String name; @NotEmpty(groups = UpdateGroup.class,message = "性别不能为空") private String sex; @NotNull(groups =InsertGroup.class,message = "年龄不能为空") @Max(value = 200,message = "age不能大于200") private Integer age; @Valid //对下层进行嵌套调用 @NotEmpty(message = "bookList不能为空") private List<Book> bookList; } @Data class Book implements Serializable{ @NotEmpty(groups = {UpdateGroup.class, Default.class}, message = "更新时id不能为空") private String id; @NotNull(groups = {InsertGroup.class}, message = "新增时bookName不能为空") private String bookName; }
@Service @Slf4j @Validated public class ParamCheckInService { public @NotNull(message = "返回值不允许为空") String test(@NotEmpty(message = "s不能为空") String s,String b){ return b; } }
上面的类是本人在总结知识点时自己测试的,而且因为要返回给前端,所以还要全局异常捕获,或者在每个方法用BindResult接收。
@ControllerAdvice public class GlobalExceptionHandler {
@ExceptionHandler({MethodArgumentNotValidException.class,BindException.class}) @ResponseStatus(HttpStatus.OK) @ResponseBody public Result<T> handleMethodArgumentNotValidException(Exception exception) { StringBuilder errorInfo = new StringBuilder(); BindingResult bindingResult=null; if(exception instanceof MethodArgumentNotValidException){ bindingResult= ((MethodArgumentNotValidException)exception).getBindingResult(); } if(exception instanceof BindException){ bindingResult= ((BindException)exception).getBindingResult(); } for(int i = 0; i < bindingResult.getFieldErrors().size(); i++){ if(i > 0){ errorInfo.append(","); } FieldError fieldError = bindingResult.getFieldErrors().get(i); errorInfo.append(fieldError.getField()).append(" :").append(fieldError.getDefaultMessage()); } return Result.error(errorInfo.toString()); } @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseBody public Result<T> handleDefaultException(Exception exception) { return Result.error("其他错误"); } }
还有需要注意的一点是在分组时,接口如果不继承Default的话,有分组校验的接口是必须加上Default.class的否则会使一些校验注解无效
所以我会在分组的接口上继承Default,不然需要分组的参数都要加Default.class看着不舒服~(controller看着简洁就行,嘿嘿~)
public interface UpdateGroup extends Default { } public interface InsertGroup extends Default { }