【工具】JSR-303后端参数校验框架的使用方法及说明

news2024/11/18 17:30:09

【工具】JSR-303后端参数校验框架的使用方法及说明

文章目录

  • 【工具】JSR-303后端参数校验框架的使用方法及说明
    • 1. 统一校验需求
    • 2. 使用说明
      • 2.1 引入依赖
      • 2.2 规则说明
      • 2.3 使用说明
      • 2.4 分组校验
      • 2.5 定制校验规则注解

1. 统一校验需求

有一句话是这样说的——“前端防君子,后端防小人”。这句话说明参数的校验在前端和后端都是十分重要的。不懂技术的人一般在前端页面无法找到系统的漏洞,但是懂技术又不怀好意的人如果获取到了你后端接口的地址,而恰好你后端又没有对参数进行校验,那么就很有可能会被他人乘虚而入,对系统造成很大的影响。为了避免这一情况的发生,所有我们需要在后端也进行参数的校验。

那么我们又有一个问题了,参数校验的代码是写在Controller层还是写在Service层呢?

对于一般的参数,我们应该是放在Controller层中进行校验,而对于业务逻辑的校验则在Service层中进行。Contoller中校验请求参数的合法性,包括:必填项校验,数据格式校验,比如:是否是符合一定的日期格式,等。Service中要校验的是业务规则相关的内容,比如:已存在的用户不能重复新增。

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

SpringBoot提供了JSR-303的支持,它就是 spring-boot-starter-validation,它的底层使用Hibernate Validator,Hibernate Validator是Bean Validation 的参考实现。

所以,我们准备在Controller层使用spring-boot-starter-validation完成对请求参数的基本合法性进行校验。


2. 使用说明

2.1 引入依赖

我们在项目的pom文件中添加如下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

2.2 规则说明

上面引入的依赖为我们提供了很多的注解,注解的使用规则如下:

2022091315452386

了解了使用的规则之后我们就可以开始使用了。


2.3 使用说明

1)场景描述

设定一个场景,我们需要添加一门课程,前端传入一系列的参数,我们后端使用dto去接收这些参数。同时我们还需要在Controller校验这些参数是否合法。

首先设定dto类代码如下所示:

@Data
public class AddCourseDto {

 @NotEmpty(message = "课程名称不能为空")
 private String name;

 @NotEmpty(message = "适用人群不能为空")
 @Size(message = "适用人群内容过少",min = 10)
 private String users;

 @NotEmpty(message = "课程分类不能为空")
 private String mt;

 @NotEmpty(message = "课程分类不能为空")
 private String st;

 @NotEmpty(message = "课程等级不能为空")
 private String grade;

 @NotEmpty(message = "收费规则不能为空")
 private String charge;
}

我们在这个dto中用到了两个校验注解 @NotEmpty@Size ,注解含义如上图所示。


2)定义接口

我们已经定义好了dto,然后我们需要在接口层对dto进行校验,校验的方法也很简单,只需要在接口的参数列表中添加一个 @Validated 注解。接口代码如下所示:

@PostMapping("/course")
public CourseBaseInfoDto createCourseBase(@RequestBody @Validated AddCourseDto addCourseDto){
    //...
  return courseBaseInfoService.createCourseBase(companyId,addCourseDto);
}

如果传入的参数中有不合规范的,Spring会抛出一个 MethodArgumentNotValidException 异常,我们需要在统一异常处理器中捕获异常,解析出异常信息。


3)编写异常处理逻辑

我们在统一异常处理器中对异常进行捕获,编写异常处理逻辑:

@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)//状态码返回500
public RestErrorResponse doMethodArgumentNotValidException(MethodArgumentNotValidException e) {
    BindingResult bindingResult = e.getBindingResult();
    //校验的错误信息
    List<FieldError> fieldErrors = bindingResult.getFieldErrors();
    //收集错误
    StringBuffer errors = new StringBuffer();
    fieldErrors.forEach(error -> {
        errors.append(error.getDefaultMessage()).append(",");
    });
    //将错误信息以json的形式返回
    return new RestErrorResponse(errors.toString());
}

我们使用httpcilent今昔测试,我们将name属性的值设为空。

POST {{content_host}}/course
Content-Type: application/json

{
  "mt": "1-1",
  "st": "1-1-1",
  "name": "",
  "pic": "",
  "teachmode": "200002",
  "users": "初级人员",
  "tags": "标签",
  "grade": "204001",
  "description": "",
  "charge": "201001",
  "price": 10,
  "originalPrice":100,
  "qq": "123",
  "wechat": "123",
  "phone": "123",
  "validDays": 365
}

进行测试:

返回信息:

image-20230225125047139

这时发现,参数校验已经生效了。但是我们这又会引发出另一个问题。那就是:

假如我们有两个接口的参数都包含了相同的dto,我们都需要对其进行校验,但是这两个接口对dto的校验规则又不一样,比如第一个接口要求dto的name属性不能为空,第二个接口却要求dto的name属性可以为空。那我们怎么办呢?我们是再创建一个和dto完全相同的类去重新编写校验规则吗?当然不是,Spring为我们提供了更好的解决方案——“分组校验”。


2.4 分组校验

有时候再同一个属性上设置一个校验规则并不能满足所有要求。

比如:订单编号由系统生成,在添加订单时要求订单编号为空,在更新订单时要求订单编写不能为空。此时就用到了分组校验,同一个属性定义多个校验规则属于不同的分组,比如:添加订单定义@NULL规则属于insert分组,更新订单定义@NotEmpty规则属于update分组,insert和update是分组的名称,是可以修改的。

1)分组

我们用class类型来表示不同的分组,所以我们定义不同的接口类型(空接口)表示不同的分组。代码如下所示:

public class ValidationGroups {

 public interface Inster{};
 public interface Update{};
 public interface Delete{};

}

2)指定分组

在dto中定义校验规则是指定分组,比如上面的name属性,我们可以为其指定两个分组。

@NotEmpty(groups = {ValidationGroups.Inster.class},message = "添加课程名称不能为空")
@NotEmpty(groups = {ValidationGroups.Update.class},message = "修改课程名称不能为空")
// @NotEmpty(message = "课程名称不能为空")
 private String name;

3)接口层引用分组

在Controller方法中启动校验规则指定要使用的分组名:

@PostMapping("/course")
public CourseBaseInfoDto createCourseBase(@RequestBody @Validated({ValidationGroups.Inster.class}) AddCourseDto addCourseDto){
    //。。。
  return courseBaseInfoService.createCourseBase(companyId,addCourseDto);
}

再次测试,由于这里指定了Insert分组,所以抛出 异常信息:添加课程名称不能为空。

如果修改分组为ValidationGroups.Update.class,异常信息为:修改课程名称不能为空。


2.5 定制校验规则注解

如果javax.validation.constraints包下的校验规则满足不了需求怎么办?

我们有两种方法:

  1. 手写校验代码。
  2. 自定义校验规则注解。

自定义校验规则注解的方法可以查看:自定义校验注解

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

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

相关文章

小知识点:Confluence + mysql 安装流程

流程一、Confluence 配置二、MySQL 配置三、启动一、Confluence 配置 访问下载地址&#xff0c;下载最新安装包 Confluence Server 下载存档 | Atlassian创建环境目录 mkdir -p /xxx/confluence/confluence-home 解压安装包 tar -zxvf atlassian-confluence-7.xx.x.tar.gz -C …

人工智能- windows10环境,配rtx 3060ti显卡,tensorflow-gpu安装

文章目录前言流程方法1.先安装网盘里的anaconda文件&#xff0c;安装后就是python3.8.8环境2.安装vs20193.vs2019安装完毕后开始安装cuda4.安装cudnn5.安装tensorflow-gpu6.测试GPU是否正常识别&#xff0c;tensorflow是否可用前言 最近显卡降价&#xff0c;入手了一块RTX3060…

ROS小车研究笔记:二维SLAM建图简介与源码分析

ROS提供了现成的各类建图算法实现。如果只是应用的话不需要了解详细算法原理&#xff0c;只需要了解其需要的输入输出即可。 1 Gmapping Gmapping使用粒子滤波算法进行建图&#xff0c;在小场景下准确度高&#xff0c;但是在大场地中会导致较大计算量和内存需求 Gmapping需要…

Go语言内存管理详解-学习笔记

1 自动内存管理 1.1 相关概念 Mutator&#xff1a;业务线程&#xff0c;分配新对象&#xff0c;修改对象指向关系Collector&#xff1a;GC线程&#xff0c;找到存活对象&#xff0c;回收死亡对象的内存空间Serial GC&#xff1a;只有一个collector&#xff08;需要暂停&#…

读书笔记//《数据分析之道》

出版时间&#xff1a;2022年 作者曾在互联网大厂做数据分析。从举例可以洞见作者的工作经历。 点评&#xff1a;作者在数据分析领域非常资深&#xff0c;尝试在书中提供一个数据分析工作框架参考。书本内容有点感觉是ppt的集合&#xff0c;辅以案例说明。不过&#xff0c;干货还…

基于ORB-SLAM2+RTAB-MAP+ROS的三维重建设计——环境配置与安装

写下这篇是为了毕设题目《基于深度相机的电缆识别系统》。使用的设备与环境如下&#xff1a;Ubuntu 20.04ROSGazebo仿真运行Kinect 2.0ORB-SLAM2论文地址&#xff1a;https://arxiv.org/abs/1610.06475GitHub&#xff1a;https://github.com/raulmur/ORB_SLAM2一、为什么要选择…

python多线程网络编程

背景 使用过flask框架后&#xff0c;我对request这个全局实例非常感兴趣。它在客户端发起请求后会保存着所有的客户端数据&#xff0c;例如用户上传的表单或者文件等。那么在很多客户端发起请求时&#xff0c;服务器是怎么去区分不同的request对象呢&#xff1f;当查看了大量的…

Android 8请求权限时弹窗BUG

弹窗BUG 应用使用requestPermissions申请权限时&#xff0c;系统会弹出一个选择窗口&#xff0c;可进行允许或拒绝&#xff0c; 此窗口中有一个”不再询问“的选择框&#xff0c; ”拒绝”及“允许”的按钮。 遇到一个Bug,单点击“不再询问”&#xff0c;“允许”这个按钮会变…

OpenAPI SDK组件介绍

背景 公司成立以来&#xff0c;积累了数以万计的可复用接口。上层的SaaS业务&#xff0c;原则上要复用这些接口开发自己的业务&#xff0c;为了屏蔽调用接口的复杂性&#xff0c;基础服务开发了apisdk组件&#xff0c;定义了一套声明OpenAPI的注解、注解解析器&#xff0c;实例…

【蓝牙mesh】Bearer层(承载层)介绍

【蓝牙mesh】Bearer层&#xff08;承载层&#xff09;介绍 Bearer层简介 蓝牙Mesh协议栈由多个不同的协议层组成&#xff0c;其中最底层的协议就是Bearer层&#xff0c;它负责提供数据传输的底层支持。蓝牙Mesh协议栈的最底层就是BLE协议栈&#xff0c;所以Bearer层是直接与BL…

GO 中的 defer 有哪些注意事项?下

上次一起写了 3 个案例&#xff0c;咱们这一次继续&#xff0c;这一次的会比上一次的稍微不太一样 案例 1 还有一个也非常常用的案例&#xff0c;使用 defer 来捕获异常 &#xff0c;也就是当程序崩溃的时候&#xff0c;defer 语句可以帮我们兜底&#xff0c;可以捕获异常后按…

vscode 配置 codeql

1、安装配置 codeql 环境 1.1 下载 codeql-cli 和 codeql 标准库 1&#xff09;下载安装 下载安装 codeql-cli: Releases github/codeql-cli-binaries GitHub 下载 codeql 标准库&#xff1a;https://github.com/gi thub/codeql 下载的安装包解压&#xff0c;codeql 可执…

二,从源代码开始编译安装iperf3

本文目录Linux系统中编译安装基本知识简介第一步&#xff0c;执行configure第二步&#xff0c;执行make第三步&#xff0c;make install其它功能说明Linux系统中编译安装基本知识简介 从前一文章"一&#xff0c;下载iPerf3最新源代码"我们已经知道如何通过git的方式…

Linux系统下命令行安装MySQL5.6+详细步骤

1、因为想在腾讯云的服务器上创建自己的数据库&#xff0c;所以我在这里是通过使用Xshell 7来连接腾讯云的远程服务器&#xff1b; 2、Xshell 7与服务器连接好之后&#xff0c;就可以开始进行数据库的安装了&#xff08;如果服务器曾经安装过数据库&#xff0c;得将之前安装的…

干货 | 八条“黄金规则”解决RF电路寄生信号

PART 01 接地通孔应位于接地参考层开关处流经所布线路的所有电流都有相等的回流。耦合策略固然很多&#xff0c;不过回流通常流经相邻的接地层或与信号线路并行布置的接地。在参考层继续时&#xff0c;所有耦合都仅限于传输线路&#xff0c;一切都非常正常。不过&#xff0c;如…

MySQL关于NULL值,常见的几个坑

数据库版本MySQL8。 1.count 函数 觉得 NULL值 不算数 &#xff0c;所以开发中要避免count的时候丢失数据。 如图所示&#xff0c;以下有7条记录&#xff0c;但是count(name)却只有6条。 为什么丢失数据&#xff1f;因为MySQL的count函数觉得 Null值不算数&#xff0c;就是说…

Shader(着色)

1.深度测试&#xff08;Z-Buffer &#xff09;每个像素需要一个深度来排序是否需要渲染&#xff0c;所以需要额外的buffer来存储&#xff0c;frame buffer 存颜色&#xff0c;depth buffer (z-buffer) 存深度。2.Lambert(漫反射)3.Blinn-Phong &#xff08;高光&#xff09;4.环…

Netty权威指南总结(一)

一、为什么选择Netty&#xff1a;API使用简单&#xff0c;开发门槛低&#xff0c;屏蔽了NIO通信的底层细节。功能强大&#xff0c;预制了很多种编解码功能&#xff0c;支持主流协议。定制能力强&#xff0c;可以通过ChannelHandler对通信框架进行灵活地拓展。性能高、成熟、稳定…

一文搞定Android Vsync原理简析

屏幕渲染原理"现代计算机之父"冯诺依曼提出了计算机的体系结构: 计算机由运算器&#xff0c;存储器&#xff0c;控制器&#xff0c;输入设备和输出设备构成&#xff0c;每部分各司其职&#xff0c;它们之间通过控制信号进行交互。计算机发展到现在&#xff0c;已经出…

【Python知识点桂电版】01基本数据类型

一、变量变量定义注&#xff1a;查看变量类型->type(变量)查看变量地址->id(变量)变量命名规则只允许出现&#xff1a;英文、中文、数字、下划线&#xff08;不推荐用中文&#xff0c;不能以数字开头&#xff09;大小写敏感不可使用关键字&#xff08;如and&#xff09;和…