探索Spring Validation:优雅实现后端数据验证的艺术

在现代Web应用开发中,数据验证是一项至关重要的任务,确保应用程序接收到的用户输入符合预期规范,不仅能够提高系统的健壮性,也能有效防止潜在的安全漏洞。Spring Framework通过其内置的Spring Validation模块,为我们提供了强大的数据验证功能,本文将带你深入了解Spring Validation的实现原理及其最佳实践。

一、Spring Validation简介

Spring Validation是基于Java Bean Validation规范(JSR 303/349 for Java EE 6/7,JSR 380 for Java EE 8)实现的,主要依赖的是Hibernate Validator作为默认的实现引擎。它允许我们在Java Bean的属性上声明验证注解,从而在运行时对这些属性进行条件性验证。

在实际项目我们需要对客户端传递到服务端的参数进行校验,用于判定请求参数的合法性,假如请求参 数不合法则不可以再去执行后续的业务了。那如何校验呢?

一种方式是我们在控制层方法中每次都自己进行参数有效值的判断,不合法可以抛出异常,但是工作量 和代码复杂度会比较高;

第二种方式就是采用市场上主流的 Spring Validation 框架去实现校验,所以 Spring Validation 框架的主要作用是 检查参数的基本有效性。

二、集成与配置

1. 引入依赖

在Maven或Gradle构建项目中,我们需要引入Hibernate Validator的相关依赖,例如在Maven的pom.xml文件中添加:

Xml

1<dependency>
2    <groupId>org.springframework.boot</groupId>
3    <artifactId>spring-boot-starter-validation</artifactId>
4</dependency>

2.使用注解

Spring Validation提供了丰富的预定义注解,如@NotNull,@NotEmpty,@NotBlank,@Size,@Range等,可以直接应用于实体类的字段上:

@NotNull注解

作用:用于验证对象是否为 null

用法: @NotNull 注解用于对象类型上

示例

@NotNull(message = "用户名不能为null")
private String username;

@NotEmpty注解

作用:用于验证字符串是否为空,并且会检查是否为 null 值(为null值时报错)

用法:用于字符串类型上

示例

@NotEmpty(message = "用户名不能为空")
private String username;

@NotBlank注解

作用:不允许为空白,即不允许是“仅由空格、TAB等空白值组成的字符串”,也不允许为空字符串,也不允许为空值null

用法:用于字符串类型上

示例

@NotBlank(message = "用户名不能为空白串")
private String username;

@Size注解

作用:可以指定最小值和最大值限制字符串的长度串,也不允许为空值null

用法:用于字符串类型参数

示例

@Size(min = 6, max = 20, message = "用户名长度必须在6到20之间")
private String username;

@Range 注解

作用:用于验证数字类型字段的取值范围,通过配置min和max属性来限制数值类型参数的值区间 包括最小值和最大值

用法:用于数值类型参数

示例

@Range(min = 1, max = 10, message = "年龄必须在1-10岁之间")
private int age;@Range(min = 0.1, max = 1.0, message = "成绩必须在0.1到1.0之间")
private double score;

三、验证流程与控制器处理

  1. 控制器层处理: 在Spring MVC的Controller中,我们可以使用@Valid注解来触发模型对象的验证,紧接着一个BindingResult对象用于捕获验证结果:

    1@PostMapping("/users")
    2public ResponseEntity<?> createUser(@Valid @RequestBody User user, BindingResult bindingResult) {
    3    if (bindingResult.hasErrors()) {
    4        // 处理验证错误
    5        return handleValidationError(bindingResult);
    6    } else {
    7        // 验证通过,继续处理业务逻辑
    8        userService.createUser(user);
    9        return ResponseEntity.ok().build();
    10    }
    11}
  2. 自定义注解与验证器: 对于更复杂或特定的验证需求,Spring Validation允许我们自定义注解并编写相应的验证器实现javax.validation.ConstraintValidator接口:

    1@Target({ElementType.FIELD})
    2@Retention(RetentionPolicy.RUNTIME)
    3@Constraint(validatedBy = EncryptedIdValidator.class)
    4public @interface EncryptedId {
    5    String message() default "加密ID格式不正确";
    6    Class<?>[] groups() default {};
    7    Class<? extends Payload>[] payload() default {};
    8}
    9
    10public class EncryptedIdValidator implements ConstraintValidator<EncryptedId, String> {
    11    // 实现自定义的验证逻辑
    12    ...
    13}

 四、快速入门

1. 在处理请求的方法的参数列表中,在POJO类型的参数上添加 @Validated 注解,表示需要通过 Spring Validation框架检查此参数,例如UserController中注册功能:

@ApiOperation(value = "注册功能")
@PostMapping("reg")
public JsonResult reg(@RequestBody @Validated UserRegDTO userRegDTO){}

2. 在此POJO类中的属性上,添加对应的检查注解,以配置检查规则, 例如,添加 @NotNull 注解,就表示“不允许为 null ”的规则!

在 UserRegDTO 类

@Data
public class UserRegDTO {@NotNull@ApiModelProperty(value = "用户名", required = true, example = "赵丽颖")private String username;@ApiModelProperty(value = "密码", required = true, example = "123456")private String password;@ApiModelProperty(value = "昵称", required = true, example = "萤火虫")private String nickname;
}

3. 重启工程,在Knife4j中测试,当提交请求时,如果没有提交username参数,服务器端将响应 400 错误。

同时在终端也会出现异常

五、异常处理与响应

1.处理异常

为了给前端提供友好的反馈,通常我们会统一处理验证失败时的异常,将其转换成HTTP状态码和错误信息:

第1步:全局异常处理器 GlobalExceptionHandler 中定义处理异常方法

@ExceptionHandler
public JsonResult handleBindException(MethodArgumentNotValidException ex){return new JsonResult(3002, "请求参数错误");
}

第2步:重启工程,在Knife4j中测试

2.明确提示信息

当提交的 username 的值为 null 时,可以发现异常已被处理!

但是,处理结果并不合适,因为,客户端得到此结果后,仍无法明确出现了什么错误!

所有的检查注解都可以配置 message 参数,用于对错误进行描述。

第1步: @NotNull 注解中添加 message 参数

@NotNull(message = "必须提交用户名")
private String username;

第2步:自定义枚举状态码 StatusCode

VALIDATE_ERROR(3002, "参数校验失败")

第3步:异常方法中获取提示信息 message

在处理异常时,需要调用 MethodArgumentNotValidException 对象的

getFieldError().getDefaultMessage() 获取以上配置的描述文本

@ExceptionHandler
public JsonResult handleBindException(MethodArgumentNotValidException ex){/*ex.getFieldError().getDefaultMessage():获取 @NotNull(message="xxx") 中
message的消息*/String message = ex.getFieldError().getDefaultMessage();return new JsonResult(StatusCode.VALIDATE_ERROR, message);
}

第3步:重启工程,在Knife4j中测试

六、非POJO类参数校验

在 Spring Validation 中,除了对 POJO(Plain Old Java Object)进行校验的功能外,还支持对非 POJO 进行校验,比如 String、Integer、Double 等类型的参数。

1.使用流程

  • 在当前方法所在的类上添加 @Validated 注解
  • 在参数上添加对应的检查注解

2.使用示例

对于微博详情页的 id 参数进行范围校验,范围只能在1-10之间

第1步:在类 WeiboController 中添加 @Validated 注解

@Validated
public class WeiboController {}

第2步:在控制器方法参数 id 上添加对应的检查注解

public JsonResult selectById(@Range(min = 1, max=10, message = "请提交合法的ID
值!") int id)

第3步:重启工程,在Knife4j或者浏览器中测试

七、总结

Spring Validation的使用极大地简化了Java应用程序中的数据验证过程,通过标准化的注解机制实现了业务逻辑和数据验证的分离,提高了代码的可读性和可维护性。同时,它也具有良好的扩展性,让我们能够轻松应对各类复杂的验证场景,确保了系统数据质量的同时提升了用户体验。

通过深入理解和灵活运用Spring Validation,开发者能够在后端建立起坚固的数据过滤防线,为构建安全可靠的应用程序打下坚实基础。而随着RESTful API设计的流行,Spring Validation更是成为了保障API契约得到严格遵循的重要工具之一。

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

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

相关文章

C++初阶之类与对象(上)详细解析

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言进阶 数据结构初阶 Linux C初阶 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力&#xff0c;一起奔赴大厂 目录 一.前言 二.类的定义和使用 2.1类的引入 2.2类的定义和访问限定…

MacOS - M1芯片 Mac 在“恢复”模式中启用系统扩展教程

部分软件需要开启系统扩展才能正常使用&#xff0c;但是默然M1芯片的Mac不能直接打开系统扩展&#xff0c;如下两图。 若要启用系统扩展&#xff0c;您需要在“恢复”环境中修改安全性设置。 若要执行此操作&#xff0c;请将系统关机&#xff0c;然后按住触控ID或电源按钮以开…

3D裸眼技术行业研究:2026年市场投资规模为10.78亿元

3D裸眼技术大多处于研发阶段&#xff0c;它的研发分两个方向&#xff0c;一是硬件设备的研发&#xff0c;二为显示内容的处理研发。第二种已经开始小范围的商业运用。大众消费者接触的不多。从技术上来看&#xff0c;3D裸眼可分为光屏障式(Barrier)、柱状透镜(Lenticular Lens)…

简单说网络:TCP+UDP

TCP和UPD: (1)都工作在传输层 (2)目的都是在程序之中传输数据 (3)数据可以是文本、视频或者图片(对TCP和UDP来说都是一堆二进制数没有太大区别) 一、区别:一个基于连接一个基于非连接 将人与人之间的通信比喻为进程和进程之前的通信:基本上有两种方式(1)写信;(2)打电话;这…

【Qt】Android上运行keeps stopping, Desktop上正常

文章目录 问题 & 背景背景问题 解决方案One More ThingTake Away 问题 & 背景 背景 在文章【Qt】最详细教程&#xff0c;如何从零配置Qt Android安卓环境中&#xff0c;我们在Qt中配置了安卓开发环境&#xff0c;并且能够正常运行。 但笔者在成功配置并完成上述文章…

C#中使用OpenCvSharp4绘制直线、矩形、圆、文本

C#中使用OpenCvSharp4绘制直线、矩形、圆、文本 继之前的Python中使用Opencv-python库绘制直线、矩形、圆、文本和VC中使用OpenCV绘制直线、矩形、圆和文字&#xff0c;将之前的Python和C示例代码翻译成C#语言&#xff0c;很简单&#xff0c;还是借用OpenCvSharp4库中的Line、…

HarmonyOS SDK 助力新浪新闻打造精致易用的新闻应用

原生智能是HarmonyOS NEXT的核心亮点之一&#xff0c;依托HarmonyOS SDK丰富全面的开放能力&#xff0c;开发者只需通过几行代码&#xff0c;即可快速实现AI功能。新浪新闻作为鸿蒙原生应用开发的先行者之一&#xff0c;从有声资讯入手&#xff0c;基于Speech Kit朗读控件上线听…

cocos creator 3.x 预制体无法显示

双击预制体&#xff0c;进入详情页&#xff0c;没有显示资源 Bomb 是个预制体&#xff0c;但是当我双击进来什么都没有了&#xff0c;无法对预制体进行可视化编辑 目前我只试出来一个解决方法&#xff1a; 把预制体拖进Canvas文件中&#xff0c;这样就能展示到屏幕上&#xff…

在angular12中proxy.conf.json中配置详解

一、proxy.conf.json文件的目录 二、proxy.conf.json文件中的配置 "/xxx/api": {"target": "地址/api","secure": false,"logLevel": "debug","changeOrigin": true,"pathRewrite": {"…

【 buuctf-后门查杀】

采用 D 盾进行扫描查杀 有一个级别为 5 的扫描结果&#xff0c;记事本打开&#xff0c;即为 flag

python算法与数据结构(搜索算法和拓扑排序算法)---广度优先搜索和拓扑排序

广度优先搜索BFS 定义&基本内容 广度优先是按照层次由近及远的进行搜索&#xff0c;在当前层次所有可及节点都搜索完毕后才会继续往下搜索&#xff0c;其本质就是寻找从起点到终点的最短路程。 树的广度优先搜索 树的广度优先遍历&#xff0c;可以看成是层序遍历。 访问…

使用vite创建vue+ts项目,整合常用插件(scss、vue-router、pinia、axios等)和配置

一、检查node版本 指令&#xff1a;node -v 为什么要检查node版本&#xff1f; Vite 需要 Node.js 版本 18&#xff0c;20。然而&#xff0c;有些模板需要依赖更高的 Node 版本才能正常运行&#xff0c;当你的包管理器发出警告时&#xff0c;请注意升级你的 Node 版本。 二、创…