• 【在SpringBoot项目中使用Validation框架检查数据格式】


    目录

    1. 添加依赖

    2. 检查POJO类型的请求参数

    3. 关于响应的消息文本

    4.  快速失败

    5. 检查未封装的请求参数


    1. 添加依赖

    pom.xml中添加spring-boot-starter-validation依赖项:

    1. <!-- Spring Boot Validation框架,用于检查数据格式 -->
    2. <dependency>
    3. <groupId>org.springframework.boot</groupId>
    4. <artifactId>spring-boot-starter-validation</artifactId>
    5. </dependency>

    2. 检查POJO类型的请求参数

    首先,在POJO参数前添加@Valid@Validated注解,用于表示此参数是需要通过Validation框架进行检查的!

     例如:

    1. @ApiOperation("添加相册")
    2. @PostMapping("/add-new")
    3. // ↓ 新添加的注解
    4. public JsonResult addNew(@Valid AlbumAddNewDTO albumAddNewDTO) {
    5. albumService.addNew(albumAddNewDTO);
    6. return JsonResult.ok();
    7. }

    然后,在此参数的属性上添加检查注解,例如添加@NotNull注解,表示将对此属性进行检查,此属性的值不允许为null

    1. @Data
    2. public class AlbumAddNewDTO implements Serializable {
    3. @ApiModelProperty(value = "相册名称", required = true)
    4. @NotNull // 新添加的注解
    5. private String name;
    6. // 省略后续代码

    完成后,重启服务,通过API文档提交请求时,故意不提交name(将对应的输入框删除),则服务器端尝试接收的name就会是null,无法通过@NotNull的检查规则,默认将出现400错误,例如:

    {
      "timestamp": "2022-12-01T06:38:26.020+00:00",
      "status": 400,
      "error": "Bad Request",
      "path": "/album/add-new"
    }

    并且,在服务器端的控制台会提示以下错误:

    2022-12-01 14:38:26.017  WARN 10708 --- [io-9080-exec-10] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errorsField error in object 'albumAddNewDTO' on field 'name': rejected value [null]; codes [NotNull.albumAddNewDTO.name,NotNull.name,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [albumAddNewDTO.name,name]; arguments []; default message [name]]; default message [不能为null]]

    可以看到,当检查不通过时,将出现org.springframework.validation.BindException异常!

    ServiceCode中添加新的枚举值:

    1. * 错误:请求参数格式有误
    2. */
    3. ERR_BAD_REQUEST(400),

    GlobalExceptionHandler中添加处理BindException异常的代码:

    1. @ExceptionHandler
    2. public JsonResult handleBindException(BindException e) {
    3. String message = "请求参数格式错误!";
    4. return JsonResult.fail(ServiceCode.ERR_BAD_REQUEST, message);
    5. }

    3. 关于响应的消息文本

    所有检查注解都可以配置检查不通过后的提示文本,例如:

    @NotNull(message = "必须提交相册名称")

    在处理异常时,应该将此处配置的文本响应到客户端去,可以通过异常对象获取以上文本!

    由于客户端提交的若干个请求参数可能有多种错误,则异常对象中可能封装了多个错误信息!如果需要显示所有错误,应该先获取全部信息,然后将这些错误信息组织起来,并响应到客户端去!

    所以,处理异常的代码可以调整为:

    1. @ExceptionHandler
    2. public JsonResult handleBindException(BindException e) {
    3. String delimiter = ",";
    4. String prefix = "添加相册失败,";
    5. String suffix = "!";
    6. StringJoiner stringJoiner = new StringJoiner(delimiter, prefix, suffix);
    7. List<FieldError> fieldErrors = e.getFieldErrors();
    8. for (FieldError fieldError : fieldErrors) {
    9. String defaultMessage = fieldError.getDefaultMessage();
    10. stringJoiner.add(defaultMessage);
    11. }
    12. return JsonResult.fail(ServiceCode.ERR_BAD_REQUEST, stringJoiner.toString());
    13. }

    4.  快速失败

    Validation框架有快速失败的机制,默认是未开启的,当客户端提交的请求参数有多种错误时,会进行全部的检查,发现所有错误!如果开启快速失败,当检查出第1个错误时,就会停止检查!

    配置快速失败,需要创建Valiator类型的对象,通过此对象进行配置,并且,此对象必须被保存在Spring容器中,框架会自动应用它!

    当需要创建某个对象并使它保存在Spring容器中,可以在配置类中添加@Bean方法,此方法返回相关对象,在启动项目时,Spring框架会自动调用此方法并将返回保存在Spring容器中。

    在项目的根包下创建config.ValidationConfiguration配置类,在此配置类中通过@Bean方法返回Validator对象,并在返回之前将此对象配置为快速失败的:

    1. import lombok.extern.slf4j.Slf4j;
    2. import org.hibernate.validator.HibernateValidator;
    3. import org.springframework.context.annotation.Bean;
    4. import org.springframework.context.annotation.Configuration;
    5. import javax.validation.Validation;
    6. @Slf4j
    7. @Configuration
    8. public class ValidationConfiguration {
    9. public ValidationConfiguration() {
    10. log.debug("创建配置类对象:ValidationConfiguration");
    11. }
    12. @Bean
    13. public javax.validation.Validator validator() {
    14. return Validation.byProvider(HibernateValidator.class)
    15. .configure() // 开始配置
    16. .failFast(true) // 配置快速失败
    17. .buildValidatorFactory() // 构建Validator工厂
    18. .getValidator(); // 从Validator工厂中获取Validator对象
    19. }
    20. }

    当配置了快速失败后,无论请求参数有多少种错误,都会在发现第1个错误后停止检查,所以,处理异常时,只需要直接获取错误对象即可,不必获取所有错误对象!即:

    1. @ExceptionHandler
    2. public JsonResult handleBindException(BindException e) {
    3. StringBuilder stringBuilder = new StringBuilder();
    4. String prefix = "添加相册失败,";
    5. String suffix = "!";
    6. String defaultMessage = e.getFieldError().getDefaultMessage();
    7. stringBuilder.append(prefix).append(defaultMessage).append(suffix);
    8. return JsonResult.fail(ServiceCode.ERR_BAD_REQUEST, stringBuilder.toString());
    9. }

    5. 检查未封装的请求参数

    如果某些请求的参数较少,或各参数并不相关,则不会将它们封装在一起,例如:

    1. // http://localhost:9080/brand/delete
    2. @PostMapping("/delete")
    3. public void delete(Long id) {
    4. }

    当需要检查这类参数时,首先,需要在当前类上添加@Validated注解,例如:

    1. @RestController
    2. @RequestMapping("/brand")
    3. @Validated // 新添加的注解
    4. public class BrandController {
    5. // 省略其它代码

    然后,在请求参数上添加检查注解,例如:

    1. // http://localhost:9080/brand/delete
    2. @PostMapping("/delete")
    3. // ↓ 新添加的注解
    4. public void delete(@Range(min = 1, max = 996) @RequestParam Long id) {
    5. }

    **提示:**以上@RequestParam在此处并无实际意义,但是,不添加此注解的话,在线API文档的调试界面中不会出现此参数的输入框,所以暂时添加上此注解,后续将删除!

    完成后,重启项目,在API文档中调整,如果提交的id参数值不在[1, 996]范围内,将出现500错误(注意:不要处理RuntimeException),则控制台会提示错误:

    javax.validation.ConstraintViolationException: delete.id: 需要在1和996之间

    则应该在全局异常处理器添加对以上异常的处理:

    1. @ExceptionHandler
    2. public JsonResult handleConstraintViolationException(ConstraintViolationException e) {
    3. Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
    4. String delimiter = ",";
    5. StringJoiner stringJoiner = new StringJoiner(delimiter);
    6. for (ConstraintViolation<?> constraintViolation : constraintViolations) {
    7. stringJoiner.add(constraintViolation.getMessage());
    8. }
    9. return JsonResult.fail(ServiceCode.ERR_BAD_REQUEST, stringJoiner.toString());
    10. }

    个人主页:居然天上楼

    感谢你这么可爱帅气还这么热爱学习~~

    人生海海,山山而川

    你的点赞👍 收藏⭐ 留言📝 加关注✅

    是对我最大的支持与鞭策

  • 相关阅读:
    CTO与CIO选型数据中台的几大建议
    8086/8088CPU的储存器结构(二)
    关闭EasyConnect进程详细步骤
    ONLYOFFICE 桌面编辑器 v8.0 更新内容详细攻略
    SQL 左连接 LEFT JOIN 关键字||SQL右连接 RIGHT JOIN 关键字
    为什么大家想要晋升职称?工程师职称有什么用?
    【Linux】Linux系统中安装Zookeeper集群的详细配置
    用AI打造一个属于自己的歌手,让她C位霸气出道
    ChatGPT批量写作文章软件
    研发效能DevOps: OpenEuler 部署 drone 持续集成平台
  • 原文地址:https://blog.csdn.net/weixin_72612071/article/details/128139906