李锋镝的博客

  • 首页
  • 时间轴
  • 留言
  • 插件
  • 左邻右舍
  • 关于我
    • 关于我
    • 另一个网站
  • 知识库
  • 赞助
Destiny
自是人生长恨水长东
  1. 首页
  2. 原创
  3. 正文

@Valid 和 @Validated 的区别

2025年5月23日 33点热度 0人点赞 2条评论

前言

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

相关文章

  • 使用RocketMQ时,服务启动过程中,Consumer在服务未启动时消费消息问题处理
  • SpringBoot整合GraphQL入门教程
  • 结合Apollo配置中心实现日志级别动态配置
  • Spring Boot 2.5.0重新设计的spring.sql.init 配置有啥用?
  • SpringBoot整合Elasticsearch游标查询(scroll)
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
标签: JAVA SpringBoot 安全
最后更新:2025年5月23日

李锋镝

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

打赏 点赞
< 上一篇

文章评论

  • lzj

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

    2025年5月23日
    回复
    • 李锋镝

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

      2025年5月23日
      回复
  • 1 2 3 4 5 6 7 8 9 11 12 13 14 15 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 46 47 48 49 50 51 52 53 54 55 57 58 60 61 62 63 64 65 66 67 69 72 74 76 77 78 79 80 81 82 85 86 87 90 92 93 94 95 96 97 98 99
    取消回复

    他乡共酌金花酒,万里同悲鸿雁天。

    最新 热点 随机
    最新 热点 随机
    @Valid 和 @Validated 的区别 URL地址末尾加不加“/”有什么区别 Java设计模式:状态模式 Java设计模式:策略模式 Java设计模式:模板方法模式 Docker核心概念解析及使用
    玩博客的人是不是越来越少了?2024年11月1号 农历十月初一准备入手个亚太的ECS,友友们有什么建议吗?别再背线程池的七大参数了,现在面试官都这么问@Valid 和 @Validated 的区别我的第一个WordPress插件:Dylan Custom Plugin上线了
    Java数据类型判断工具类DataTypeUtil Java中ArrayList为什么比LinkedList查询速度快? 微服务架构梳理总结(二) 透过现象看本质:Java类动态加载和热替换 Java 序列化和反序列化为什么要实现 Serializable 接口? linux中ftp查看不到文件列表的问题
    标签聚合
    ElasticSearch JAVA 多线程 文学 JVM docker 教程 Spring 日常 分布式 SpringBoot 面试 K8s IDEA MySQL 设计模式 SQL 数据库 Redis 架构
    友情链接
    • i架构
    • LyShark - 孤风洗剑
    • 临窗旋墨
    • 博友圈
    • 博客录
    • 博客星球
    • 哥斯拉
    • 志文工作室
    • 搬砖日记
    • 旋律的博客
    • 旧时繁华
    • 林羽凡
    • 知向前端
    • 集博栈
    • 韩小韩博客

    COPYRIGHT © 2025 lifengdi.com. ALL RIGHTS RESERVED.

    Theme Kratos Made By Dylan

    津ICP备2024022503号-3