化繁为简,使用Hibernate Validator实现参数校验
前言
在之前的悦享校园的开发中使用了SSM框架,由于当时并没有使用参数参数校验工具,方法的入参判断使用了大量的if else语句,代码十分臃肿,因此最近在重构代码时,将框架改为SpringBoot后,引入了Hibernate Validator校验工具对参数进行优雅校验(SSM同样可用)。本文将通过实例来演示如何使用该框架。
环境配置
JDK 1.8
Spring Boot 2.7.12
导入依赖
<!--SpringBoot 2.3开始,校验包单独组件,需要手动引入 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>
基础校验
在正式开始之前,需要先对以下的内容作以了解,方便后续的学习。
校验注解
Hibernate Validator,提供了丰富的校验注解来供我们使用,这里列举一些比较常用的:
注解 | 解释 |
@Null | 验证对象是否为空 |
@NotNull | 验证对象是否为非空 |
@NotBlank | 用于String对象,验证字符串不为空且trim()后长度大于0 |
@Length | 验证对象的长度是否符合 |
@Size | 验证对象长度是否在给定的范围之内(用于Array,Collection,Map,String) |
@Min | 入参对象的值不能小于该值(用于Number和String) |
@Max | 入参对象的值不能大于该值(用于Number和String) |
@Digits | 验证number和string的构成是否合法 |
@Past | 验证date和calendar对象是否在当前时间之前 |
@Future | 验证date和calendar对象是否在当前时间之后 |
@Pattern | 验证是否符合正则表达式规则 |
验证邮箱 | |
@Positive | 验证输入的对象是否非负数 |
@Range | 验证输入的对象的值是否在指定范围内 |
参数绑定
@PathVariable
该注解用于接收具有Restful风格的参数,如/api/v1/1001,最终userId的值为1001。
如下代码中,使用name属性可以指定GetMapping中的id名称与之对应,从而可以自定义参数名称userId,而不是使用默认名称id
@GetMapping("/v1/{id}")
public void getMsg(@PathVariable(name = "id") Integer userId){}
@RequestParam
该注解用于接收查询参数,如/api/v1/product?user="123",则user的值为123。该注解也可用于接收form-data类型的数据。
当在参数前使用@RequireParam时,当请求该方法时,对应的参数必须存在,否则会引发异常,可使用@RequireParam(required = false)指明该参数非必须,该注解在入参为null时可提供默认值。
@GetMapping("/v1/product")
public void getMsg(@RequestParam String user){}
@RequestBody
该注解用于接收JSON格式的数据,如请求为{"name":123,"age":18},需要有对应的实体类作为映射。
@PostMapping("/v1/user")
public void getMsg(@RequestBody User user){}
@Validated
该注解可以作用于类、方法、参数上,用于开启参数校验。
@Valid
该注解可以作用于方法、参数、字段、构造器上,同样可以用于参数校验。
单参校验
将@Validated注解用于类上,可以不用在每个方法的参数上重复开启校验,使用前面提的基础校验即可对参数作约束。
校验方法
@RestController
@RequestMapping("/v1/hello")
@Slf4j
@Validated
public class HelloController {/*** GetMapping 请求* @param name 用户名称* @param uid 用户uid* @return*/@GetMapping("/{id}")public ResultDataVO getMsg(@RequestParam String name,@Max(value = 10,message = "最大值不能超过10")@PathVariable(name = "id") int uid) {log.info("访问hello下的msg方法。");String result = "Hello,"+name+" id "+uid;return ResultDataVO.success(result);}
}
请求参数 响应结果
由于我们没有给String参数赋值,因此默认为空字符串。但由于在uid上使用了@Max注解,因此当入参为100时便会出现异常,而返回的JSON格式为全局的响应处理,在后续的文章会提到。
对象校验
当我们在使用中,往往会遇到多个参数的情况,由于get请求对参数长度有限制,且参数会拼接在URL中, 因此对于此场景我们一般使用对象的方式来接收参数,而对于我们的参数也将传入也将用JSON格式。
由于使用JSON格式传参,将使用@RequestBody注解,除此之外还要使用@Validated或@Valid注解,关于两者的选择,只需要记住分组校验使用@Validated,否则二者均可。
即使在类上添加了@Validated注解,此处仍然需要以上两个注解之一,否则参数校验将无效。
校验方法
@RestController
@RequestMapping("/v1/hello")
@Slf4j
@Validated
public class HelloController {/*** 对象校验示例* @param user* @return */@PostMapping("/msg")public ResultDataVO(@RequestBody @Valid UserDTO user){return ResultDataVO.success(user.toString());}
}
UserDTO
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDTO {/*** id*/@Min(value = 1,message = "id值不合法")@Positiveprivate Integer id;/*** 昵称*/@NotBlank(message = "用户名不能为空")@Length(min = 4,max=10,message = "用户名必须在4-10个字符之间")private String username;/*** 年龄*/@Range(min = 1,max=120,message = "年龄不在合法范围内")@NotNull(message = "age不能为空")private Integer age;
}
上述代码中,参数为UserDTO对象,其中包含三个待校验的字段,由于未涉及到分组校验,因此校验方法中参数前使用@Valid注解(@Validated注解亦可),注意入参的字段名称需要和UserDTO中的名称一致。
请求参数
响应结果
分组校验
假设有这样的场景,在用户登录和修改密码中,两者分别需要如下参数,登录时需要用户名、密码,而修改时需要密码、新密码,为了方便管理,只使用了一个DTO类来存放上述的字段,此时由于这些参数需要在不同的场景下校验,而加上基础校验的注解会导致所有参数均被校验,面对此问题,我们将使用分组校验来解决。
可以看到如何代码中,均是使用了@Validate注解,且注解中含有一个分组接口,使用该接口可以帮助我们告知程序该对那些参数进行校验。
校验方法
@RestController
@Slf4j
@RequestMapping("/local/auth")
@Validated
public class LocalAuthController {@Autowiredprivate LocalAuthService localAuthService;/*** 用户登录接口* @param localAuthDTO 账号对象* @return*/@PostMapping("/login")LocalAuthVO loginCheck(@RequestBody @Validated(AuthCheckSequence.class) LocalAuthDTO localAuthDTO){return localAuthService.userLoginCheck(localAuthDTO);}/*** 用户修改密码接口* @param localAuthDTO 账号对象* @return*/@PutMapping("/password")ResultDataVO userChangePassword(@RequestBody@Validated(AuthChangeSequence.class)LocalAuthDTO localAuthDTO){return localAuthService.userModifyPassword(localAuthDTO);}
}
分组接口
AuthChangeSequence
/*** 分组校验,用户登录*/public interface AuthCheckSequence {}
AuthCheckSequence
/*** 分组校验,密码修改*/
public interface AuthChangeSequence {}
LocalAuthDTO
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class LocalAuthDTO {/*** 用户名*/@NotBlank(message = "用户名不能为空",groups = AuthCheckSequence.class)@Pattern(regexp = "^[a-zA-Z0-9]{3,8}$", message = "用户名必须由3-8个字母或数字组成",groups = AuthCheckSequence.UsernameCheck.class)private String username;/*** 密码*/@NotBlank(message = "密码不能为空",groups = AuthCheckSequence.class)@Size(min = 6,max = 18, message = "密码长度必须在6到18位之间",groups = AuthCheckSequence.PasswordCheck.class)private String password;/*** 新密码,修改密码时使用*/@NotBlank(message = "新密码不能为空",groups = AuthChangeSequence.class)@Size(min = 6,max = 18, message = "新密码长度必须在6到18位之间",groups = AuthChangeSequence.ChangePassword.class)private String newPassword;
}
请求参数
响应结果
从上图所示请求结果可以看出,使用@Validated注解+分组校验接口后,将只对该参数中标明了对应分组接口的字段进行校验,并不会对全部参数进行校验。
顺序校验
由于用户人数增多,我们将在对用户进行分组,将在LocalAuthDTO中引入新的字段,而我们所期望的是能够按照用户类型,用户名,密码的顺序来校验,而不是像之前对象校验最终显示的结果那样,随机进行校验并返回结果,因此需要使用在分组校验的基础上做一些改进,使其可以按照我们所指定的顺序执行校验,以前面登录为例:
校验方法
@RestController
@Slf4j
@RequestMapping("/local/auth")
@Validated
public class LocalAuthController {@Autowiredprivate LocalAuthService localAuthService;/*** 用户登录接口* @param localAuthDTO 账号对象* @return*/@PostMapping("/login")LocalAuthVO loginCheck(@RequestBody @Validated(AuthCheckSequence.class) LocalAuthDTO localAuthDTO){return localAuthService.userLoginCheck(localAuthDTO);}
}
AuthCheckSequence
通过在该分组接口中新建接口,并使用@GroupSequence注解中参数的顺序来实现校验参数的顺序。如下将标识使用AuthCheckSequence分组的参数将按照用户类型、用户名、密码的顺序进行校验。
@GroupSequence({AuthCheckSequence.UserTypeCheck.class, AuthCheckSequence.UsernameCheck.class, AuthCheckSequence.PasswordCheck.class})
public interface AuthCheckSequence {/*** 用户类型*/interface UserTypeCheck {};/*** 用户名校验*/interface UsernameCheck {};/*** 密码校验*/interface PasswordCheck {};
}
LocalAuthDTO
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class LocalAuthDTO {/*** 用户类型 1.用户 2.商家 3.管理员,目前仅支持用户和商家类型注册*/@NotNull(message = "用户类型不能为空",groups = AuthCheckSequence.UserTypeCheck.class)@Range(min = 1,max = 3,message = "用户类型不合法",groups = AuthCheckSequence.UserTypeCheck.class)private Integer userType;/*** 用户名*/@NotBlank(message = "用户名不能为空",groups = AuthCheckSequence.UsernameCheck.class)@Pattern(regexp = "^[a-zA-Z0-9]{3,8}$", message = "用户名必须由3-8个字母或数字组成",groups = AuthCheckSequence.UsernameCheck.class)private String username;/*** 密码*/@NotBlank(message = "密码不能为空",groups = AuthCheckSequence.PasswordCheck.class)@Size(min = 6,max = 18, message = "密码长度必须在6到18位之间",groups = AuthCheckSequence.PasswordCheck.class)private String password;
}
请求参数
响应结果
相关文章:

化繁为简,使用Hibernate Validator实现参数校验
前言 在之前的悦享校园的开发中使用了SSM框架,由于当时并没有使用参数参数校验工具,方法的入参判断使用了大量的if else语句,代码十分臃肿,因此最近在重构代码时,将框架改为SpringBoot后,引入了Hibernate V…...
【Qt】多线程
线程创建 自定义线程类 #ifndef CUSTOMETHREAD_H #define CUSTOMETHREAD_H#include <QObject> #include <QThread> #include "add.h"class CustomeThread : public QThread {Q_OBJECT public:// Bind the thread kernel function.explicit CustomeThre…...

腾讯云GPU服务器GN7实例NVIDIA T4 GPU卡
腾讯云GPU服务器GN7实例搭载1颗 NVIDIA T4 GPU,8核32G配置,系统盘为100G 高性能云硬盘,自带5M公网带宽,系统镜像可选Linux和Windows,地域可选广州/上海/北京/新加坡/南京/重庆/成都/首尔/中国香港/德国/东京/曼谷/硅谷…...

3. 爬取自己CSDN博客列表(自动方式)(分页查询)(网站反爬虫策略,需要在代码中添加合适的请求头User-Agent,否则response返回空)
文章目录 步骤打开谷歌浏览器输入网址按F12进入调试界面点击网络,清除历史消息按F5刷新页面找到接口(community/home-api/v1/get-business-list)接口解读 撰写代码获取博客列表先明确返回信息格式json字段解读 Apipost测试接口编写python代码…...

利用HTTP代理实现请求路由
嘿,大家好!作为一名专业的爬虫程序员,我知道构建一个高效的分布式爬虫系统是一个相当复杂的任务。在这个过程中,实现请求的路由是非常关键的。今天,我将和大家分享一些关于如何利用HTTP代理实现请求路由的实用技巧&…...

深度学习(36)—— 图神经网络GNN(1)
深度学习(36)—— 图神经网络GNN(1) 这个系列的所有代码我都会放在git上,欢迎造访 文章目录 深度学习(36)—— 图神经网络GNN(1)1. 基础知识2.使用场景3. 图卷积神经网…...

深入理解JVM——垃圾回收与内存分配机制详细讲解
所谓垃圾回收,也就是要回收已经“死了”的对象。 那我们如何判断哪些对象“存活”,哪些已经“死去”呢? 一、判断对象已死 1、引用计数算法 给对象中添加一个引用计数器,每当有一个地方引用它时,计数器就加一&…...

基于SSH框架实现的管理系统(包含java源码+数据库)
资料下载链接 介绍 基于SSH框架的管理系统 简洁版 ; 实现 登录 、 注册 、 增 、 删 、 改 、 查 ; 可继续完善增加前端、校验、其他功能等; 可作为 SSH(Structs Spring Hibernate)项目 开发练习基础模型…...
图像识别代做服务:实现创新应用的新契机
导言: 随着人工智能和图像处理技术的不断进步,图像识别已经成为了许多领域中的关键应用。然而,图像识别技术的开发和应用往往需要庞大的团队和大量的资源。这就是为什么图像识别代做服务正在崭露头角。本文将探讨图像识别代做服务如何成为实现…...

Coreutils工具包,Windows下使用Linux命令
之前总结过两篇有关【如何在Windows系统下使用Linux的常用命令】的文章: GnuWin32,Windows下使用Linux命令 UnxUtils工具包,Windows下使用Linux命令 今天再推荐一个类似的工具包Coreutils 一、简介 GNU core utilities是GNU操作系统基本…...
神经网络基础-神经网络补充概念-13-python中的广播
概念 在 Python 中,广播(Broadcasting)是一种用于在不同形状的数组之间执行二元操作的机制。广播允许你在不显式复制数据的情况下,对不同形状的数组进行运算。这在处理数组的时候非常有用,尤其是在科学计算、数据分析…...

HDFS原理剖析
一、概述 HDFS是Hadoop的分布式文件系统(Hadoop Distributed File System),实现大规模数据可靠的分布式读写。HDFS针对的使用场景是数据读写具有“一次写,多次读”的特征,而数据“写”操作是顺序写,也就是…...

css学习2(利用id与class修改元素)
1、id选择器可以为标有特定id的html元素指定特定的样式。 2、选择器以#开头,后跟某id的属性值。 3、class选择器用于描述一组元素的样式,class可以在多个元素使用。 4、类选择器用.选择。 5、指定特定的元素使用class。 6、元素的多个类用空格分开&…...
wsl2(debian)安装python的不同版本例如3.8
要在Debian上安装 Python 3.8,可以按照以下步骤操作: 1.确保你的 Debian 系统已经更新到最新版本,可以使用以下命令更新: sudo apt update sudo apt upgrade2.安装 Python 3.8 的依赖项,以及构建 Python 时需要的工具…...
Python教程(9)——Python变量类型列表list的用法介绍
列表操作 创建列表访问列表更改列表元素增加列表元素修改列表元素删除列表元素 删除列表 在Python中,列表(list)是一种有序、可变的数据结构,用于存储多个元素。列表可以包含不同类型的元素,包括整数、浮点数、字符串等…...

springboot+VUE智慧公寓管理系统java web酒店民宿房屋住宿报修信息jsp源代码
本项目为前几天收费帮学妹做的一个项目,Java EE JSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。 一、项目描述 springbootVUE智慧公寓管理系统 系统有2权限…...
神经网络基础-神经网络补充概念-36-dropout正则化
概念 Dropout 是一种常用的正则化技术,用于减少深度神经网络中的过拟合问题。它在训练过程中随机地将一部分神经元的输出置为零,从而强制模型在训练过程中学习多个独立的子模型,从而减少神经元之间的依赖关系,提高模型的泛化能力…...
Go语言基础之变量和常量
标识符与关键字 标识符 在编程语言中标识符就是程序员定义的具有特殊意义的词,比如变量名、常量名、函数名等等。 Go语言中标识符由字母数字和_(下划线)组成,并且只能以字母和_开头。 举几个例子:abc, _, _123, a123 关键字 关…...

Spring Boot 项目实现 Spring AOP
【注】实现在SpringBoot项目中,同时给两个类的方法添加AOP前置通知 1、创建一个SpringBoot项目 2、创建两个目标类和方法 package com.tqazy.learn_spring_project.spring_aop;import org.springframework.stereotype.Service;/*** ClassName SpringAopUserServi…...

Baumer工业相机堡盟工业相机如何通过BGAPISDK设置相机的固定帧率(C#)
Baumer工业相机堡盟工业相机如何通过BGAPI SDK设置相机的固定帧率(C#) Baumer工业相机Baumer工业相机的固定帧率功能的技术背景CameraExplorer如何查看相机固定帧率功能在BGAPI SDK里通过函数设置相机固定帧率 Baumer工业相机通过BGAPI SDK设置相机固定帧…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...

HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...

分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...
Vue 模板语句的数据来源
🧩 Vue 模板语句的数据来源:全方位解析 Vue 模板(<template> 部分)中的表达式、指令绑定(如 v-bind, v-on)和插值({{ }})都在一个特定的作用域内求值。这个作用域由当前 组件…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...
ubuntu22.04 安装docker 和docker-compose
首先你要确保没有docker环境或者使用命令删掉docker sudo apt-get remove docker docker-engine docker.io containerd runc安装docker 更新软件环境 sudo apt update sudo apt upgrade下载docker依赖和GPG 密钥 # 依赖 apt-get install ca-certificates curl gnupg lsb-rel…...
13.10 LangGraph多轮对话系统实战:Ollama私有部署+情感识别优化全解析
LangGraph多轮对话系统实战:Ollama私有部署+情感识别优化全解析 LanguageMentor 对话式训练系统架构与实现 关键词:多轮对话系统设计、场景化提示工程、情感识别优化、LangGraph 状态管理、Ollama 私有化部署 1. 对话训练系统技术架构 采用四层架构实现高扩展性的对话训练…...