深入解析@Validated注解:Spring 验证机制的核心工具


一、注解出处与核心定位

1. 注解来源

所属框架@ValidatedSpring Framework 提供的注解(org.springframework.validation.annotation 包下)。
核心定位
作为 Spring 对 JSR-380(Bean Validation 2.0+) 规范的增强实现,用于触发方法参数、返回值或类成员变量的校验逻辑。
与标准Valid`(JSR 原生注解)相比,支持 分组验证层级校验,更贴合 Spring 生态。


二、基础使用步骤

1. 添加依赖(Spring Boot 示例)

pom.xml 中引入 Bean Validation 实现:

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

2. 启用校验支持

在 Spring Boot 中无需额外配置,自动生效

3. 编写校验规则(DTO/VO)

在数据对象中标注 Bean Validation 注解java

public class UserCreateDTO {
@NotNull(message = "ID 不能为空")
private Long id;@NotEmpty(message = "用户名不能为空")
private String username;@NotBlank(message = "密码不能为空或纯空格")
private String password;@Size(min = 6, max = 20, message = "密码长度需在6-20位之间")
private String password;@Email(message = "邮箱格式不正确")
private String email;@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式错误")
private String phone;@Min(value = 18, message = "年龄需≥18岁")
private Integer age;@DecimalMin(value = "0.0", inclusive = false, message = "价格必须大于0")
private BigDecimal price;@Positive(message = "库存必须为正数")
private Integer stock;@NegativeOrZero(message = "折扣率需≤0")
private BigDecimal discountRate;@Past(message = "出生日期必须早于当前时间")
private LocalDate birthday;@Future(message = "预约时间必须晚于当前时间")
private LocalDateTime appointmentTime;@Length(min = 2, max = 10, message = "名称长度需在2-10字符之间")
private String name;@Range(min = 1, max = 100, message = "数量需在1-100之间")
private Integer quantity;@URL(protocol = "https", message = "仅支持HTTPS链接")
private String website;@CreditCardNumber(message = "信用卡号无效")
private String cardNumber;@SafeHtml(message = "包含非法HTML标签")
private String description;
}

4. 触发校验(Controller 层)

在 Controller 方法参数前使用 @Validated@Valid

@RestController
public class UserController {@PostMapping("/users")public ResponseEntity<?> createUser(@RequestBody @Validated UserCreateDTO dto) { // 触发校验// 业务逻辑return ResponseEntity.ok().build();}
}

5. 处理校验异常

通过 @ExceptionHandler 捕获校验失败异常,返回统一错误响应:

@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(MethodArgumentNotValidException.class)public ResponseEntity<ErrorResponse> handleValidationException(MethodArgumentNotValidException ex) {List<String> errors = ex.getBindingResult().getFieldErrors().stream().map(error -> error.getField() + ": " + error.getDefaultMessage()).toList();return ResponseEntity.badRequest().body(new ErrorResponse("参数校验失败", errors));}
}

三、进阶功能与使用拓展

1. 分组校验(多场景复用规则)

场景说明
  • 创建用户时:所有字段必填
  • 更新用户时:允许不修改密码(密码字段非必填)
步骤实现

1. 定义分组接口

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

2. 在 DTO 中指定分组

public class UserDTO {@NotBlank(groups = {CreateGroup.class, UpdateGroup.class})private String username;@NotBlank(groups = CreateGroup.class)  // 仅创建时校验private String password;
}

3. Controller 方法指定生效分组

@PostMapping("/users")
public ResponseEntity<?> createUser(@RequestBody @Validated(CreateGroup.class) UserDTO dto) { // 仅校验 CreateGroup 分组规则
}@PutMapping("/users/{id}")
public ResponseEntity<?> updateUser(@PathVariable Long id,@RequestBody @Validated(UpdateGroup.class) UserDTO dto) { // 仅校验 UpdateGroup 分组规则
}

2. 方法级别校验(Service 层验证)

在 Service 接口/实现类中使用 @Validated 触发方法参数校验:

@Service
@Validated  //级别开启校验
public class UserService {public void updateEmail(@NotNull Long userId, @Email String newEmail) {  // 直接标注校验规则// 业务逻辑}
}

3. 自定义校验注解

需求示例

验证手机号格式(自定义规则)。

实现步骤

1. 定义注解 @Phone

@Documented
@Constraint(validatedBy = PhoneValidator.class)
@Target({FIELD, PARAMETER})
@Retention(RUNTIME)
public @interface Phone {String message() default "手机号格式不正确";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}

2. 编写校验器 PhoneValidator

public class PhoneValidator implements ConstraintValidator<Phone, String> {private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");@Overridepublic boolean isValid(String value, ConstraintValidatorContext context) {if (value == null) return true;  // 结合 @NotNull 使用return PHONE_PATTERN.matcher(value).matches();}
}

3. 在 DTO 中使用

public class UserDTO {@Phoneprivate String phone;
}

4. 级联校验(嵌套对象验证)

当对象包含其他对象成员时,使用 @Valid 触发嵌套校验:

public class OrderCreateDTO {@Valid  // 触发 AddressDTO 内部校验@NotNull(message = "收货地址不能为空")private AddressDTO address;// 其他字段...
}public class AddressDTO {@NotBlankprivate String city;@NotBlankprivate String street;
}

四、原理与关键机制

1. 校验触发流程

  1. 代理拦截:Spring 通过 AOP 代理拦截带有 @Validated 注解的类方法。
  2. 参数解析:在方法执行前,校验参数是否符合约束。
  3. 异常抛出:若校验失败,抛出 ConstraintViolationException(方法级别)或 MethodArgumentNotValidException(Controller 层)。
  4. 异常处理:通过 HandlerExceptionResolver@ExceptionHandler 处理错误。

2. 与 @Valid 的核心差异

特性@Valid (JSR-380)@Validated (Spring)
分组支持不支持支持
校验范围仅方法参数、字段方法参数、返回值、类成员变量
层级校验触发需显式添加 @Valid可自动级联
适用场景简单 Bean 校验Spring 生态复杂校验需求

五、常见问题与排查

1. 校验注解不生效

可能原因
• 未添加 spring-boot-starter-validation 依赖
• 未在类上标注 @Validated(方法级别校验)
• 校验方法未被 Spring 代理(如内部方法调用)

2. 分组校验未按预期执行

检查点
• Controller/Service 方法是否指定了正确的 groups
• 分组接口是否正确定义(空接口即可,无需实现)

3. 自定义校验器未生效

排查步骤
• 确保 ConstraintValidator 实现类被 Spring 管理(如添加 @Component
• 检查注解的 @Constraint(validatedBy) 指向正确类


六、最佳实践总结

  1. 分层校验
    • Controller 层:处理基础数据格式校验
    • Service 层:执行业务规则校验(如库存检查)

  2. 合理分组:避免为不同场景创建重复 DTO,通过分组复用校验规则。

  3. 统一异常处理:全局捕获校验异常,返回结构化的错误信息。

  4. 性能优化
    • 避免在复杂校验中执行数据库操作(优先通过缓存或异步校验)
    • 对高频接口禁用实时校验(如通过 groups 动态控制)

通过灵活运用 @Validated,开发者可以构建健壮维护的校验体系,显著提升代码质量和系统可靠性。

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

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

相关文章

2025年认证杯数学建模竞赛A题完整分析论文(含模型、可运行代码)(共32页)

2025年认证杯数学建模竞赛A题完整分析论文 目录 摘要 一、问题分析 二、问题重述 三、模型假设 四、 模型建立与求解 4.1问题1 4.1.1问题1解析 4.1.2问题1模型建立 4.1.3问题1样例代码&#xff08;仅供参考&#xff09; 4.1.4问题1求解结果分析&#xff08…

Google A2A协议,是为了战略性占领标准?

一、导读 2025 年 4 月 9 日&#xff0c;Google 正式发布了 Agent2Agent&#xff08;A2A&#xff09;协议。 A2A 协议致力于打破智能体之间的隔阂&#xff0c;让它们能够跨越框架和供应商的限制&#xff0c;以一种标准化、开放的方式进行沟通与协作 截止到现在&#xff0c;代…

Ansible:roles角色

文章目录 Roles角色Ansible Roles目录编排Roles各目录作用创建 roleplaybook调用角色调用角色方法1&#xff1a;调用角色方法2&#xff1a;调用角色方法3&#xff1a; roles 中 tags 使用实战案例 Roles角色 角色是ansible自1.2版本引入的新特性&#xff0c;用于层次性、结构化…

MCU的USB接口作为 USB CDC串口输出

引用&#xff1a; https://microchip-mplab-harmony.github.io/usb_apps_device/apps/usb_uart_bridge_dual/readme.html STM32 USB使用记录&#xff1a;使用CDC类虚拟串口&#xff08;VCP&#xff09;进行通讯_stm32 usb使用记录:使用cdc类虚拟串口(vcp)进行通讯-CSDN博客 前…

深度解析强化学习:原理、算法与实战

深度解析强化学习:原理、算法与实战 0. 前言1. 强化学习基础1.1 基本概念1.2 马尔科夫决策过程1.3 目标函数1.4 智能体学习过程2. 计算状态值3. 计算状态-动作值4. Q 学习4.1 Q 值4.2 使用 Q 学习进行 frozen lake 游戏4.3. frozen lake 问题4.4 实现 Q 学习小结系列链接0. 前…

UE5蓝图之间的通信------接口

一、创建蓝图接口 二、双击创建的蓝图接口&#xff0c;添加函数&#xff0c;并重命名新函数。 三、在一个蓝图&#xff08;如玩家角色蓝图&#xff09;中实现接口&#xff0c;如下图&#xff1a; 步骤一&#xff1a;点击类设置 步骤二&#xff1a;在细节面板已经实现的接口中…

2025 年“认证杯”数学中国数学建模网络挑战赛 A题 小行星轨迹预测

近地小行星&#xff08; Near Earth Asteroids, NEAs &#xff09;是轨道相对接近地球的小行 星&#xff0c;它的正式定义为椭圆轨道的近日距不大于 1.3 天文单位&#xff08; AU &#xff09;的小行星。 其中轨道与地球轨道最近距离小于 0.05A 且直径大于 140 米的小行星被…

Axure中继器(Repeater): 列表多选和 列表查询

文章目录 引言I 列表多选添加选中交互事件添加未选中交互事件II 列表查询知识点操作说明引言 基于鼠标点击交互事件实现列表多选列表查询 I 列表多选 添加选中交互事件 给列标题第一列多选框元件命名为ckeck,并同时添加选中交互事件; 同步添加设置选择/选中动作,目标元件选…

windows11下pytorch(cpu)安装

先装anaconda 见最下方 Pytorch 官网&#xff1a;PyTorch 找到下图&#xff08;不要求版本一样&#xff09;&#xff08;我的电脑是集显&#xff08;有navdia的装gpu&#xff09;&#xff0c;装cpu&#xff09; 查看已有环境列表 创建环境 conda create –n 虚拟环境名字(…

最新版IDEA超详细图文安装教程(适用Mac系统)附安装包及补丁2025最新教程

目录 前言 一、IDEA最新版下载 二、IDEA安装 三、IDEA补丁 前言 IDEA&#xff08;IntelliJ IDEA&#xff09;是专为Java语言设计的集成开发环境&#xff08;IDE&#xff09;&#xff0c;由JetBrains公司开发&#xff0c;被公认为业界最优秀的Java开发工具之一。DEA全称Int…

react从零开始的基础课1

全文约5万字。 1.hello,.. // App.jsx import { useState } from react import reactLogo from ./assets/react.svg import viteLogo from /vite.svg import ./App.cssfunction App() {const [count, setCount] useState(0)return (<><Greeting name"world&qu…

【linux知识】web服务环境搭建(一):用户以及开发环境初始化

toc 创建用户组以及用户 以下是 创建用户组 wendao 和用户 wendao 并指定 GID、UID 及家目录 的完整操作指南&#xff1a; 一、创建用户组&#xff08;指定 GID&#xff09; sudo groupadd -g 1500 wendao # 创建组并指定 GID 为 1500• 注意&#xff1a;GID 需唯一&#…

音视频 五 看书的笔记 MediaCodec

MediaCodec 用于访问底层媒体编解码器框架&#xff0c;编解码组件。通常与MediaExtractor(解封装,例如Mp4文件分解成 video和audio)、MediaSync、MediaMuxer(封装 例如音视频合成Mp4文件)、MediaCrypto、Image(cameraX 回调的ImageReader对象可以获取到Image帧图像,可转换成YU…

李宏毅NLP-3-语音识别part2-LAS

语音识别part2——LAS Listen Listen主要功能是提取内容信息&#xff0c;去除说话人差异和噪声 。编码器&#xff08;Encoder&#xff09;结构&#xff0c;输入是声学特征&#xff0c;经过 Encoder 处理后&#xff0c;输出为高级表示&#xff0c;这些高级表示可用于后续语音识别…

开源CMS的模块化设计和API接口如何具体影响其扩展性?

优秀的CMS系统都有自己主打的特点&#xff0c;开源CMS凭借其灵活性和低成本优势占据了市场主流地位&#xff0c;而模块化设计与API接口正是其扩展性的两大基石。本文将深入探讨这两大技术特性是如何影响cms的扩展性的。 一、模块化设计&#xff1a;功能解耦与生态繁荣的引擎 …

一文读懂WPF系列之常用控件以及样式

WPF控件 控件分类概览常用控件常用控件代码示例和效果 样式与模板应用样式定义​​方式行内样式​​页面/窗口级资源样式&#xff08;Local Resource&#xff09;应用程序全局资源独立资源字典&#xff08;ResourceDictionary&#xff09;控件模板&#xff08;ControlTemplate&…

AndroidTV D贝桌面-v3.2.5-[支持文件传输]

AndroidTV D贝桌面 链接&#xff1a;https://pan.xunlei.com/s/VONXSBtgn8S_BsZxzjH_mHlAA1?pwdzet2# AndroidTV D贝桌面-v3.2.5[支持文件传输] 第一次使用的话&#xff0c;壁纸默认去掉的&#xff0c;不需要按遥控器上键&#xff0c;自己更换壁纸即可

XDocument和XmlDocument的区别及用法

因为这几天用到了不熟悉的xml统计数据&#xff0c;啃了网上的资料解决了问题&#xff0c;故总结下xml知识。 1.什么是XML?2.XDocument和XmlDocument的区别3.XDocument示例1示例2&#xff1a;示例3&#xff1a; 4.XmlDocument5.LINQ to XML6.XML序列化(Serialize)与反序列化(De…

从竞速到巡检:不同无人机如何匹配最佳PCB方案?

随着无人机技术的快速发展&#xff0c;高性能PCB&#xff08;印刷电路板&#xff09;成为无人机制造商的核心需求之一。无论是消费级无人机还是工业级应用&#xff0c;PCB的质量直接影响飞行控制、信号传输和整机稳定性。那么&#xff0c;无人机制造商在选型高端PCB时&#xff…

高支模自动化监测解决方案

1.行业现状 高大模板支撑系统在浇筑施工过程中&#xff0c;诸多重大安全风险点进行实时自动化安全监测的解决方案主要监测由于顶杆失稳、扣件失效、承压过大等引起的支撑轴力、模板沉降、相对位移、支撑体系倾斜等参数变化。系统采用无线自动组网、高频连续采样&#xff0c;实时…