java valid 注解_springboot中@Valid注解与@Validated注解区别以及全局异常的处理

前端传过来数据的时候,要进行校验,但是大量的校验很繁琐,会造成大量的if else语句的产生,所以@Valid和@Validated很好的解决了这个问题.

首先说一下两个注解的区别:

1.两者的所属的包是不同的

@Valid属于javax.validation包下,是jdk给提供的

@Validated是org.springframework.validation.annotation包下的,是spring提供的

2.@Validated要比@Valid更加强大

@Validated在@Valid之上提供了分组功能和验证排序功能

一.处理校验的异常

首先定义一个实体类:

@Datapublic classPerson {

@NotEmpty(message= "姓名不能为空")privateString name;

@Max(value= 18,message = "年龄不能超过18岁")privateString age;

@Max(value= 1, message = "性别只能为0和1: 0=女1=男")

@Min(value= 0, message = "性别只能为0和1: 0=女1=男")privateShort sex;

}

然后controller,BindingResult对象,用于获取校验失败情况下的反馈信息:

@RestController

@Slf4jpublic classVerifyController {

@PostMapping(value= "/valid")public voidverifyValid(@Valid @RequestBody Person person, BindingResult result) {

log.info("I am verifyValid() method, the request params is: 【{}】", JSON.toJSONString(person));if(result.hasErrors()) {

FieldError fieldError=result.getFieldError();if (fieldError != null) {

log.error("error msg: 【{}】", fieldError.getDefaultMessage());

}

}

}

@PostMapping(value= "/validated")public voidverifyValidated(@Validated @RequestBody Person person, BindingResult result) {

log.info("I am verifyValidated() method, the request params is: 【{}】", JSON.toJSONString(person));if(result.hasErrors()) {

FieldError fieldError=result.getFieldError();if (fieldError != null) {

log.error("error msg: 【{}】", fieldError.getDefaultMessage());

}

}

}

}

此时访问两个controller结果都可以进行校验:

/validated:

2020-01-14 12:32:54.805 INFO 25244 --- [nio-8080-exec-1] com.example.controller.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] com.example.controller.VerifyController : error msg: 【性别只能为0和1: 0=女1=男】2020-01-14 12:33:10.638 INFO 25244 --- [nio-8080-exec-2] com.example.controller.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] com.example.controller.VerifyController : error msg: 【年龄不能超过18岁】2020-01-14 12:33:18.034 INFO 25244 --- [nio-8080-exec-3] com.example.controller.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] com.example.controller.VerifyController : error msg: 【姓名不能为空】

/valid:

2020-01-14 12:35:19.151 INFO 25244 --- [nio-8080-exec-5] com.example.controller.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] com.example.controller.VerifyController : error msg: 【姓名不能为空】2020-01-14 12:35:24.306 INFO 25244 --- [nio-8080-exec-6] com.example.controller.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] com.example.controller.VerifyController : error msg: 【年龄不能超过18岁】2020-01-14 12:35:29.565 INFO 25244 --- [nio-8080-exec-7] com.example.controller.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] com.example.controller.VerifyController : error msg: 【性别只能为0和1: 0=女1=男】

在有些时候我们不一定能够使用BindingResult result来处理校验的结果集,在实际的生产环境中,更方便的是获取该异常然后进行返回.

通过观察发现,两者在使用@RequestBody参数注解的情况下,两者抛出的都是MethodArgumentNotValidException异常:

org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public void com.example.controller.VerifyController.verifyValidated(com.example.model.Person) with 3 errors: [Field error in object 'person' on field 'age': rejected value [19]; codes [Max.person.age,Max.age,Max.java.lang.String,Max]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [person.age,age]; arguments []; default message [age],18]; default message [年龄不能超过18岁]] [Field error in object 'person' on field 'name': rejected value []; codes [NotEmpty.person.name,NotEmpty.name,NotEmpty.java.lang.String,NotEmpty]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [person.name,name]; arguments []; default message [name]]; default message [姓名不能为空]] [Field error in object 'person' on field 'sex': rejected value [10]; codes [Max.person.sex,Max.sex,Max.java.lang.Short,Max]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [person.sex,sex]; arguments []; default message [sex],1]; default message [性别只能为0和1: 0=女1=男]]

at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:139)

at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)

at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:167)

at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134)

at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)

at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888)

at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)

at org.springframework.web.servlet.mvc.method.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

@ResponseBodypublic classGlobleExceptionHandler {/*** 要拦截的异常Exception*/@ExceptionHandler(value= Exception.class)public ResultexceptionHandler(Exception e) {if (e instanceofBindException) {

e.printStackTrace();  //将异常打印出来

BindException ex=(BindException) e;

List allErrors =ex.getAllErrors();

ObjectError objectError= allErrors.get(0);

String ms=objectError.getDefaultMessage();returnResult.error(CodeMsg.BIND_ERROR.fillArgs(ms));

}else{

e.printStackTrace();returnResult.error(CodeMsg.SERVER_ERROR);

}

}

}

返回值的Result是统一封装了返回给前端的json数据,具体的实现可以在我上一篇博客中查看:

但是如果不在controller接口中加@RequestBody注解,两者抛出的则是BindException:

org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 3 errors

这里提醒一下各位小伙伴,在controller接口中加不加@ResquestBody注解,抛出的校验异常是不一样的.各位在抓取异常的时候需要注意一下.

二.@Valid和@Validated两者的区别

两者的主要区别就是关于分组和分组排序了.@Validated中可以进行分组排序

首先定义两个接口:

public interfaceFirst {

}public interfaceSecond {

}

这俩接口是用来分组的.

实体类如下:

@Datapublic classPerson {

@NotEmpty(groups= First.class, message = "姓名不能为空")privateString name;

@Max(value= 18,groups = Second.class,message = "年龄不能超过18岁")privateString age;

@Max(value= 1, message = "性别只能为0和1: 0=女1=男")

@Min(value= 0, message = "性别只能为0和1: 0=女1=男")privateShort sex;

}

然后controller(与上面一样,两个都没有添加分组),多次校验下我们会发现不管是 @Valid 注解还是 @Validated 注解都只会校验没有添加 groups 属性的实体类字段 (此处只校验了 sex 字段)

也就是说,在实体类中,添加分组的两个字段,name,和age在校验中失效了.

因为@Valid注解中没有关于分组的参数,所以在@Validated中加入注解,变成下面这样:

@RestController

@Slf4jpublic classVerifyController {

@PostMapping(value= "/valid")public voidverifyValid(@Valid @RequestBody Person person, BindingResult result) {

log.info("I am verifyValid() method, the request params is: 【{}】", JSON.toJSONString(person));if(result.hasErrors()) {

FieldError fieldError=result.getFieldError();if (fieldError != null) {

log.error("error msg: 【{}】", fieldError.getDefaultMessage());

}

}

}

@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: 【{}】", JSON.toJSONString(person));if(result.hasErrors()) {

FieldError fieldError=result.getFieldError();if (fieldError != null) {

log.error("error msg: 【{}】", fieldError.getDefaultMessage());

}

}

}

}

此时,@Validated则可以校验对应有First分组的name字段了,但是别的字段,也就是说除了加了First分组的name字段,别的字段都不能进行校验.

那么怎么办呢,因为value是Clazz[]数组格式的,所以可以这样:

value={First.class,Second.class}

也可以进行分组排序:

定义一个分组排序接口:

@GroupSequence({First.class,Second.class})public interfaceGroup {

}

然后controller中    value=Group.class,就可以对所有已经分组的字段进行校验了,但是没有进行分组的字段是不会被校验的.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值