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

Spring Boot数据校验validation实战:写少一半代码,还更优雅!

在这里插入图片描述

🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志
🎐 个人CSND主页——Micro麦可乐的博客
🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战
🌺《RabbitMQ》专栏19年编写主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战
🌸《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解
🌛《开源项目》本专栏主要介绍目前热门的开源项目,带大家快速了解并轻松上手使用
🍎 《前端技术》专栏以实战为主介绍日常开发中前端应用的一些功能以及技巧,均附有完整的代码示例
✨《开发技巧》本专栏包含了各种系统的设计原理以及注意事项,并分享一些日常开发的功能小技巧
💕《Jenkins实战》专栏主要介绍Jenkins+Docker的实战教程,让你快速掌握项目CI/CD,是2024年最新的实战教程
🌞《Spring Boot》专栏主要介绍我们日常工作项目中经常应用到的功能以及技巧,代码样例完整
👍《Spring Security》专栏中我们将逐步深入Spring Security的各个技术细节,带你从入门到精通,全面掌握这一安全技术
如果文章能够给大家带来一定的帮助!欢迎关注、评论互动~

Spring Boot 数据校验validation实战:写少一半代码,还更优雅

  • 1. 前言
  • 2. 没有使用 Validation 的传统写法
  • 3. 使用 Validation 的优雅写法
  • 4. 全局异常处理(友好返回错误信息)
  • 5. 常用校验注解
  • 6. 分组校验
  • 7. 结语

1. 前言

在我们日常开发中,后端经常需要对请求参数进行校验。比如注册用户时,用户名不能为空、密码长度要在 6~16 之间、邮箱必须符合格式等等,如果我们不做校验,脏数据就可能进入数据库,造成业务问题;如果校验方式不合理,代码又会变得臃肿

在这里插入图片描述

相信很多小伙伴还在 Controller 代码中写大量重复的 if-else 判断,既冗余又难维护!(如果你也是这样操作,那一定要看完本篇文章)

下面博主介绍一下Spring Boot 提供的 Validation(基于 JSR 303/380 规范)让我们能通过注解的方式优雅地完成参数校验,极大地提升了开发效率和代码可读性


2. 没有使用 Validation 的传统写法

下面我们先看看没用 Validation 的“土法校验”,再对比一下用了注解后的优雅写法。当不使用数据校验框架时,我们通常会在 Controller 中手动校验参数,代码会像这样:

场景:创建用户接口

定义接受参数对象UserDto

// UserDTO实体类
class UserDto {private String name;private Integer age;private String email;// getter和setter省略
}

要求:用户名不能为空,长度5-10;邮箱格式必须正确;年龄在18-60之间

@RestController
@RequestMapping("/user")
public class UserController {@PostMapping("/add")public String addUser(UserDto user) {// 手动校验参数if (user.getName() == null || user.getName().trim().isEmpty()) {return "用户名不能为空";}if (user.getName().length() < 5 || user.getName().length() > 10) {return "用户名长度必须在5-10之间";}if (user.getAge() == null) {return "年龄不能为空";}if (user.getAge() < 18 || user.getAge() > 60) {return "年龄必须在18-60之间";}if (user.getEmail() == null || user.getEmail().trim().isEmpty()) {return "邮箱不能为空";}if (!user.getEmail().matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$")) {return "邮箱格式不正确";}// 业务逻辑处理return "用户添加成功";}
}

可以看出上述写法的缺点:
代码冗长,不利于维护
每个接口都要写重复的校验逻辑
校验逻辑和业务逻辑耦合,不够优雅


3. 使用 Validation 的优雅写法

我们可以在实体类上加注解,把校验规则声明在模型上,让 Spring 自动完成校验

Maven 依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>
</dependency>

UserDto对象加上注解

import javax.validation.constraints.*;public class UserDto {@NotBlank(message = "用户名不能为空")@Size(min = 2, max = 10, message = "用户名长度必须在{min}-{max}之间")private String username;@NotBlank(message = "邮箱不能为空")@Email(message = "邮箱格式不正确") // 自带邮箱格式校验,无需自己写正则!private String email;@NotNull(message = "年龄不能为空")@Min(value = 0, message = "年龄最小为{value}")@Max(value = 150, message = "年龄最大为{value}")private Integer age;// 省略 Getter 和 Setter...
}

在Controller参数前加@Valid或@Validated注解

import javax.validation.Valid;@RestController
@RequestMapping("/user")
public class UserController {@PostMapping("/add")// 关键一步:在 @RequestBody 前加上 @Valid 注解public String addUser(@Valid @RequestBody UserDto user) {// 只需关注核心业务System.out.println("用户创建成功: " + user);return "success";}
}

通过上述使用 validation 改造,Spring 会自动对 UserDto 的字段进行校验,当请求参数不满足规则时,Spring Boot 会自动抛出 MethodArgumentNotValidException 异常,不会进入这个方法体。但我们不能直接给用户返回异常栈,需要统一处理


4. 全局异常处理(友好返回错误信息)

刚才我们已经说过了参数校验不满足规则,系统会抛出MethodArgumentNotValidException ,那么我们就可以通过 @RestControllerAdvice 捕获 MethodArgumentNotValidException,来实现统一返回错误信息

import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;@RestControllerAdvice
public class GlobalExceptionHandler {/*** 处理实体校验异常*/@ExceptionHandler(MethodArgumentNotValidException.class)public Map<String, Object> handleValidException(MethodArgumentNotValidException e) {Map<String, Object> errorResult = new HashMap<>();errorResult.put("code", 400);errorResult.put("message", "参数校验失败");// 从异常对象中拿到具体的错误信息// 这里只取第一个错误信息,也可以全部返回String defaultMessage = Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage();errorResult.put("data", defaultMessage);return errorResult;}
}

最后我们可以使用Postman或curl测试,观察接口返回的JSON异常数据


5. 常用校验注解

注解功能说明
@NotNull值不能为null
@NotBlank字符串不能为空(trim后长度>0)
@NotEmpty集合、数组、Map、String不能为空
@Size(min=, max=)检查字符串、集合、数组大小
@Min(value)数字最小值
@Max(value)数字最大值
@Email校验邮箱格式
@Pattern(regexp=)正则表达式匹配
@Positive正数
@Future日期必须在未来
@Past日期必须在过去

6. 分组校验

当同一个实体类在不同场景下有不同的校验规则时,比如新增时ID应为空,而更新时ID不能为空,这时就需要分组校验

定义分组接口(标记接口)

public interface CreateGroup {} // 创建分组
public interface UpdateGroup {} // 更新分组

在实体上指定分组
继续改造一下我们的UserDto,这时候需要增加id字段

public class UserDto {@Null(groups = CreateGroup.class, message = "创建时ID必须为空")@NotNull(groups = UpdateGroup.class, message = "更新时ID不能为空")private Long id;@NotBlank(message = "用户名不能为空", groups = {CreateGroup.class, UpdateGroup.class})private String username;// ... 其他字段
}

在Controller中使用@Validated指定分组

@PostMapping("/create")
public String create(@Validated(CreateGroup.class) @RequestBody UserDto user) {// ... 创建逻辑
}@PostMapping("/update")
public String update(@Validated(UpdateGroup.class) @RequestBody UserDto user) {// ... 更新逻辑
}

7. 结语

通过使用 Spring Boot Validation,我们可以告别繁琐的手动参数校验,让代码更加简洁、优雅、易维护。希望本文能帮助你在项目中更好地应用数据校验机制,提升开发效率和代码质量,是开发中必不可少的利器!

如果你在实践过程中有任何疑问或更好的扩展思路,欢迎在评论区留言,最后希望大家 一键三连 给博主一点点鼓励!


专栏回顾:
01 Spring Boot 整合 spring-boot-starter-mail 实现邮件发送和账户激活
02 使用Spring Boot自定义注解 + AOP实现基于IP的接口限流和黑白名单
03 Spring Boot 使用自定义注解和自定义线程池实现异步日志记录
04 Spring Boot整合Jasypt 库实现配置文件和数据库字段敏感数据的加解密
05 Spring Boot中整合Jasypt 使用自定义注解+AOP实现敏感字段的加解密
06 Spring Boot整合WebSocket和Redis实现直播间在线人数统计功能
07 Spring Boot通过自定义注解和Redis+Lua脚本实现接口限流
08 Spring Boot整合Redis通过Zset数据类型+定时任务实现延迟队列
09 Spring Boot整合Redis实现发布/订阅功能
10 Spring Boot集成 Spring Retry 实现容错重试机制并附源码
11 Spring Boot 3 整合 SpringDoc OpenAPI 生成接口文档
12 Spring Boot 整合开源 Tess4J库 实现OCR图片文字识别
13 Spring Boot 实现 AOP 动态热插拔功能并附DEMO源码
14 Spring Boot中@Async注解的使用及原理 + 常见问题及解决方案
15 Spring Boot集成OpenPDF和Freemarker实现PDF导出功能并附水印
16 使用Spring Boot整合ip2region获取客户端IP地理位置信息
17 SpringBoot中MyBatis使用自定义TypeHandler
18 Spring Boot 集成 PDFBox 实现PDF电子签章的简单应用
19 实现重试只知道Spring Retry?试试Spring Boot 整合 Fast Retry 来实现重试机制
20 在Spring Boot中使用SeeEmitter类实现EventStream流式编程将实时事件推送至客户端
21 Spring Boot 整合 ShedLock 处理定时任务重复执行的问题
22 视频续播功能实现 - 断点续看从前端到 Spring Boot 后端
23 前端与 Spring Boot 后端无感 Token 刷新 - 从原理到全栈实践
24 一文让你测底明白如何在 Spring Boot 上传中将 MultipartFile 转 File 对象
在这里插入图片描述

http://www.xdnf.cn/news/1432351.html

相关文章:

  • 在线宠物用品|基于vue的在线宠物用品交易网站(源码+数据库+文档)
  • 硬件开发_基于物联网的自动售卖机系统
  • 联邦学习论文分享:GPT-FL: Generative Pre-Trained Model-AssistedFederated Learning
  • Apache 的安装及基本使用
  • MMORPG 游戏战斗系统架构
  • MATLAB矩阵及其运算(一)变量与常量
  • Python 中将 JSON 字符串转为对象的几种方法对比
  • 软件测试面试题【内附超详细面试宝典】
  • 【本地知识库问答系统】MaxKB搭建本地知识库问答系统
  • 低代码开发平台有哪些,中国十大低代码开发平台排名
  • 从零开始的云计算生活——第五十六天,临深履薄,kubernetes模块之etcd备份恢复和集群升级指南
  • Ruoyi-vue-plus-5.x第三篇Redis缓存与分布式技术:3.2 缓存注解与使用
  • 第2章:用户界面与基本监控
  • Ansible 循环、过滤器与判断逻辑
  • 小学一到六年级语文/英语/数学作业出题布置网站源码 支持生成PDF和打印
  • 基金交易量预测比赛_数据分析
  • MySQL 8.0 窗口函数详解:让数据分析更简单高效
  • 大数据毕业设计选题推荐-基于大数据的大学生就业因素数据分析系统-Spark-Hadoop-Bigdata
  • 华为OD最新机试真题-中庸行者-OD统一考试(C卷)
  • 【Unity Shader学习笔记】(二)图形显示系统
  • 从Web2到Web3:一场重塑数字未来的“静默革命”
  • mac 本地安装maven环境
  • LLM面试50问:NLP/RAG/部署/对齐/安全/多模态全覆盖
  • CentOS7.6
  • @Hadoop 介绍部署使用详细指南
  • Qt中QSettings的键值使用QDataStream进行存储
  • 【ComfyUI】SDXL Refiner 提示进一步提升生成图像的质量
  • Android的USB通信 (AOA Android开放配件协议)
  • CSS基础学习步骤
  • 蓝桥杯算法之基础知识(5)