springboot中@Valid注解与@Validated注解区别以及全局异常的处理
前端传过来数据的时候,要进⾏校验,但是⼤量的校验很繁琐,会造成⼤量的if else语句的产⽣,所以@Valid和@Validated很好的解决了这个问题.
⾸先说⼀下两个注解的区别:
1.两者的所属的包是不同的
@Valid属于javax.validation包下,是jdk给提供的
@Validated是org.springframework.validation.annotation包下的,是spring提供的
2.@Validated要⽐@Valid更加强⼤
@Validated在@Valid之上提供了分组功能和验证排序功能
⼀.处理校验的异常
⾸先定义⼀个实体类:
@Data
public class Person {
@NotEmpty(message = "姓名不能为空")
private String name;
@Max(value = 18,message = "年龄不能超过18岁")
private String age;
@Max(value = 1, message = "性别只能为0和1: 0=⼥1=男")
@Min(value = 0, message = "性别只能为0和1: 0=⼥1=男")
private Short sex;
}
然后controller,BindingResult对象,⽤于获取校验失败情况下的反馈信息:
@RestController
@Slf4j
public class VerifyController {
spring mvc和boot区别@PostMapping(value = "/valid")
public void verifyValid(@Valid @RequestBody Person person, BindingResult result) {
log.info("I am verifyValid() method, the request params is: 【{}】", JSONString(person));
if (result.hasErrors()) {
FieldError fieldError = FieldError();
if (fieldError != null) {
<("error msg: 【{}】", DefaultMessage());
}
}
}
@PostMapping(value = "/validated")
public void verifyValidated(@Validated @RequestBody Person person, BindingResult result) {
log.info("I am verifyValidated() method, the request params is: 【{}】", JSONString(person));
if (result.hasErrors()) {
FieldError fieldError = FieldError();
if (fieldError != null) {
<("error msg: 【{}】", DefaultMessage());
}
}
}
}
此时访问两个controller结果都可以进⾏校验:
/validated:
2020-01-14 12:32:54.805 INFO 25244 --- [nio-8080-exec-1] ller.VerifyController : I am verifyValidated() method, the request params is: 【{"age":"19","name":"","sex":10}】
2020-01-14 12:32:54.806 ERROR 25244 --- [nio-8080-exec-1] ller.VerifyController : error msg: 【性别只能为0和1: 0=⼥1=男】
2020-01-14 12:33:10.638 INFO 25244 --- [nio-8080-exec-2] ller.VerifyController : I am verifyValidated() method, the request params is: 【{"age":"19","name":"","sex":1}】
2020-01-14 12:33:10.639 ERROR 25244 --- [nio-8080-exec-2] ller.VerifyController : error msg: 【年龄不能超过18岁】
2020-01-14 12:33:18.034 INFO 25244 --- [nio-8080-exec-3] ller.VerifyController : I am verifyValidated() method, the request params is: 【{"age":"18","name":"","sex":1}】
2020-01-14 12:33:18.034 ERROR 25244 --- [nio-8080-exec-3] ller.VerifyController : error msg: 【姓名不能为空】
/valid:
2020-01-14 12:35:19.151 INFO 25244 --- [nio-8080-exec-5] ller.VerifyController : I am verifyValid() method, the request params is: 【{"age":"19","name":"","sex":10}】
2020-01-14 12:35:19.151 ERROR 25244 --- [nio-8080-exec-5] ller.VerifyController : error msg: 【姓名不能为空】
2020-01-14 12:35:24.306 INFO 25244 --- [nio-8080-exec-6] ller.VerifyController : I am verifyValid() method, the request params is: 【{"age":"19","name":"aa","sex":10}】
2020-01-14 12:35:24.306 ERROR 25244 --- [nio-8080-exec-6] ller.VerifyController : error msg: 【年龄不能超过18岁】
2020-01-14 12:35:29.565 INFO 25244 --- [nio-8080-exec-7] ller.VerifyController : I am verifyValid() method, the request params is: 【{"age":"18","name":"aa","sex":10}】
2020-01-14 12:35:29.565 ERROR 25244 --- [nio-8080-exec-7] ller.VerifyController : error msg: 【性别只能为0和1: 0=⼥1=男】
在有些时候我们不⼀定能够使⽤BindingResult result来处理校验的结果集,在实际的⽣产环境中,更⽅便的是获取该异常然后进⾏返回.
通过观察发现,两者在使⽤@RequestBody参数注解的情况下,两者抛出的都是MethodArgumentNotValidException异常:
org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public ller.VerifyController.del.Person) with 3 errors: [Fiel at org.springframework.web.hod.solveArgument(RequestResponseBodyMethodProcessor.java:139)
at org.hod.solveArgument(HandlerMethodArgumentResolverComposite.java:121)
at org.hod.MethodArgumentValues(InvocableHandlerMethod.java:167)
at org.hod.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134)
at org.springframework.web.hod.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
at org.springframework.web.hod.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888)
at org.springframework.web.hod.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
at org.springframework.web.hod.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
为了统⼀抓取异常,⾸先定义⼀个全局异常类:
@ControllerAdvice
@ResponseBody
public class GlobleExceptionHandler {
/**
* 要拦截的异常Exception
*/
@ExceptionHandler(value = Exception.class)
public Result<String> exceptionHandler(Exception e) {
if (e instanceof BindException) {
e.printStackTrace(); //将异常打印出来
BindException ex = (BindException) e;
List<ObjectError> allErrors = ex.getAllErrors();
ObjectError objectError = (0);
String ms = DefaultMessage();
(CodeMsg.BIND_ERROR.fillArgs(ms));
} else {
e.printStackTrace();
(CodeMsg.SERVER_ERROR);
}
}
}
返回值的Result是统⼀封装了返回给前端的json数据,具体的实现可以在我上⼀篇博客中查看:
但是如果不在controller接⼝中加@RequestBody注解,两者抛出的则是BindException:
org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 3 errors
这⾥提醒⼀下各位⼩伙伴,在controller接⼝中加不加@ResquestBody注解,抛出的校验异常是不⼀样的.各位在抓取异常的时候需要注意⼀下.
⼆.@Valid和@Validated两者的区别
两者的主要区别就是关于分组和分组排序了.@Validated中可以进⾏分组排序
⾸先定义两个接⼝:
public interface First {
}
public interface Second {
}
这俩接⼝是⽤来分组的.
实体类如下:
@Data
public class Person {
@NotEmpty(groups = First.class, message = "姓名不能为空")
private String name;
@Max(value = 18, groups = Second.class,message = "年龄不能超过18岁")
private String age;
@Max(value = 1, message = "性别只能为0和1: 0=⼥1=男")
@Min(value = 0, message = "性别只能为0和1: 0=⼥1=男")
private Short sex;
}
然后controller(与上⾯⼀样,两个都没有添加分组),多次校验下我们会发现不管是 @Valid 注解还是 @Validated 注解都只会校验没有添加 groups 属性的实体类字段 (此处只校验了 sex 字段)
也就是说,在实体类中,添加分组的两个字段,name,和age在校验中失效了.
因为@Valid注解中没有关于分组的参数,所以在@Validated中加⼊注解,变成下⾯这样:
@RestController
@Slf4j
public class VerifyController {
@PostMapping(value = "/valid")
public void verifyValid(@Valid @RequestBody Person person, BindingResult result) {
log.info("I am verifyValid() method, the request params is: 【{}】", JSONString(person));
if (result.hasErrors()) {
FieldError fieldError = FieldError();
if (fieldError != null) {
<("error msg: 【{}】", DefaultMessage());
}
}
}
@PostMapping(value = "/validated")
public void verifyValidated(@Validated(value = First.class) @RequestBody Person person, BindingResult result) {
log.info("I am verifyValidated() method, the request params is: 【{}】", JSONString(person));
if (result.hasErrors()) {
FieldError fieldError = FieldError();
if (fieldError != null) {
<("error msg: 【{}】", DefaultMessage());
}
}
}
}
此时,@Validated则可以校验对应有First分组的name字段了,但是别的字段,也就是说除了加了First分组的name字段,别的字段都不能进⾏校验.
那么怎么办呢,因为value是Clazz[]数组格式的,所以可以这样:
value={First.class,Second.class}
也可以进⾏分组排序:
定义⼀个分组排序接⼝:
@GroupSequence({First.class,Second.class})
public interface Group {
}
然后controller中 value=Group.class,就可以对所有已经分组的字段进⾏校验了,但是没有进⾏分组的字段是不会被校验的.
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论