百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

一坨一坨 if/else 参数校验,被 SpringBoot 参数校验组件整干净了

itomcoil 2025-07-06 12:57 2 浏览

来源:
https://mp.weixin.qq.com/s/ZVOiT-_C3f-g7aj3760Q-g

数据的校验的重要性就不用说了,即使在前端对数据进行校验的情况下,我们还是要对传入后端的数据再进行一遍校验,避免用户绕过浏览器直接通过一些 HTTP 工具直接向后端请求一些违法数据。

最普通的做法就像下面这样。我们通过 if/else 语句对请求的每一个参数一一校验。

这样的代码,小伙伴们在日常开发中一定不少见,很多开源项目都是这样对请求入参做校验的。

但是,不太建议这样来写,这样的代码明显违背了 单一职责原则。大量的非业务代码混杂在业务代码中,非常难以维护,还会导致业务层代码冗杂!

实际上,我们是可以通过一些简单的手段对上面的代码进行改进的!这也是本文主要要介绍的内容!

废话不多说!下面我会结合自己在项目中的实际使用经验,通过实例程序演示如何在 SpringBoot 程序中优雅地的进行参数验证(普通的 Java 程序同样适用)。

不了解的朋友一定要好好看一下,学完马上就可以实践到项目上去。

并且,本文示例项目使用的是目前最新的 Spring Boot 版本 2.4.5!(截止到 2021-04-21)

示例项目源代码地址:https://github.com/CodingDocs/springboot-guide/tree/master/source-code/bean-validation-demo

添加相关依赖

如果开发普通 Java 程序的的话,你需要可能需要像下面这样依赖:

不过,相信大家都是使用的 Spring Boot 框架来做开发。

基于 Spring Boot 的话,就比较简单了,只需要给项目添加上 spring-boot-starter-web 依赖就够了,它的子依赖包含了我们所需要的东西。另外,我们的示例项目中还使用到了 Lombok。

但是!!!Spring Boot 2.3 1 之后,spring-boot-starter-validation 已经不包括在了 spring-boot-starter-web中,需要我们手动加上!


验证 Controller 的输入

验证请求体

验证请求体即使验证被 @RequestBody 注解标记的方法参数。

PersonController

我们在需要验证的参数上加上了@Valid注解,如果验证失败,它将抛出MethodArgumentNotValidException。默认情况下,Spring 会将此异常转换为 HTTP Status 400(错误请求)。

PersonRequest

我们使用校验注解对请求的参数进行校验!

正则表达式说明:

  • ^string : 匹配以 string 开头的字符串
  • string$ :匹配以 string 结尾的字符串
  • ^string$ :精确匹配 string 字符串
  • (^Man$|^Woman$|^UGM$) : 值只能在 Man,Woman,UGM 这三个值中选择

GlobalExceptionHandler

自定义异常处理器可以帮助我们捕获异常,并进行一些简单的处理。如果对于下面的处理异常的代码不太理解的话,可以查看这篇文章 《SpringBoot 处理异常的几种常见姿势》。

通过测试验证

下面我通过 MockMvc 模拟请求 Controller 的方式来验证是否生效。当然了,你也可以通过 Postman 这种工具来验证。

使用 Postman 验证

验证请求参数

验证请求参数(Path Variables 和 Request Parameters)即是验证被 @PathVariable 以及 @RequestParam 标记的方法参数。

PersonController

一定一定不要忘记在类上加上 Validated 注解了,这个参数可以告诉 Spring 去校验方法参数。

ExceptionHandler

通过测试验证

使用 Postman 验证

验证 Service 中的方法

我们还可以验证任何 Spring Bean 的输入,而不仅仅是 Controller 级别的输入。通过使用@Validated@Valid注释的组合即可实现这一需求!

一般情况下,我们在项目中也更倾向于使用这种方案。

一定一定不要忘记在类上加上 Validated 注解了,这个参数可以告诉 Spring 去校验方法参数。

通过测试验证:

输出结果如下:

name 不能为空
sex 值不在可选范围

Validator 编程方式手动进行参数验证

某些场景下可能会需要我们手动校验并获得校验结果。

我们通过 Validator 工厂类获得的 Validator 示例。另外,如果是在 Spring Bean 中的话,还可以通过@Autowired 直接注入的方式。

@Autowired
Validator validate

具体使用情况如下:

输出结果如下:

sex 值不在可选范围
name 不能为空

自定以 Validator(实用)

如果自带的校验注解无法满足你的需求的话,你还可以自定义实现注解。

案例一:校验特定字段的值是否在可选范围

比如我们现在多了这样一个需求:PersonRequest 类多了一个 Region 字段,Region 字段只能是ChinaChina-TaiwanChina-HongKong这三个中的一个。

第一步,你需要创建一个注解 Region

第二步,你需要实现 ConstraintValidator接口,并重写isValid 方法。

现在你就可以使用这个注解:

@Region
private String region;

通过测试验证

使用 Postman 验证

案例二:校验电话号码

校验我们的电话号码是否合法,这个可以通过正则表达式来做,相关的正则表达式都可以在网上搜到,你甚至可以搜索到针对特定运营商电话号码段的正则表达式。

PhoneNumber.java

PhoneNumberValidator.java

搞定,我们现在就可以使用这个注解了。

通过测试验证

使用验证组

验证组我们基本是不会用到的,也不太建议在项目中使用,理解起来比较麻烦,写起来也比较麻烦。简单了解即可!

当我们对对象操作的不同方法有不同的验证规则的时候才会用到验证组。

我写一个简单的例子,你们就能看明白了!

1.先创建两个接口,代表不同的验证组

public interface AddPersonGroup {
}
public interface DeletePersonGroup {
}

2.使用验证组

通过测试验证:

验证组使用下来的体验就是有点反模式的感觉,让代码的可维护性变差了!尽量不要使用!

常用校验注解总结

JSR303 定义了 Bean Validation(校验)的标准 validation-api,并没有提供实现。Hibernate Validation是对这个规范/规范的实现 hibernate-validator,并且增加了 @Email@Length@Range 等注解。Spring Validation 底层依赖的就是Hibernate Validation

JSR 提供的校验注解:

  • @Null 被注释的元素必须为 null
  • @NotNull 被注释的元素必须不为 null
  • @AssertTrue 被注释的元素必须为 true
  • @AssertFalse 被注释的元素必须为 false
  • @Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
  • @Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
  • @DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
  • @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
  • @Size(max=, min=) 被注释的元素的大小必须在指定的范围内
  • @Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
  • @Past 被注释的元素必须是一个过去的日期
  • @Future 被注释的元素必须是一个将来的日期
  • @Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式

Hibernate Validator 提供的校验注解

  • @NotBlank(message =) 验证字符串非 null,且长度必须大于 0
  • @Email 被注释的元素必须是电子邮箱地址
  • @Length(min=,max=) 被注释的字符串的大小必须在指定的范围内
  • @NotEmpty 被注释的字符串的必须非空
  • @Range(min=,max=,message=) 被注释的元素必须在合适的范围内

拓展

经常有小伙伴问到:“@NotNull@Column(nullable = false) 两者有什么区别?”

我这里简单回答一下:

  • @NotNull是 JSR 303 Bean 验证批注,它与数据库约束本身无关。
  • @Column(nullable = false) : 是 JPA 声明列为非空的方法。

总结来说就是即前者用于验证,而后者则用于指示数据库创建表的时候对表的约束。

相关推荐

zabbix企业微信告警(zabbix5.0企业微信告警详细)

zabbix企业微信告警的前提是用户有企业微信且创建了一个能够发送消息的应用,具体怎么创建可以协同用户侧企业微信的管理员。第一步:企业微信准备我们需要的内容包括企业ID,应用的AgentId和应用的S...

基于centos7部署saltstack服务器管理自动化运维平台

概述SaltStack是一个服务器基础架构集中化管理平台,具备配置管理、远程执行、监控等功能,基于Python语言实现,结合轻量级消息队列(ZeroMQ)与Python第三方模块(Pyzmq、PyCr...

功能实用,效率提升,Python开发的自动化运维工具

想要高效的完成日常运维工作,不论是代码部署、应用管理还是资产信息录入,都需要一个自动化运维平台。今天我们分享一个开源项目,它可以帮助运维人员完成日常工作,提高效率,降低成本,它就是:OpsManage...

centos定时任务之python脚本(centos7执行python脚本)

一、crontab的安装默认情况下,CentOS7中已经安装有crontab,如果没有安装,可以通过yum进行安装。yuminstallcrontabs二、crontab的定时语法说明*代表取...

Fedora 41 终于要和 Python 2.7 说再见了

红帽工程师MiroHroncok提交了一份变更提案,建议在Fedora41中退役Python2.7,并放弃仍然依赖Python2的软件包。Python2已于2020年1...

软件测试|使用docker搞定 Python环境搭建

前言当我们在公司的电脑上搭建了一套我们需要的Python环境,比如我们的版本是3.8的Python,那我可能有一天换了一台电脑之后,我整套环境就需要全部重新搭建,不只是Python,我们一系列的第三方...

环境配置篇:Centos如何安装Python解释器

有小伙伴时常会使用Python进行编程,那么如何配置centos中的Python环境呢?1)先安装依赖yuminstallgccgcc-c++sqlite-devel在root用户下操作:1...

(三)Centos7.6安装MySql(centos8.3安装docker)

借鉴文章:centos7+django+python3+mysql+阿里云部署项目全流程。这里我只借鉴安装MySql这一部分。链接:https://blog.csdn.net/a394268045/a...

Centos7.9 如何安装最新版本的Docker

在CentOS7.9系统中安装最新版本的Docker,需遵循以下步骤,并注意依赖项的兼容性问题:1.卸载旧版本Docker(如已安装)若系统中存在旧版Docker,需先卸载以避免冲突:sudoy...

Linux 磁盘空间不够用?5 招快速清理文件,释放 10GB 空间不是梦!

刚收到服务器警告:磁盘空间不足90%!装软件提示Nospaceleftondevice!连日志都写不进去,系统卡到崩溃?别慌!今天教你5个超实用的磁盘清理大招,从临时文件到无用软件一键搞定...

Playwright软件测试框架学习笔记(playwright 官网)

本文为霍格沃兹测试开发学社学员学习笔记,人工智能测试开发进阶学习文末加群。一,Playwright简介Web自动化测试框架。跨平台多语言支持。支持Chromium、Firefox、WebKit...

为SpringDataJpa集成QueryObject模式

1.概览单表查询在业务开发中占比最大,是所有CRUDBoy的入门必备,所有人在JavaBean和SQL之间乐此不疲。而在我看来,该部分是最枯燥、最没有技术含量的“伪技能”。1.1.背景...

金字塔测试原理:写好单元测试的8个小技巧,一文总结

想必金字塔测试原理大家已经很熟悉了,近年来的测试驱动开放在各个公司开始盛行,测试代码先写的倡议被反复提及。鉴于此,许多中大型软件公司对单元测试的要求也逐渐提高。那么,编写单元测试有哪些小技巧可以借鉴和...

测试工程师通常用哪个单元测试库来测试Java程序?

测试工程师在测试Java程序时通常使用各种不同的单元测试库,具体选择取决于项目的需求和团队的偏好。我们先来看一些常用的Java单元测试库,以及它们的一些特点:  1.JUnit:  ·描述:JUn...

JAVA程序员自救之路——SpringAI评估

背景我们用SpringAI做了大模型的调用,RAG的实现。但是我们做的东西是否能满足我们业务的要求呢。比如我们问了一个复杂的问题,大模型能否快速准确的回答出来?是否会出现幻觉?这就需要我们构建一个完善...