Java后端Controller参数校验的一些干货及问题~

209 阅读6分钟

你们好,我是金金金。

image.png

场景

先看如下一张图,这是一个控制器里面的一个方法,第一眼是不是就感觉代码量非常多?而且随着参数越来越多 你则需要写nif else来完成校验,属实是麻烦而且不够优雅

image.png

JSR303校验

仔细认真看,更容易理解吸收,想想什么层面需要做校验呢?

  • 前端请求后端接口传输参数,是在controller中校验还是在Service中校验?

都需要校验,只是分工不同。

  • Contoller中校验请求参数的合法性,包括:必填项校验,数据格式校验,比如:是否是符合一定的日期格式,等。

  • Service中要校验的是业务规则相关的内容,比如:课程已经审核通过所以提交失败。

  • Service中根据业务规则去校验不方便写成通用代码,Controller中则可以将校验的代码写成通用代码。

  • Service层,校验是和业务逻辑紧密相关的。因为不同的业务场景下,校验规则可能不同,很难将这些规则抽象成通用的代码。 比如,在处理订单的Service层中,校验的逻辑可能会涉及多个业务条件和数据库查询,这些条件可能只在特定的业务场景下适用,难以通用化。

    • 所以一般service层都是手动if校验

    image.png

  • Controller层,校验通常是对请求参数的基本合法性进行验证 例如字段是否为空、长度是否在允许范围内、值是否在有效范围内等。由于这些校验规则通常是标准化的,不依赖于复杂的业务逻辑,因此很容易抽象成通用代码。 例如,可以使用注解、AOP等方式实现通用的参数校验逻辑,这样在不同的Controller中都可以复用这些校验逻辑。

    • 所以controller层一般可以使用注解做校验

      image.png 早在JavaEE6规范中就定义了参数校验的规范,它就是JSR-303,它定义了Bean Validation,即对bean属性进行校验。

SpringBoot提供了JSR-303的支持,它就是spring-boot-starter-validation,它的底层使用Hibernate ValidatorHibernate ValidatorBean 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>

规则对应参考如下:

image.png

实体类

  • 控制器层方法接收的参数是一个DTO实体类

    image.png

  1. 定义校验规则:首先找到这个DTO,在对应的属性上面添加对应的校验注解

    image.png

  2. 开启校验:在Controller方法接收参数前面加上注解@Validated

    image.png

  3. 自定义全局校验拦截MethodArgumentNotValidException异常(参数验证失败会抛出这个异常,所以也就是为什么拦截这个异常的原因),返回自定义响应实体给到前端

    image.png

  4. 测试

    • 我已经测试过了,是可以的,我就不贴图片了(懒一下~)

单个、多个参数校验

  • 控制器层方法接收的参数不是一个实体类,而是直接写明了参数个数的情况(一般参数个数低于三个可以这么写,超过3个还是建议用一个DTO接收比较好~)

    image.png

  1. 方法所在的控制器类上加注解@Validated

    image.png

  2. 参数前面加入相对应的校验注解

    image.png

    这里有个坑需要注意~先接着往下看

  3. 测试,前端不传递roomNumber参数

    • 前端并未收到房间号不能为空的信息

      image.png

    • 后端也并未打印出房间号为空的字样

      image.png

    这里需要注意,是因为加了@RequestParam导致没传递参数被此注解给拦截了,并未走到@NotBlank

    所以既然加了@NotBlank校验,可以把@RequestParam("roomNumber")给去掉

    image.png

  4. 再次测试

    • 后端:成功被全局异常所拦截,成功打印信息

      image.png

    • 前端:接收到了后端返回的信息,弹出对应的报错信息,相当完美!

      image.png

  • 传入一个三位数字的字符串,如预期一样提示出来了

    image.png

总结

DTO参数

  1. 对应属性上加入校验规则注解
  2. 开启校验,在对应的方法参数前面加@Validated

普通参数

  1. 控制器类上加入@Validated
  2. 方法参数前面加入对应的校验规则注解(注意:@RequestParam注解)
  • 编写有误还请大佬指正,万分感谢。