之前两篇文章 Spring-boot 自定义参数校验注解和如何在 spring-boot 中进行参数校验, 我们介绍了, 参数校验以及如何自定义参数校验注解, 但是当传递参数出错时, 只是把错误信息打印到了控制台, 合理的做法是应该把校验的错误信息返回给前端, 告知用户那里有问题, 下面就这一步内容进行说明.
请求 body 参数
上篇文章 Spring-boot 自定义参数校验注解的最后, 在控制台打印了校验出错的信息
出错的异常类是 MethodArgumentNotValidException, 那如果想要自定义异常的返回, 就需要在全局的异常处理器中针对这种异常进行处理.
在这篇文章 spring-boot 自定义异常返回中, 我们说了如何进行自定义异常的返回, 参数校验的错误信息返回依然按照此方式进行处理, 在全局异常处理类中定义异常处理方法:
- @ExceptionHandler(value = MethodArgumentNotValidException.class)
- @ResponseStatus(HttpStatus.BAD_REQUEST)
- @ResponseBody
- public UnifyResponse handlerBeanValidationException(HttpServletRequest request,
- MethodArgumentNotValidException ex) {
- String requestUri = request.getRequestURI();
- String method = request.getMethod();
- List<ObjectError> errors = ex.getBindingResult().getAllErrors();
- return UnifyResponse.builder()
- .code(5000)
- .message(formatError(errors))
- .requestUri(method + " " + requestUri)
- .build();
- }
- private String formatError(List<ObjectError> errors) {
- StringBuilder builder = new StringBuilder();
- errors.forEach(error -> builder.append(error.getDefaultMessage()).append(";"));
- return builder.toString();
- }
我们来对上面的代码进行一下解释:
因为这个处理方法只是针对 MethodArgumentNotValidException 这个异常进行处理, 所以
@ExceptionHandler(value = MethodArgumentNotValidException.class)
这里指定
@ResponseStatus(HttpStatus.BAD_REQUEST), 所有的参数校验错误都是一类的, 状态码设置为 HttpStatus.BAD_REQUEST, 也就是 code 等于 400, 当然也可以定义为其他的, 按照自己业务需求定义就好, 可以参考这篇文章 spring-boot 自定义异常返回里关于自定义状态码的部分.
@ResponseBody, 因为这个异常处理方法要返回自定义的对象, 所以要使用这个注解, 不然 spring-boot 是不会对自定义对象进行序列化的
List<ObjectError> errors = ex.getBindingResult().getAllErrors()
进行参数校验的时候, 可能多个参数都有问题, 我们希望能够有问题的参数的错误信息全部都返回回去, 所以这里要获取所有的错误.
回顾一下参数的定义, 对这里有疑惑的同学可以看一下这篇文章 Spring-boot 自定义参数校验注解
- @Builder
- @Getter
- @Setter
- @PasswordEqual(min = 5, message = "密码和确认密码不一样")
- public class UserDto {
- private int userId;
- @Length(min = 2, max = 10, message = "用户名长度必须在 2-10 的范围内")
- private String username;
- private String password;
- private String confirmPassword;
- }
接下来我们定再定义一个简单的接口, 当传参出错时看异常处理方法能否按照定义的那样返回错误信息
- @RequestMapping("/v2/user/create")
- public UserDto createUser(@RequestBody @Validated UserDto userDto){
- return userDto;
- }
我们先来构造一个密码和确认密码不一致的情况
可以看到定义的错误信息被返回, 而且状态码和自定义的 code 都是符合设计的, 接下来我们再看一下多个参数错误的场景:
上面的场景中, 用户名是不符合要求的, 密码和确认密码也不一样, 所以会产生两条错误信息, 将其拼接到一起, 返回给前端.
之前讨论的都是 body 里提交的参数, 接下来我们看下路径参数或者查询参数校验出错时的处理
查询参数和路径参数
我们先定义两个接口一个是路径参数查询信息, 一个是通过查询参数查询信息
- @GetMapping("/v2/user/info")
- public UserDto getUserInfo(@RequestParam @Length(min = 2, max = 5, message = "用户名长度必须在 2-5 的范围")
- String username){
- return UserDto.builder()
- .userId(1000)
- .username(username)
- .build();
- }
- @GetMapping("/v2/user/{username}")
- public UserDto getUserInfoV2(@PathVariable @Length(min = 2, max = 5, message = "用户名长度必须在 2-5 的范围") String username){
- return UserDto.builder()
- .userId(2000)
- .username(username)
- .build();
- }
然后我们访问这两接口, 当发生错误时, 看看他们会不会进入上文定义的异常处理方法中:
很明显, 并没有进入上文定义的异常处理方法中, 而是进入了 handleException 这个异常方法当中, 这个算是个兜底的异常处理方法.
看一下控制台的输出:
这里抛出了 ConstraintViolationException 异常, 这个异常我们并没有定制对应的异常处理函数, 下面我们就来写一下:
- @ExceptionHandler(ConstraintViolationException.class)
- @ResponseStatus(HttpStatus.BAD_REQUEST)
- @ResponseBody
- public UnifyResponse handlerConstraintViolationException(HttpServletRequest request, ConstraintViolationException ex){
- String requestUri = request.getRequestURI();
- String method = request.getMethod();
- Set<ConstraintViolation<?>> errors = ex.getConstraintViolations();
- return UnifyResponse.builder()
- .code(6000)
- .message(formatConstraintException(errors))
- .requestUri(method + " " + requestUri)
- .build();
- }
- private String formatConstraintException(Set<ConstraintViolation<?>> constraintViolations){
- StringBuilder builder = new StringBuilder();
- constraintViolations.forEach(constraintViolation -> builder.append(constraintViolation.getMessage()));
- return builder.toString();
- }
整体来说异常处理和上文几乎是一样的, 只是获取错误 message 的方式不一样而已, 我们再请求一下:
至此参数校验的错误 message 自定义返回, 都完成了.
本文链接:
欢迎大家去 我的博客 https://www.immortalp.com/ 瞅瞅, 里面有更多关于测试实战的内容哦!!
来源: https://www.cnblogs.com/zyjimmortalp/p/12901581.html