你们好,我是金金金。
场景
先看如下一张图,这是一个控制器里面的一个方法,第一眼是不是就感觉代码量非常多?而且随着参数越来越多 你则需要写
n个if else来完成校验,属实是麻烦而且不够优雅
JSR303校验
仔细认真看,更容易理解吸收,想想什么层面需要做校验呢?
- 前端请求后端接口传输参数,是在
controller中校验还是在Service中校验?
都需要校验,只是分工不同。
-
Contoller中校验请求参数的合法性,包括:必填项校验,数据格式校验,比如:是否是符合一定的日期格式,等。 -
Service中要校验的是业务规则相关的内容,比如:课程已经审核通过所以提交失败。 -
Service中根据业务规则去校验不方便写成通用代码,Controller中则可以将校验的代码写成通用代码。
-
在
Service层,校验是和业务逻辑紧密相关的。因为不同的业务场景下,校验规则可能不同,很难将这些规则抽象成通用的代码。 比如,在处理订单的Service层中,校验的逻辑可能会涉及多个业务条件和数据库查询,这些条件可能只在特定的业务场景下适用,难以通用化。- 所以一般
service层都是手动if校验
- 所以一般
-
在
Controller层,校验通常是对请求参数的基本合法性进行验证 例如字段是否为空、长度是否在允许范围内、值是否在有效范围内等。由于这些校验规则通常是标准化的,不依赖于复杂的业务逻辑,因此很容易抽象成通用代码。 例如,可以使用注解、AOP等方式实现通用的参数校验逻辑,这样在不同的Controller中都可以复用这些校验逻辑。-
所以
controller层一般可以使用注解做校验早在
JavaEE6规范中就定义了参数校验的规范,它就是JSR-303,它定义了Bean Validation,即对bean属性进行校验。
-
SpringBoot提供了JSR-303的支持,它就是spring-boot-starter-validation,它的底层使用Hibernate Validator,Hibernate Validator是Bean Validation 的参考实现。
所以,在
Controller层使用spring-boot-starter-validation完成对请求参数的基本合法性进行校验。
使用
- 如何在
controller层面完成优雅的参数校验呢?接着往下看~
引入需要的坐标依赖
参数校验(
Spring Boot 2.3.1之后,spring-boot-starter-validation已经不包括在了spring-boot-starter-web中,需要手动加上)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
规则对应参考如下:
实体类
-
控制器层方法接收的参数是一个DTO实体类
-
定义校验规则:首先找到这个
DTO,在对应的属性上面添加对应的校验注解 -
开启校验:在
Controller方法接收参数前面加上注解@Validated -
自定义全局校验拦截
MethodArgumentNotValidException异常(参数验证失败会抛出这个异常,所以也就是为什么拦截这个异常的原因),返回自定义响应实体给到前端 -
测试
- 我已经测试过了,是可以的,我就不贴图片了(懒一下~)
单个、多个参数校验
-
控制器层方法接收的参数不是一个实体类,而是直接写明了参数个数的情况(一般参数个数低于三个可以这么写,超过3个还是建议用一个
DTO接收比较好~)
-
方法所在的控制器类上加注解
@Validated -
参数前面加入相对应的校验注解
这里有个坑需要注意~先接着往下看
-
测试,前端不传递
roomNumber参数-
前端并未收到房间号不能为空的信息
-
后端也并未打印出房间号为空的字样
这里需要注意,是因为加了
@RequestParam导致没传递参数被此注解给拦截了,并未走到@NotBlank所以既然加了
@NotBlank校验,可以把@RequestParam("roomNumber")给去掉 -
-
再次测试
-
后端:成功被全局异常所拦截,成功打印信息
-
前端:接收到了后端返回的信息,弹出对应的报错信息,相当完美!
-
-
传入一个三位数字的字符串,如预期一样提示出来了
总结
DTO参数
- 对应属性上加入校验规则注解
- 开启校验,在对应的方法参数前面加
@Validated
普通参数
- 控制器类上加入
@Validated- 方法参数前面加入对应的校验规则注解(注意:
@RequestParam注解)
- 编写有误还请大佬指正,万分感谢。