李锋镝的博客

  • 首页
  • 时间轴
  • 说说
  • 每日心情
  • Now
  • 系列文章
  • 论坛
  • 左邻右舍
    • 左邻右舍
    • 博友圈
  • 留言
    • 留言
    • 走心评论
  • 关于
    • 关于本站
    • 网站地图
    • 网站统计
    • 另一个网站
    • 我的导航站
    • 赞助
  • 🚇开往
!Destiny
惟坚韧者始能遂其志
  1. 首页
  2. 原创
  3. 正文

@Valid 和 @Validated 的区别

2025年5月23日 约 1,371 字5 分钟 168 0 2
本文最后更新于 2025年5月23日,距今已 488 天,其中的信息可能已经发生变化,请注意甄别。

前言

参数校验是保证程序健壮性的重要环节,前端校验为用户体验,后端校验为系统安全。Spring Boot 中常用 @Valid 和 @Validated 实现参数校验,本文将详细解析两者的区别、用法及代码示例。

一、@Valid 注解

1. 功能与依赖

  • 标准规范:属于 Java EE 标准注解(JSR 303 规范),用于触发参数合法性校验。
  • 依赖引入:
    • Spring Boot 项目:已包含在 spring-boot-starter-web 中,无需额外引入。
    • 非 Spring Boot 项目:需手动添加 javax.validation 和 hibernate-validator 依赖。
<!-- 非Spring Boot项目依赖 -->  
<dependency>  
    <groupId>javax.validation</groupId>  
    <artifactId>validation-api</artifactId>  
</dependency>  
<dependency>  
    <groupId>org.hibernate</groupId>  
    <artifactId>hibernate-validator</artifactId>  
</dependency>  

2. 使用场景

  • 适用位置:方法参数、构造函数、成员属性(field)、方法返回值。
  • 核心功能:支持嵌套校验(对对象中的属性值,甚至嵌套对象进行校验)。
  • 代码示例:

    // 实体类  
    @Data  
    public class SysUser {  
      @NotBlank(message = "姓名不能为空")  
      @Length(max = 10, message = "名称不能超过{max}字符")  
      private String name;  
    
      @NotNull(message = "年龄不能为空")  
      @Range(min = 1, max = 100, message = "年龄范围为{min}到{max}岁")  
      private Integer age;  
    }  
    // 控制器  
    @RestController  
    @RequestMapping("/sysUser")  
    public class SysUserController {  
      @PostMapping("/add")  
      public String addUser(@RequestBody @Valid SysUser sysUser, BindingResult bindingResult) {  
          if (bindingResult.hasErrors()) {  
              return bindingResult.getAllErrors().get(0).getDefaultMessage(); // 返回第一条错误信息  
          }  
          return "操作成功!";  
      }  
    }  

    说明:需通过 BindingResult 手动捕获校验结果,若不处理错误,程序不会中断执行。

二、@Validated 注解

1. 功能与定位

  • Spring 专属:Spring 框架特有的注解,是 @Valid 的增强版,支持分组验证。
  • 无嵌套校验:仅能对单一对象进行校验,无法递归验证嵌套对象。

2. 使用场景

  • 适用位置:类、方法、方法参数(不能用于成员属性)。
  • 分组验证:针对同一对象的不同操作(如新增、更新),设置不同的校验规则。

    // 分组接口  
    public interface CreationGroup {} // 新增分组  
    public interface UpdateGroup {} // 更新分组  
    // 实体类(分组校验示例)  
    @Data  
    public class SysUser {  
      @NotNull(message = "更新时ID不能为空", groups = UpdateGroup.class)  
      private String id;  
    
      @NotBlank(message = "名字不能为空", groups = {CreationGroup.class, UpdateGroup.class})  
      @Size(min = 6, max = 12, message = "名字长度在6-12之间")  
      private String name;  
    }  
    // 控制器(分组校验应用)  
    @RestController  
    public class SysUserController {  
      @PostMapping("/insert")  
      public String insertUser(@Validated(CreationGroup.class) @RequestBody SysUser sysUser, BindingResult bindingResult) {  
          if (bindingResult.hasErrors()) {  
              return "插入失败:" + bindingResult.getFieldError().getDefaultMessage();  
          }  
          return "插入成功";  
      }  
    
      @PostMapping("/update")  
      public String updateUser(@Validated(UpdateGroup.class) @RequestBody SysUser sysUser, BindingResult bindingResult) {  
          // 同上逻辑  
      }  
    }  

3. 全局异常处理

  • 自动抛异常:使用 @Validated 时,若校验失败,程序会自动抛出 MethodArgumentNotValidException。
  • 统一捕获:通过 @RestControllerAdvice 全局捕获异常,返回友好提示。
    @RestControllerAdvice  
    public class ValidatedExceptionHandler {  
      @ExceptionHandler(MethodArgumentNotValidException.class)  
      @ResponseBody  
      @ResponseStatus(HttpStatus.BAD_REQUEST)  
      public Result handleValidationException(MethodArgumentNotValidException ex) {  
          String errorMessage = ex.getBindingResult().getAllErrors().get(0).getDefaultMessage();  
          return Result.error("参数校验失败:" + errorMessage);  
      }  
    }  

三、核心区别对比

维度 @Valid @Validated
所属框架 Java EE(JSR 303) Spring 框架
嵌套校验 支持(可校验嵌套对象) 不支持
分组验证 不支持 支持(通过 groups 参数定义分组)
适用位置 方法、构造函数、参数、成员属性 类、方法、参数(不能用于成员属性)
校验结果处理 需手动通过 BindingResult 捕获 自动抛出异常,需全局捕获处理
代码简洁性 需显式处理错误结果 自动中断流程,代码更简洁

四、参数校验常用注解

1. 值校验

注解 说明 示例
@Null 必须为 null @Null(message = "人数必须为null")
@NotNull 不能为 null @NotNull(message = "人数不能为空")
@NotBlank 字符串非空(至少一个非空格字符) @NotBlank(message = "姓名不能为空")
@NotEmpty 集合/数组非空 @NotEmpty(message = "组织部门不能为空")
@Positive 必须为正数 @Positive(message = "金额必须为正数")

2. 范围校验

注解 说明 示例
@Min 最小值约束 @Min(value = 18, message = "年龄≥18")
@Max 最大值约束 @Max(value = 120, message = "年龄≤120")
@Range 范围约束(min/max) @Range(min = 18, max = 80, message = "年龄范围")
@Past 必须为过去时间 @Past(message = "日期必须为过去")

3. 长度校验

注解 说明 示例
@Size 集合/数组长度约束 @Size(min = 7, max = 11, message = "长度7-11")
@Length 字符串长度约束 @Length(min = 6, max = 12, message = "姓名长度")

4. 格式校验

注解 说明 示例
@Pattern 正则匹配 @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式错误")
@Email 邮箱格式校验 @Email(message = "请输入有效邮箱")
@URL URL 格式校验 @URL(message = "无效的URL地址")

五、总结

  • 选择建议:
    • 需要嵌套校验(如对象中包含子对象)时,使用 @Valid。
    • 需要分组验证(如不同业务场景执行不同校验规则)时,使用 @Validated。
  • 最佳实践:
    • 统一使用 @Validated 简化代码,通过全局异常处理统一返回错误信息。
    • 复杂校验场景结合分组验证,提高代码可维护性。

掌握 @Valid 和 @Validated 的区别,能更灵活地实现参数校验,保障系统数据的完整性和安全性。

除非注明,否则均为李锋镝的博客原创文章,转载必须以链接形式标明本文链接

本文链接:https://www.lifengdi.com/article/4420

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
分享到

@Valid 和 @Validated 的区别

也可使用浏览器菜单中的「分享」功能

微信扫一扫分享

标签: JAVA SpringBoot 安全
最后更新:2025年5月23日

岁月同一天 9 月 23 日

回望过去的今天,你在写什么

  • 代码人生
    1 年前 2025年9月23日
    Consul开启transparent-proxy访问外部资源的时候,请求偶发Connection reset问题分析

    在Consul中启用透明代理(Transparent Proxy)后,访问外部资源出现偶发Connection rese…

  • 其他
    7 年前 2019年9月23日
    Idea激活码

    2020.4.21到期 亲测有效 812LFWMRSH-eyJsaWNlbnNlSWQiOiI4MTJMRldNUlNI…

相关文章
  • RocketMQ的push消费方式实现详解2022年8月9日
  • Java进阶实战:10个高效技巧+环境管理指南,让代码简洁又优雅2025年12月12日
  • 使用itext和freemarker来根据Html模板生成PDF文件,加水印、印章2019年9月5日
  • 以面试官视角万字解读线程池10大经典面试题2025年5月14日
  • BeanCopier工具类(性能优化工具类)2019年7月10日

李锋镝

既然选择了远方,便只顾风雨兼程。

打赏 点赞
< 上一篇
下一篇 >
1234567891112131415161718192021222324252627282930313233343536373839404142434446474849505152535455575859606162636465666769727476777879808182858687909293949596979899
取消回复
…

文章评论

  • lzjLv 1

    您好,请问您的自定义域名邮箱mailme@lifengdi.com是怎么实现的,自建的吗?

    WindowsWindowsChrome 136.0.0.0Chrome 136.0.0.0中国中国-北京
    2025年5月23日
    00 回复
    • 李锋镝博主

      @lzj 用的是阿里云的企业邮箱。 :8:

      macOSmacOSChrome 136.0.0.0Chrome 136.0.0.0中国中国-北京
      2025年5月23日
      00 回复
  • 春未老,风细柳斜斜。试上超然台上看,半壕春水一城花。烟雨暗千家。 寒食后,酒醒却咨嗟。休对故人思故国,且将新火试新茶。诗酒趁年华。

    听点儿音乐吧 朋友~
    文章目录
    最新 热点 随机
    最新 热点 随机
    Redis7+&8.X 全新进阶系列(02):Redis Functions 详解——替代Lua脚本的官方轻量化函数方案 Redis7.x&8.x 全新进阶系列(01):划时代升级总览——从6.x到7.x/8.x全版本变革全景 让WordPress静态化之Rocket‑Nginx WordPress下一代默认主题Ipsum预览 C++之父重磅发声:AI编程正在毁掉一代程序员 支撑全网40%网站的WordPress正在重新拥抱PHP生态
    关于主题加载速度优化的一点儿小演进给主题增加了Now、每日心情、年度回顾、岁月同一天、随机漫步等功能WordPress缓存插件WP Fastest Cache、WP Rocket 、FlyingPress对比关于使用AI的一些思考WordPress下一代默认主题Ipsum预览Kratos+ v1.1.16版本更新说明
    Redis 7.0+ 中 EXPIREAT 的增强选项详解 Chrome等浏览器下出现net::ERR_BLOCKED_BY_CLIENT的解决办法 从零开始入门 K8s | Kubernetes 网络概念及策略控制 LangChain + Zod 实战指南:构建类型安全的AI结构化输出系统 办理居住证困难重重啊! 是时候优雅的和NullPointException说再见了
    最近评论
    李锋镝 发布于 23 小时前(09月22日) 是的,换风格了,不过我觉得之前的年份命名挺好的,一看就知道哪一年的
    obaby 发布于 1 天前(09月22日) 我现在是个假的wp了,哈哈哈 wp终于改了主题的命名风格了
    李锋镝 发布于 3 天前(09月20日) 静态博客我之前也用过,但是感觉不是很方便,后来就一直用的WordPress
    Sheep5 发布于 3 天前(09月20日) 我直接用静态博客,天然有速度优势。
    不凡 发布于 3 天前(09月20日) 主要是wordpress插件丰富,需要什么功能插件,插件市场应有尽有,typecho是性能更好、更轻...
    标签聚合
    SpringBoot Spring 多线程 IDEA 日常 MySQL AI K8s 架构 AI编程 JAVA SQL Theme ElasticSearch WordPress Claude Redis 分布式 数据库 JVM
    友情链接
    • 老张博客
    • Mr.Sun的博客
    • 懋和道人
    • 志文工作室
    • 皮皮社
    • 林羽凡
    • 彬红茶日记
    • sssr7844的博客
    • 蜗牛工作室
    • 九仞之行
    • 临窗旋墨
    • 韩小韩博客
    • 韩情脉脉
    • 若梦博客
    • lijie blog
    • 瓦匠个人小站
    • 搬砖日记
    • 哥斯拉
    • Serendipity
    • Honesty

    COPYRIGHT © 2016-2026 lifengdi.com. ALL RIGHTS RESERVED.

    lifengdi.com

    Domain age badge for lifengdi.com

    Theme Kratos-plus By Dylan Li

    津ICP备2024022503号-3

    京公网安备11011502039375号