当前位置: 首页 > news >正文

【spring】参数校验Validation

前言

在实际开发中,我们无法保证客户端传来的请求都是合法的。比如一些要求必传的参数没有传递,传来的参数长度不符合要求等,这种时候如果放任不管,继续执行后续业务逻辑,很有可能就会出现意想不到的bug。

有人可能会说,这不是前端的问题吗,让前端校验去。话是这么说,但我们也不能前端校验百分百不会出现问题。并且有些请求可能也不是正规通过客户端发来的,可能是黑客恶意攻击,又或是通过Postman等发来的,这些请求就不一定会“合法”了。

因此,对客户端传来的每个请求都进行必要的参数校验是十分重要的。而很多简单的校验如果都需要程序员自己去写的话,就会导致代码过于冗长、繁琐。为了让校验更加简洁明了,Spring为我们提供了Validation工具类来提供各种校验方法。

一、Validation常见的校验注解

空校验注解

  • @Null:被注释的元素必须为null
  • @NotNull:被注释的元素必须不为null
  • @NotBlank:被注释的字符串去掉前后空格后长度必须非零。
  • @NotEmpty:被注释的字符串、集合或数组不能为空(字符串长度非零、集合大小非零)。

布尔校验注解

  • @AssertTrue:被注释的元素必须为true
  • @AssertFalse:被注释的元素必须为false

日期校验注解

  • @Past:被注释的元素必须是一个过去的日期。
  • @Future:被注释的元素必须是一个将来的日期。

数字校验注解

  • @Min(value):被注释的元素必须是一个数字,其值必须大于等于指定的最小值。
  • @Max(value):被注释的元素必须是一个数字,其值必须小于等于指定的最大值。
  • @DecimalMin(value):被注释的元素必须是一个数字,其值必须大于等于指定的最小值。
  • @DecimalMax(value):被注释的元素必须是一个数字,其值必须小于等于指定的最大值。

长度校验注解

  • @Size(max, min):被注释的元素(如字符串、集合、数组)的大小必须在指定的范围内。

模式匹配校验注解

  • @Pattern(regexp):被注释的元素必须符合指定的正则表达式。

邮箱校验注解

  • @Email:被注释的元素必须是电子邮箱地址。

范围校验注解

  • @Range(min, max):被注释的元素必须在合适的范围内。

二、Validation的简单应用

首先我们需要导入Validation的依赖:

<!--validation依赖,负责参数校验-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>
</dependency>

接着在需要使用校验的类上添加@Validation注解

接着主要有两种方式使用校验注解:

1、直接在对应参数上加上注解

@RestController
@RequestMapping("/user")
@Validation
public class UserController {@RequestMapping("/login")public Result login(@Size(max = 12,min = 4) String username, @Pattern(regexp = "^\S{5,16}$") String password){//登录return Result.success();}}

2、实体类添加校验

对于一些实体类来说,直接在参数上加注解就不太可取了,程序会无法定位到指定参数。

需要再实体类内部对应的变量上添加注解:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Category {@NotNullprivate Integer id;//主键ID@NotEmptyprivate String categoryName;//分类名称@NotEmptyprivate String categoryAlias;//分类别名private Integer createUser;//创建人ID@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime createTime;//创建时间@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime updateTime;//更新时间
}

接着在使用实体类的地方加上 @Validated 注解,就能让这些校验生效了:

@PutMapping("/update")public Result update(@RequestBody @Validated User user){//业务逻辑return Result.success();}

二、分组校验

前面我们介绍了如何在实体类中添加校验注解。但是,事实上在实现不同功能时,对同一个实体类的校验规则可能是会有差异的。

比如在添加用户的场景下,用户的id值就是在存入数据库后生成的,在参数传递时自然就不是必传项;而在更新用户的场景下,我们需要通过id定位指定用户,完成信息更新操作,这时在参数传递时id就是必传项了。

这样,对id值的校验就会产生冲突了。如果将id设定为必传值,那么就会导致添加用户的操作可能出现错误。不把id设定为必传值,更新用户的操作又会出现错误。

为了应对这一问题,就可以对校验项进行分组归类。具体操作步骤如下:

在实体类内部定义相应组别接口:

public class User {//各成员变量//添加用户类分组public interface Add extends Default {}//更新用户类分组public interface Update extends Default{}
}

注意:如果没有手动对校验项进行分组,其默认就在 Default

对校验项进行分组,只需要通过groups属性指定组别即可:

@NotNull(groups = Update.class)

接着在校验时指定对应的分组即可:

@PutMapping
public Result update(@RequestBody @Validated(User.Update.class) User user){//业务逻辑return Result.success();
}@PostMapping
public Result add(@RequestBody @Validated(User.Add.class) User user){//业务逻辑return Result.success();
}

这样就能实现不同业务场景下的多样化校验了。

三、自定义校验

实际开发中的校验规则可能是五花八门的,但官方提供的校验注解就这么多,很多时候并不能满足我们的校验需求。这时候就需要通过自定义校验注解来实现个性化的校验了。

首先需要定义一个注解:

@Documented //元注解
@Target(ElementType.FIELD) //元注解
@Retention(RetentionPolicy.RUNTIME) //元注解
@Constraint(validatedBy = {/*校验规则*/}) //自定义校验规则
public @interface State {//提供校验失败后的提示信息String message() default "state参数的值只能是已发布或草稿";//指定分组Class<?>[] groups() default {};//负载  获取到State注解的附加信息Class<? extends Payload>[] payload() default {};
}

接着定义一个类去实现 ConstraintValidator 接口,并实现 isValid 方法:

public class StateValidation implements ConstraintValidator<State,String> {@Overridepublic boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {//返回true表示校验通过,返回false则表示校验不通过if(value==null) return false;if(value.equals("已发布")||value.equals("草稿"))return true;return false;}
}

然后就要在之前定义的注解中的@Constraint中填入自定义类:

@Constraint(validatedBy = {StateValidation.class}) //自定义校验规则

接着就可以像使用其它校验注解一样来使用自己自定义的注解了:


那么本篇文章就到此为止了,如果觉得这篇文章对你有帮助的话,可以点一下关注和点赞来支持作者哦。如果有什么讲的不对的地方欢迎在评论区指出,希望能够和你们一起进步

相关文章:

【spring】参数校验Validation

前言 在实际开发中&#xff0c;我们无法保证客户端传来的请求都是合法的。比如一些要求必传的参数没有传递&#xff0c;传来的参数长度不符合要求等&#xff0c;这种时候如果放任不管&#xff0c;继续执行后续业务逻辑&#xff0c;很有可能就会出现意想不到的bug。 有人可能会…...

基于PyQt5的UI界面开发——图像与视频的加载与显示

介绍 这里我们的主要目标是实现一个基于PyQt5和OpenCV的图像浏览和视频播放应用。用户可以选择本地的图像或视频文件夹&#xff0c;进行图像自动播放和图像切换以及视频播放和调用摄像头等操作&#xff0c;并且支持图像保存功能。项目的核心设计包括文件路径选择、图像或视频的…...

[python SQLAlchemy数据库操作入门]-16.CTE:简化你的复杂查询

哈喽,大家好,我是木头左! 在SQL的世界里,Common Table Expressions(公共表表达式),简称CTE,是一种强大的工具,它允许用户在单个查询中定义临时的结果集。这些结果集可以在整个查询中被多次引用,就像它们是数据库中的物理表一样。CTE不仅提供了一种组织和简化复杂查询…...

多分类的损失函数

在多分类任务中,常用的损失函数能够衡量模型输出的类别分布与目标类别之间的差异,帮助模型学习更准确的分类能力。以下是多分类任务中常用的损失函数: 1. 交叉熵损失(Cross-Entropy Loss) 公式: CrossEntropyLoss = − 1 N ∑ i =...

在WSL的系统中配置免密和GitHub传输数据(SSH)

在 WSL&#xff08;Windows Subsystem for Linux&#xff09;系统中配置免密与 GitHub 传输数据&#xff0c;主要包括设置 SSH 密钥对、将公钥添加到 GitHub 账户以及确保可以通过 WSL 正常使用这些密钥。以下是详细的步骤&#xff1a; 1. 检查现有 SSH 密钥 首先&#xff0c…...

Python中元组(tuple)内置的数据类型

在Python中&#xff0c;元组&#xff08;tuple&#xff09;是一种内置的数据类型&#xff0c;用于存储不可变的有序元素集合。元组在很多方面与列表&#xff08;list&#xff09;相似&#xff0c;但它们之间存在一些关键的区别。以下是关于Python元组的详细解释&#xff1a; 定…...

chrome缓存机制以及验证缓存机制

一、Chrome 缓存机制 浏览器缓存机制旨在提高网页加载速度、减少服务器负载和节约带宽。Chrome 的缓存主要包括以下几种类型&#xff1a; 1. 强缓存 (Strong Cache) 无需向服务器发送请求即可使用缓存的资源。由 HTTP 响应头控制&#xff0c;包括&#xff1a; Expires&…...

医药进出口交易|基于SSM+vue的医药进出口交易系统的设计与实现(源码+数据库+文档)

医药进出口交易系统 目录 基于SSM&#xff0b;vue的医药进出口交易系统的设计与实现 一、前言 二、系统设计 三、系统功能设计 5.1系统登录 5.2管理员功能模块 5.3仓储部门功能模块 5.4业务部门功能模块 5.5供应部门功能模块 5.6财务部功能模块 5.7客户功能模块 …...

爱快 IK-Q6000 WiFi6无线路由器 简单开箱评测和拆解

爱快&#xff08;iKuai&#xff09; IK-Q6000 WiFi6无线路由器 简单开箱评测和拆解 因为用的爱快软路由&#xff0c;所以就想着将AP全换成爱快的&#xff0c;方便管理&#xff0c;目前买了多款爱快的无线路由器当AP&#xff08;IK-Q6000、IK-W35、IK-Q3600&#xff09;&#x…...

时间敏感网络中全面分析与调度的模型驱动方法

论文&#xff1a;A Model-Driven Approach for the Comprehensive Analysis and Scheduling in Time-Sensitive Networks》 背景与动机 TSN 的发展与应用领域&#xff1a;自 2012 年起&#xff0c;IEEE 802.1 TSN 任务组致力于开发通信标准&#xff0c;增强 IEEE 802 网络&…...

统计颜色Count Color(POJ2777)题解

有一个长度为L厘米板&#xff0c;L是一个正整数&#xff0c;所以我们可以把它均匀地划分成L个部分&#xff0c;分别从左到右编号为1&#xff0c;2……L&#xff0c;每一个部分长度都为1厘米。现在我们必须给每个部分涂色&#xff0c;一个部分一种颜色&#xff0c;要求完成以下两…...

MySQL数据的增删改查(一)

目录 新增&#xff08;create&#xff09; 插入单条记录 插入多条记录 查询&#xff08;retrieve&#xff09; 查询所有列 查询特定列 查询字段为表达式 别名 去重 排序 按单列排序 按多列排序 使用表达式或别名排序 排序NULL值 条件查询 比较运算符 逻辑运算…...

国产文本编辑器EverEdit - 如何给小众语言开发大纲分析脚本

1 开发参考&#xff1a;小众语言如何开发大纲分析脚本 1.1 应用场景 在使用IDE进行代码开发时&#xff0c;代码中的变量、结构体、函数等&#xff0c;在大纲视图中都会显示出来&#xff0c;用户可以快速的了解当前文档的结构&#xff0c;以及快速跳转到函数、变量的声明位置。…...

【数据结构】线性数据结构——数组

1. 定义 数组是一种线性数据结构&#xff0c;由一组相同类型的元素组成&#xff0c;这些元素使用连续的内存空间存储。数组通过索引&#xff08;下标&#xff09;访问&#xff0c;每个元素的索引是固定的&#xff0c;从零开始递增。 2. 特点 顺序存储&#xff1a; 元素在内存…...

QT---------GUI程序设计基础

代码UI化设计&#xff08;QT&#xff09; 实例功能概述 假设我们要创建一个简单的计算器应用程序。该应用程序具有以下功能&#xff1a; 包含数字按钮&#xff08;0-9&#xff09;、操作符按钮&#xff08;、-、*、/&#xff09;、等于按钮&#xff08;&#xff09;和清除按…...

2、Bert论文笔记

Bert论文 1、解决的问题2、预训练微调2.1预训练微调概念2.2深度双向2.3基于特征和微调&#xff08;预训练下游策略&#xff09; 3、模型架构4、输入/输出1.输入&#xff1a;2.输出&#xff1a;3.Learned Embeddings(学习嵌入)1. **Token Embedding**2. **Position Embedding**3…...

Linux之ARM(MX6U)裸机篇----7.蜂鸣器实验

一&#xff0c;蜂鸣器模块 封装步骤&#xff1a; ①初始化SNVS_TAMPER这IO复用为GPIO ②设置SNVS_TAMPPER这个IO的电气属性 ③初始化GPIO ④控制GPIO输出高低电平 bsp_beep.c: #include "bsp_beep.h" #include "cc.h"/* BEEP初始化 */ void beep_init…...

Zabbix 监控平台 添加监控目标主机

Zabbix监控平台是一个企业级开源解决方案&#xff0c;用于分布式系统监视和网络监视。它由Zabbix Server和可选组件Zabbix Agent组成&#xff0c;通过C/S模式&#xff08;客户端-服务器模型&#xff09;采集数据&#xff0c;并通过B/S模式&#xff08;浏览器-服务器模型&#x…...

SpringCloud整合skywalking实现链路追踪和日志采集

1.部署skywalking https://blog.csdn.net/qq_40942490/article/details/144701194 2.添加依赖 <!-- 日志采集 --><dependency><groupId>org.apache.skywalking</groupId><artifactId>apm-toolkit-logback-1.x</artifactId><version&g…...

html文件通过script标签引入外部js文件,但没正确加载的原因

移动端H5应用&#xff0c;html文件通过script标签引入外部js文件&#xff0c;但没正确加载&#xff0c;在移动设备上难以排查。通过PC浏览器打开&#xff0c;发现js被阻止了&#xff1a;blocked:mixed-content。 原因在于&#xff1a; “blocked:mixed - content” 是浏览器的…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型

CVPR 2025 | MIMO&#xff1a;支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题&#xff1a;MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者&#xff1a;Yanyuan Chen, Dexuan Xu, Yu Hu…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中&#xff0c;车辆不再仅仅是传统的交通工具&#xff0c;而是逐步演变为高度智能的移动终端。这一转变的核心支撑&#xff0c;来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒&#xff08;T-Box&#xff09;方案&#xff1a;NXP S32K146 与…...