文章目录
前言
最近在写项目时要校验传过来的参数是否为空,手动判空很繁琐,所以使用注解判空,但默认的Exception异常拦截报错不准确,想要定义符合类型的报错返回值,所以查阅资料写了这篇博客
做检验的逻辑是在源码节的第10步
参考链接:
springboot2.3之后,hibernate-validator依赖缺失【踩坑】
Java注解校验参数 javax.validation 和 hibernate-validator(注解说明,全局异常处理)
Jakarta Bean Validation,Constrain once, validate everywhere!(javax和jakarta区别)
spring boot中使用Bean Validation做优雅的参数校验(注解说明,全局异常处理通用模板)
参数校验Jakarta Bean Validation学习
Spring Validation最佳实践及其实现原理,参数校验没那么简单!(全局异常处理通用模板)
还在为参数校验发愁?spring-validation最佳实践指南(重要,全局异常处理通用模板)
10.2添加
数据校验JSR303快速入门(简单使用、分组效验、自定义注解效验)
springboot 参数异常拦截(3种)
SpringBoot学习笔记35——实现List校验@Validated
SpringBoot 之配置全局异常处理器捕获异常
使用SpringBoot进行优雅的数据验证
一、hibernate-validator
不同版本的hibernate-validator的依赖也不尽相同7.0.0之后:
7.0.0之前(不过其实6版本的最后一些版本已经是jakarta.validation-api依赖了):
二、全局异常拦截校验参数注解
1.@RequestBody
POST、PUT请求一般会使用requestBody传递参数,这种情况下,后端使用DTO对象进行接收。只要给DTO对象加上@Validated注解就能实现自动参数校验。比如,有一个保存User的接口,要求userName长度是2-10,account和password字段长度是6-20。如果校验失败,会抛出MethodArgumentNotValidException异常,Spring默认会将其转为400(Bad Request)请求。
2.@RequestParam/@PathVariable
GET请求一般会使用requestParam/PathVariable传参。如果参数比较多(比如超过6个),还是推荐使用DTO对象接收。否则,推荐将一个个参数平铺到方法入参中。在这种情况下,必须在Controller类上标注@Validated注解,并在入参上声明约束注解(如@Min等)。如果校验失败,会抛出ConstraintViolationException异常。代码示例如下:
三、实践代码
@RestController
@Validated
@Slf4j
//@Valid
public class TestController {
@RequestMapping("/test")
public TestRepository.User test(@RequestParam Integer a) throws Exception {
return service.test(a);
}
/**
* 对照组1 requestParam参数
* 当前controller没有@Validated全都不生效
* 加@Valid注解无用
* 测试@NotNull不传任何参数即可,postman中的params不加这个参数,加上就是空串而不是null,这时候要使用@NotBlank
* @param userId
* @return
*/
//异常类型:ConstraintViolationException
//没有@Validated注解均不生效(必须是@Validated注解,@Valid注解无用)
//不生效
@GetMapping(value = "/user0")
String getUserInfo0(String userId) {
return userId;
}
//生效
@GetMapping(value = "/user1")
String getUserInfo1( @Valid @NotNull String userId) {
return userId;
}
//生效
@GetMapping(value = "/user2")
String getUserInfo2( @Validated @NotNull String userId) {
return userId;
}
//生效
@GetMapping(value = "/user3")
String getUserInfo3( @NotNull String userId) {
return userId;
}
/**
* 对照组2 requestBody参数
* 和当前controller是否有@Validated注解无关,去掉也不影响
* @param user
* @return
*/
//异常类型: MethodArgumentNotValidException
//不生效
@PostMapping(value = "/user00")
String saveUser0( @RequestBody User user) {
return user.getName();
}
//生效
@PostMapping(value = "/user11")
String saveUser1( @RequestBody @Validated User user) {
return user.getName();
}
//生效
@PostMapping(value = "/user22")
String saveUser2( @RequestBody @Valid User user) {
return user.getName();
}
@Data
public class User {
@NotBlank(message = "用户名不能为空")
private String name;
}
postman调用截图:
param:
body:
四、异常情况
- 使用@Min,@Max等注解时一般和@NotBlank搭配,否则null(即不传参)可以通过@Min@Max等的校验
注意:”null elements are considered valid“
五、源码
1.DispatchServlet的doDispatch方法:
2.AbstractHandlerMethodAdapter的handle方法
3.RequestMappingHandlerAdapter的handleInternal方法
进入这个else
4.RequestMappingHandlerAdapter的invokeHandlerMethod方法
invokeAndHandle
5.ServletInvocableHandlerMethod的invokeAndHandle方法
6.InvocableHandlerMethod的invokeForRequest方法
7.InvocableHandlerMethod的getMethodArgumentValues方法
8.HandlerMethodArgumentResolverComposite的resolveArgument方法
9 .分两类(param和body)
9.1 body
9.2 param
10.AbstractMessageConverterMethodArgumentResolver 的validateIfApplicable方法
-
回到InvocableHandlerMethod的doInvoke方法
-
doInvoke方法
-
使用反射机制