化繁为简,使用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

验证是否符合正则表达式规则

@Email验证邮箱
@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;
}

请求参数

 响应结果

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python学习笔记_基础篇(八)_正则表达式

1. 正则表达式基础 1.1. 简单介绍 正则表达式并不是Python的一部分。正则表达式是用于处理字符串的强大工具&#xff0c;拥有自己独特的语法以及一个独立的处理引擎&#xff0c;效率上可能不如str自带的方法&#xff0c;但功能十分强大。得益于这一点&#xff0c;在提供了正则…

机器学习深度学习——自注意力和位置编码(数学推导+代码实现)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——注意力分数&#xff08;详细数学推导代码实现&#xff09; &#x1f4da;订阅专栏&#xff1a;机器学习…

传输控制协议TCP

目录 TCP报文格式 TCP的特点 TCP原理: 1.确认应答机制 2.超时重传机制 3.连接管理机制 建立连接 ​编辑关闭连接 4.滑动窗口机制 ​5.流量控制 6.拥塞控制 7.延迟应答 8.捎带应答 TCP报文格式 1.源端口号:发送端的哪一个端口发出的 2.目的端口号:接收端的哪一个端…

如何使用Python编写小游戏?

大家好&#xff0c;我是沐尘而生&#xff0c;如果你是一个热爱编程的小伙伴&#xff0c;又想尝试游戏开发&#xff0c;那么这篇文章一定能满足你的好奇心。不废话&#xff0c;让我们马上进入Python游戏开发的精彩世界吧&#xff01; Python游戏开发的魅力 编写小游戏不仅仅是锻…

Markdown编辑器 Mac版Typora功能介绍

Typora mac是一款跨平台的Markdown编辑器&#xff0c;支持Windows、MacOS和Linux操作系统。它具有实时预览功能&#xff0c;能够自动将Markdown文本转换为漂亮的排版效果&#xff0c;让用户专注于写作内容而不必关心格式调整。 Typora Mac版除了支持常见的Markdown语法外&#…

机器学习需要面对的两大问题:泛化性和可信性

随着人工智能的迅速发展&#xff0c;机器学习成为了炙手可热的领域&#xff0c;它让计算机能够从数据中学习并做出智能决策。然而&#xff0c;机器学习在取得巨大成功的同时&#xff0c;也面临着两个重大挑战&#xff1a;泛化性和可信性。这两大问题的解决关系到机器学习应用的…

【设计模式——学习笔记】23种设计模式——解释器模式Interpreter(原理讲解+应用场景介绍+案例介绍+Java代码实现)

案例引入 通过解释器模式来实现四则运算&#xff0c;如计算ab-c的值&#xff0c;具体要求 先输入表达式的形式&#xff0c;比如abc-de&#xff0c;要求表达式的字母不能重复在分别输入a,b,c,d,e的值最后求出结果 传统方案 编写一个方法&#xff0c;接收表达式的形式&#xf…

长胜证券:宁德时代发布神行超充电池 信创利好政策陆续出台

昨日&#xff0c;两市股指早盘震动回升&#xff0c;午后再度回落&#xff0c;尾盘加快下行。截至收盘&#xff0c;沪指跌0.82%报3150.13点&#xff0c;深成指跌0.94%报10579.56点&#xff0c;创业板指跌0.73%报2132.97点&#xff0c;科创50指数跌1.71%&#xff1b;两市算计成交…

最新Ubuntu LVGL SDL模拟器安装

前言 本文主要说明Ubuntu 23.4安装LVGL 9.0以及基于SDL的模拟环境。 代码下载 访问lv_port_pc_eclipse可以看到相信信息&#xff0c;官方已经打包好了整个代码环境。 安装CMAKE。 sudo apt install cmake安装SDL。 sudo apt-get update && sudo apt-get install …

云原生 envoy xDS 动态配置 java控制平面开发 支持restful grpc实现 EDS 动态endpoint配置

envoy xDS 动态配置 java控制平面开发 支持restful grpc 动态endpoint配置 大纲 基础概念Envoy 动态配置API配置方式动静结合的配置方式纯动态配置方式实战 基础概念 Envoy 的强大功能之一是支持动态配置&#xff0c;当使用动态配置时&#xff0c;我们不需要重新启动 Envoy…

安科瑞变电所运维平台在电力系统中应用分析

摘要&#xff1a;现代居民生活、工作对电力资源的需求量相对较多&#xff0c;给我国的电力产业带来了良好的发展机遇与挑战。探索电力系统基本构成&#xff0c; 将变电运维安全管理以及相应的设备维护工作系统性开展&#xff0c;能够根据项目实践工作要求&#xff0c;将满足要求…

hbase 报错 Master passed us a different hostname to use; was=

原因 wsl2的 /etc/hosts 配置的不兼容,我这里是ubuntu22 命令行输入hostname 看输出什么,比如输出 aaa 那么替换/etc/hosts 127.0.0.1 aaa

Mysql之explain详解

1. explain作用 使用explain可以展示出sql语句的执行计划&#xff0c;再根据sql的执行计划去判断这条sql有哪些点可以进行优化&#xff0c;从而让sql的效率达到最大化。 2. 执行计划各列含义 &#xff08;1&#xff09;id&#xff1a;id列是select的序列号&#xff0c;这个…

【BASH】回顾与知识点梳理(三十二)

【BASH】回顾与知识点梳理 三十二 三十二. SELinux 初探32.1 什么是 SELinux当初设计的目标&#xff1a;避免资源的误用传统的文件权限与账号关系&#xff1a;自主式访问控制, DAC以政策规则订定特定进程读取特定文件&#xff1a;委任式访问控制, MAC 32.2 SELinux 的运作模式安…

nvm管理node版本

nvm是什么&#xff1f; NVM全名叫做 nodejs version manage,即Node的版本管理工具。 使用NVM&#xff0c;可以通过命令很方便地在多个NodeJS版本之间进行切换。 nvm的下载与安装 下载地址&#xff1a;Releases coreybutler/nvm-windows (github.com) windows系统下载nvm-setup…

【自动化测试】接口自动化01

文章目录 一、熟悉若requests库以及底层方法的调用逻辑二、接口自动化以及正则和Jsonpath提取器的应用6. 高频面试题&#xff1a;9. 示例&#xff1a;接口关联13. 文件上传示例14. cookie关联的接口 努力经营当下 直至未来明朗 一、熟悉若requests库以及底层方法的调用逻辑 接…

RTT(RT-Thread)ADC设备(RTT保姆级介绍)

目录 ADC设备 前言 ADC相关参数说明 访问ADC设备 配置ADC设备 ADC实例 硬件设计 软件设计 ADC设备 前言 ADC(Analog-to-Digital Converter) 指模数转换器。是指将连续变化的模拟信号转换为离散的数字信号的器件。 对于ADC的详细介绍和在STM32中的裸机应用可参考以下…

在CentOS 7上使用kubeadm部署Kubernetes集群

如有错误&#xff0c;敬请谅解&#xff01; 此文章仅为本人学习笔记&#xff0c;仅供参考&#xff0c;如有冒犯&#xff0c;请联系作者删除&#xff01;&#xff01; 前言&#xff1a; Kubernetes是一个开源的容器编排平台&#xff0c;用于管理和自动化部署容器化的应用程序。…

软文发布问题解答:高效宣传与推广指南

以下是一秒推小编针对软文发布的20个常见问题及回答&#xff1a; 1. 什么是软文&#xff1f; 答&#xff1a;软文是指用文学手法、写作技巧撰写的宣传文章&#xff0c;以实现对特定受众的陈述、说明和推销。 2. 发布软文的目的是什么&#xff1f; 答&#xff1a;发布软文的目…

出现ffmpeg.dll丢失的修复方法分享,教你快速修复ffmpeg.dll文件

当你使用或尝试运行与FFmpeg相关的应用程序时&#xff0c;可能会遇到一个常见的问题&#xff0c;ffmpeg.dll文件丢失。这个动态链接库文件对于正常运行FFmpeg应用程序至关重要。在本文中&#xff0c;我们将详细探讨为什么会出现ffmpeg.dll丢失的情况&#xff0c;并提供一些修复…