SpringBoot数据校验+全局异常处理--@RequestBody与@Valid一起使用校验失效
场景:SpringBoot 通过 spring-boot-starter-validation 模块包含了数据校验的⼯作,只需要简单几个注解就可以对请求数据进行校验,很方便。这过程还包含了全局异常的处理,以下是步骤:1、User 实体类属性添加校验注解public class User{private Integer id;//校验注解@NotBlank(message = "⽤户名不能为空!")
场景:
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位!]] ]
完结撒花~~~
更多推荐
所有评论(0)