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

news2024/11/25 10:47:06

目录

1. 添加依赖

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

3. 关于响应的消息文本

4.  快速失败

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


1. 添加依赖

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

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

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

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

 例如:

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

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

@Data
public class AlbumAddNewDTO implements Serializable {

    @ApiModelProperty(value = "相册名称", required = true)
    @NotNull // 新添加的注解
    private String name;
    
    // 省略后续代码

完成后,重启服务,通过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 errors<EOL>Field 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中添加新的枚举值:

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

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

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

3. 关于响应的消息文本

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

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

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

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

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

@ExceptionHandler
public JsonResult handleBindException(BindException e) {
    String delimiter = ",";
    String prefix = "添加相册失败,";
    String suffix = "!";
    StringJoiner stringJoiner = new StringJoiner(delimiter, prefix, suffix);
    List<FieldError> fieldErrors = e.getFieldErrors();
    for (FieldError fieldError : fieldErrors) {
        String defaultMessage = fieldError.getDefaultMessage();
        stringJoiner.add(defaultMessage);
    }
    return JsonResult.fail(ServiceCode.ERR_BAD_REQUEST, stringJoiner.toString());
}

4.  快速失败

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

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

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

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

import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.HibernateValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.validation.Validation;

@Slf4j
@Configuration
public class ValidationConfiguration {

    public ValidationConfiguration() {
        log.debug("创建配置类对象:ValidationConfiguration");
    }

    @Bean
    public javax.validation.Validator validator() {
        return Validation.byProvider(HibernateValidator.class)
                .configure() // 开始配置
                .failFast(true) // 配置快速失败
                .buildValidatorFactory() // 构建Validator工厂
                .getValidator(); // 从Validator工厂中获取Validator对象
    }

}

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

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

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

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

// http://localhost:9080/brand/delete
@PostMapping("/delete")
public void delete(Long id) {
}

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

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

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

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

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

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

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

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

@ExceptionHandler
public JsonResult handleConstraintViolationException(ConstraintViolationException e) {
    Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
    String delimiter = ",";
    StringJoiner stringJoiner = new StringJoiner(delimiter);
    for (ConstraintViolation<?> constraintViolation : constraintViolations) {
        stringJoiner.add(constraintViolation.getMessage());
    }
    return JsonResult.fail(ServiceCode.ERR_BAD_REQUEST, stringJoiner.toString());
}

个人主页:居然天上楼

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

人生海海,山山而川

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

是对我最大的支持与鞭策

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/53039.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ctfshow 月饼杯

寒假打算认真学习一下&#xff0c;就先从半个月的刷题开始。 文章目录web1_此夜圆web2_故人心web3_莫负婵娟web1_此夜圆 题目给的有附件&#xff0c;一看就是php反序列化字符串逃逸(应该是签到题)。 源码&#xff1a; <?php error_reporting(0);class a {public $uname;…

负载均衡组件Ribbon核心-@LoadBalanced-下

引言 书接上篇 负载均衡组件Ribbon核心-LoadBalanced-上 我们讲完了理解LoadBalanced注解的知识准备&#xff0c;接下来就是LoadBalanced注解详解。 LoadBalancerAutoConfiguration 激活 LoadBalanced 注解功能起点来至LoadBalancerAutoConfiguration自动配置类&#xff0c;S…

uni-app 超详细教程(三)(从菜鸟到大佬)

本文中内容为&#xff1a; 1. 支付功能&#xff08;微信支付&#xff0c;支付宝支付&#xff09; 2. 项目打包&#xff1a;&#xff08;APP打包&#xff0c;H5打包&#xff0c;微信小程序打包&#xff09; 一&#xff0c;uni - app 的支付功能 一、微信支付 1、登录微信开…

如何在Ubuntu20.04上安装RDP远程

计算机最有意思的事情&#xff0c;就是你可以用任何方式去实现跨设备连接。例如google通过webrtc实现远程桌面&#xff0c;Linux则是常用ssh等。在远程桌面上一般分为windows的RDP和Unix/Linux的VNC。 常规在windows上winr输入mstsc,我们通过微软的RDP技术去远程计算机。RDP和…

C#Lambda让代码变得更加简洁而优雅

Using a lambda expression&#xff0c;we can make the code more compact and elegant。   在使用lambda表达式时&#xff0c;可以使代码更加简洁和优雅。 Lambda&#xff0c;希腊字母λ&#xff0c;在C#编程语言中&#xff0c;被引入为Lambda表达式&#xff0c;表示为匿名…

使用[阿里问题定位神器]Arthas入门

目录 注意 安装 在线安装 离线安装 目前我接触到的实用命令 dashboard heapdump thread jad stack trace 注意 arthas本身有一定的性能消耗&#xff0c;所以生产环境小心使用 arthas本身有一定的性能消耗&#xff0c;所以生产环境小心使用 arthas本身有一定的性能…

【Linux】万字总结Linux 基本指令,绝对详细!!!

文章目录 Linux 基本指令 ls 指令 alias 指令 cd指令 pwd 指令 clear指令 touch 指令 mkdir 指令&#xff08;重要&#xff09; rmdir指令 && rm 指令&#xff08;重要&#xff09;&#xff1a; man指令&#xff08;重要&#xff09; cp指令&#xff08;重…

闭关三个月,腾讯大咖手写Framework最新源码笔记,从基础到进阶直接封神

什么是Android Framework 我们首先给出Android Framework的定义&#xff0c;然后再对该定义给出详细的解释。 Android Framework包含三个内容&#xff1a;服务端、客户端、linux驱动 服务端 Android Framework服务端包括两个很重要的类&#xff1a;WindowManagerService (W…

实验(六):定时器实验

一、实验目的与任务 实验目的&#xff1a; 1&#xff0e;掌握定时/计数器的中断法工作原理&#xff1b; 2&#xff0e;熟悉C51编程与调试方法。 任务&#xff1a; 1. 运行Keil开发环境&#xff0c;完成定时器软件编程&#xff1b; 2. 建立Proteus仿真模型&#xff1b; 3&#x…

day15_面向对象的三大特征之一(继承)

继承的概述 Java是对现实社会的模拟&#xff0c;现实中有儿子可以继承父亲的财产&#xff0c;因此有了富二代的。 java中多个类中存在相同属性和行为时&#xff0c;将这些内容抽取到单独一个类中&#xff0c;那么多个类中无需再定义这些属性和行为&#xff0c;只需要和抽取出来…

CSDNtop1全栈接口测试教程 jmeter接口测试,接口自动化测试

测试时优先对其进行结构化拆分&#xff0c;将测试整体拆分为各个场景 创建线程组&#xff0c;简单控制器&#xff0c;HTTP请求默认值&#xff0c;HTTP信息头管理器 将测试目标结构化&#xff0c;可以更好地管理测试框架和整合其他组件&#xff0c;有利于反馈工作 添加HTTP请求…

如何做好自动化测试?揭开测试项目团队的自动化实践过程……

稍具测试规模的项目团队皆想引进自动化测试&#xff0c;然而动手实现自动化测试的团队却不多&#xff0c;未能真正实施的原因多种多样&#xff0c;有扼杀在摇篮里的&#xff0c;有写了后弃之不用。那么是不是所有的业务都适合自动化测试呢&#xff1f;下面就介绍下自己在项目中…

超级好用的笔记工具------Typora 如何修改Typora 中图片保存的位置

用了这么多的笔记、最后还是选择了Typora。真的是很不错呐。一些私密的笔记、比如公司内部资料。放到网页多多少少是不安全的。还是放到本地安全的多。 1、使用Typora 做的小笔记 1.1 目录情况 这个可以按照自己的进度或者时间节点自行分级 1.2 某一个页面的具体设计 2、基本…

react18 通过redux 做一个简单的状态管理基站

我们打开react项目 在终端输入 npm install redux --saveredux就进来了 这里 我们引入了 redux 但其实 有一个 redux 和一个 react-redux 两者区别在于 redux 是一个js的状态管理容器 而react-redux 则提供了 更多便于react开发的状态管理方法 然后我们在项目的src目录下创…

4-FreeRTOS队列、互斥、信号量

1-队列 队列&#xff08;我对队列的理解就是上体育课&#xff0c;排队这种&#xff09;是任务之间通信的一种方式。队列可以用于任务和任务之间或者中断和任务之间消息的接收与发送。在多数情况下&#xff0c;他们消息缓冲是按照FIFO&#xff08;先进先出&#xff09;原则。也…

文本处理方式方法

概述 从今天开始&#xff0c;我们将开启一段自然语言处理的流程&#xff0c;自然语言可以让来处理、理解以及运用人类的语言&#xff0c;实现机器语言和人类语言之间的沟通桥梁。 文本处理 我们正在进行文本处理的时候&#xff0c;经常会用到文本长度不一致的情况&#xff0c…

Microsoft SQL Server 图书管理数据库的建立

文章目录题目描述创建数据库使用数据库创建三个表外码的表示形式结果展示题目描述 – 新建 “图书管理数据库" – 其中包含三个关系 – 图书&#xff08;编号&#xff0c;图书名&#xff0c;作者&#xff0c;出版社&#xff0c;类型&#xff0c;单价&#xff09; – 借阅…

ASP.NET Core 3.1系列(16)——Entity Framework Core之Code First

1、前言 前一篇博客介绍了EFCore中的DB First开发模式&#xff0c;该模式可以根据数据库生成实体类和数据库上下文&#xff0c;因此适用于数据库已经存在的场景。而与之相对应的&#xff0c;Code First主要是根据自定义的实体类和数据库上下文反向构建数据库&#xff0c;因此也…

操作系统02_进程管理_同步互斥信号量_PV操作_死锁---软考高级系统架构师007

存储管理可以分为固定存储管理和分页存储管理。 现在固定存储管理已经不用也不考,但要知道因为固定存储管理指的是整存整取 也就是把一整个程序,比如说10G的游戏全部都存到内存里 这样的话是非常占用内存的,这个固定存储管理现在已经不用了。 然后这里我们主要看分页存储管: …

网页去色变黑白+网页黑白恢复为彩色

前言 特定节日&#xff0c;你会发现网页和app首页都会变成灰色&#xff0c;以此来表达我们的哀思之情。 好奇宝宝想知道各个网站都是使用哪些小技巧来做出这种效果的&#xff08;由彩变灰&#xff0c;由灰变彩&#xff09;&#xff0c;于是稍微学习了一下… 由灰变彩 稍微想…