李锋镝的博客

  • 首页
  • 时间轴
  • 说说
  • 左邻右舍
  • 博友圈
  • 关于我
    • 关于我
    • 另一个网站
    • 我的导航站
    • 网站地图
    • 赞助
  • 留言
  • 走心评论
  • 系列文章
  • 🚇开往
Destiny
自是人生长恨水长东
  1. 首页
  2. 原创
  3. 正文

@Valid 和 @Validated 的区别

2025年5月23日 约 1,371 字5 分钟 500点热度 0人点赞 2条评论
本文最后更新于 2025年5月23日,距今已 422 天,其中的信息可能已经发生变化,请注意甄别。

前言

参数校验是保证程序健壮性的重要环节,前端校验为用户体验,后端校验为系统安全。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

推荐阅读

  • SpringBoot 实现 RSA+AES 自动接口解密
  • SpringBoot常用注解
  • CompletableFuture使用详解
  • SpringBoot 中内置的 49 个常用工具类
  • SpringBoot 实现接口防刷的 5 种实现方案
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
标签: JAVA SpringBoot 安全
最后更新:2025年5月23日
相关文章
  • 别再背线程池的七大参数了,现在面试官都这么问2025年5月15日
  • JVM内存结构详解2019年10月18日
  • 阿里巴巴《Java开发手册》下载2019年6月28日
  • @Async注解的坑2022年8月11日
  • Redisson分布式锁的watch dog自动续期机制2023年1月5日

李锋镝

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

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

文章评论

  • lzjLv 1

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

    WindowsChrome 136.0.0.0 中国-北京市
    2025年5月23日
    00 回复
    • 李锋镝管理

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

      macOSChrome 136.0.0.0 中国-北京市
      2025年5月23日
      00 回复
  • 昨夜星辰昨夜风,画楼西畔桂堂东。
    身无彩凤双飞翼,心有灵犀一点通。
    隔座送钩春酒暖,分曹射覆蜡灯红。
    嗟余听鼓应官去,走马兰台类转蓬。

    听点儿音乐吧 朋友~
    文章目录

    那年今日(07月20日)

    • 1999年:中国在西藏找到石油
    • 1985年:西藏大学在拉萨成立
    • 1983年:中国近代妇幼卫生事业的创始人杨崇瑞逝世
    • 1969年:人类实现首次登月
    • 1822年:奥地利近代遗传学的奠基者孟德尔出生
    • 更多历史事件
    最新 热点 随机
    最新 热点 随机
    增加了两套复古皮肤-牛皮纸、千禧网页 Claude Design介绍与使用 Kratos+主题新功能介绍 Taste Skill 说明与使用 jasypt-spring-boot 使用说明 Kratos+主题新功能预览及功能演示
    AI时代,个人技术博客的出路在哪里?这个域名注册整整十年了,十年时间,真快啊WordPress实现用户评论等级排行榜插件WordPress网站换了个字体,差点儿把样式换崩了做了一个WordPress文章热力图插件千万级大表新增字段实战指南:告别锁表与业务中断
    Maven发布本地项目的jar包和源码到私有仓库(maven-source-plugin的简单使用) 【漫画】戏说外行对程序员的误会有多深 AI重构开发者工作范式:从Anthropic内部调研看Claude对研发领域的深层影响 深入理解 Java 泛型:从通配符到实战应用全解析 Python 3.12并发革命:大厂争相升级的底层逻辑与实战指南 居家办公了~
    最近评论
    皮皮社长 发布于 3 天前(07月17日) 李哥你这也太复古了点吧, :37: 你这主题排版得好,我的主题不行,主要是不懂代码,都是ai搞的。
    李锋镝 发布于 6 天前(07月14日) 外面的主题功能差异化比较大,部分功能没有还得通过插件来实现,这样样式也不统一,而且经常有爆出风险、漏...
    瓦匠 发布于 6 天前(07月14日) 很奈斯啊,都在设计属于自己的主题了,羡慕了
    rxshc 发布于 1 周前(07月13日) 工具看着挺实用的。
    李锋镝 发布于 2 周前(07月09日) https://github.com/Leonxlnx/taste-skill
    标签聚合
    K8s SpringBoot MySQL AI WordPress MCP 多线程 JVM Spring JAVA 日常 数据库 ElasticSearch Redis 架构 SQL AI编程 IDEA 分布式 设计模式
    友情链接
    • Blogs·CN
    • Honesty
    • Mr.Sun的博客
    • 临窗旋墨
    • 哥斯拉
    • 彬红茶日记
    • 志文工作室
    • 懋和道人
    • 拾趣博客导航
    • 搬砖日记
    • 旧时繁华
    • 林羽凡
    • 瓦匠个人小站
    • 皮皮社
    • 知向前端
    • 韩小韩博客
    • 风渡言

    COPYRIGHT © 2026 lifengdi.com. ALL RIGHTS RESERVED.

    域名年龄

    Theme Kratos+ By Dylan Li

    津ICP备2024022503号-3

    京公网安备11011502039375号