场景:

SpringBoot 通过 spring-boot-starter-validation 模块包含了数据校验的⼯作,只需要简单几个注解就可以对请求数据进行校验,很方便。这过程还包含了全局异常的处理,以下是步骤:

1、User 实体类属性添加校验注解

public class User{
 
 private Integer id;
 //校验注解
 @NotBlank(message = "⽤户名不能为空!")
 private String userName;
 @NotBlank(message = "⽤户密码不能为空!")
 @Length(min = 6, max = 10,message = "密码⻓度⾄少6位但不超过10位!")
 private String userPwd;
 
 /*
 省略get set ⽅法 
 */
}

2、在控制层的接口方法形参上添加@RequestBody+@Valid 注解

@RestController
public class UserController {
    @Autowired
    private UserService userService;
/**
     * 添加用户
     * @param user
     * @return
     */
@PostMapping("user")
    public ResultInfo addUser(@RequestBody @Valid User user)
    {

        //结果集
        ResultInfo resultInfo = new ResultInfo();
        //有了全局异常处理GlobalExceptionHandler类,可以不用加try catch
        userService.addUser(user);

        //没有异常则返回默认的结果值:200,添加成功
        return resultInfo;
    }
   }

3、在全局异常处理类中添加校验异常方法BindExceptionHandler

/**
 * 全局异常处理
 * 返回JSON格式
 */

//Controller增强器,可对controller中被 @RequestMapping注解的方法加一些逻辑处理,当将异常抛到controller时,可以对异常进行统一处理,规定返回的json格式或是跳转到一个错误页面
@ControllerAdvice
public class GlobalExceptionHandler {
/**
     * 数据校验全局处理
     * BindException是@Valid使用校验失败时产生的异常
     */
    @ExceptionHandler(value = BindException.class)
    @ResponseBody
    public ResultInfo BindExceptionHandler(BindException e)
    {

        //捕获数据校验异常
        ResultInfo resultInfo = new ResultInfo();
        resultInfo.setCode(500);
        //获取实体类定义的校验注解字段上的message作为异常信息,@NotBlank(message = "用户密码不能为空!")异常信息即为"用户密码不能为空!"
        resultInfo.setResultmsg(e.getBindingResult().getFieldError().getDefaultMessage());
        return resultInfo;
    }
     /**
     * 全局异常处理
     *如果设置了特定异常处理,全局异常处理可作为兜底异常
     * @param e
     * @return
     */
    //设置处理的异常类型,如果没有特定异常则为最大的异常Exception.class
    @ExceptionHandler(value = Exception.class)
    //最终结果是JSON格式
    @ResponseBody
    public ResultInfo exceptionHandler(Exception e)
    {

        ResultInfo resultInfo = new ResultInfo();
        //一旦进入这个方法说明有异常,这是固定的异常信息
        resultInfo.setCode(100);
        resultInfo.setResultmsg("操作异常!");
        return resultInfo;
    }
}

问题描述

使用postman测试结果,userPwd密码故意设置成不符合规范的密码,但是测试捕获异常的不是校验异常而是全局异常
在这里插入图片描述
而在控制台中却把校验异常的错误打印出来了

2022-03-13 13:27:26.701  WARN 14232 --- [nio-8080-exec-1] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public com.xxxx.springboot_mybatis.po.vo.ResultInfo com.xxxx.springboot_mybatis.controller.UserController.addUser(com.xxxx.springboot_mybatis.po.User): 
[Field error in object 'user' on field 'userPwd': rejected value [222]; codes [Length.user.userPwd,Length.userPwd,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.userPwd,userPwd]; arguments []; default message [userPwd],10,6]; default message [密码⻓度⾄少6位但不超过10!]] ]

我又单独使用了注解@Valid而没有使用@RequestBody

@RestController
public class UserController {
    @Autowired
    private UserService userService;
/**
     * 添加用户
     * @param user
     * @return
     */
@PostMapping("user")
    public ResultInfo addUser(@Valid User user)
    {

        //结果集
        ResultInfo resultInfo = new ResultInfo();
        //有了全局异常处理GlobalExceptionHandler类,可以不用加try catch
        userService.addUser(user);

        //没有异常则返回默认的结果值:200,添加成功
        return resultInfo;
    }
   }

还是同样的测试数据,这次的测试结果如下:
数据校验异常捕获成功
在这里插入图片描述
测试结果和控制台打印异常一致

2022-03-13 13:40:31.560  WARN 11844 --- [nio-8080-exec-5] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors

Field error in object 'user' on field 'userPwd': rejected value [222]; codes [Length.user.userPwd,Length.userPwd,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.userPwd,userPwd]; arguments []; default message [userPwd],10,6]; default message [密码⻓度⾄少6位但不超过10!]]

原因分析:

对比一下两次的测试结果以及控制台打印异常,发现了一个不同的地方,控制台显示使用@RequestBody+@Valid注解产生的异常是MethodArgumentNotValidException,而单独使用注解@Valid产生的异常是BindException。


解决方案:

提示:在全局异常处理类中再添加一个新的方法,用于捕获控制台打印的异常MethodArgumentNotValidException

/**
     * 数据校验全局处理
     * MethodArgumentNotValidException是@RequestBody和@Validated配合时产生的异常,比如在传参时如果前端的json数据里部分缺失@RequestBody修饰的实体类的属性就会产生这个异常。
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public ResultInfo MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e)
    {

        //捕获数据校验异常
        ResultInfo resultInfo = new ResultInfo();
        resultInfo.setCode(600);
        //获取实体类定义的校验注解字段上的message作为异常信息,@NotBlank(message = "用户密码不能为空!")异常信息即为"用户密码不能为空!"
        resultInfo.setResultmsg(e.getBindingResult().getFieldError().getDefaultMessage());
        return resultInfo;
    }

在控制层的接口方法形参上添加@RequestBody+@Valid 注解再测试一遍,数据校验异常捕获成功
在这里插入图片描述
控制台同样打印出了MethodArgumentNotValidException异常

2022-03-13 13:53:42.574  WARN 11732 --- [nio-8080-exec-1] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public com.xxxx.springboot_mybatis.po.vo.ResultInfo com.xxxx.springboot_mybatis.controller.UserController.addUser(com.xxxx.springboot_mybatis.po.User): 
[Field error in object 'user' on field 'userPwd': rejected value [222]; codes [Length.user.userPwd,Length.userPwd,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.userPwd,userPwd]; arguments []; default message [userPwd],10,6]; default message [密码⻓度⾄少6位但不超过10!]] ]

完结撒花~~~

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐