[特殊字符] 芋道项目中的参数校验机制详解:以 AppProductActivityListReqVO 为例
在芋道(yudao)框架的 APP 接口开发中,我们经常会遇到这样的代码:
@GetMapping("/list")
@Operation(summary = "获得活动商品列表(按开始日期分组)")
@PermitAll
public CommonResult<List<AppProductActivityListRespVO>> getActivitySpuList(@Valid AppProductActivityListReqVO reqVO) {return success(appProductActivityService.getActivitySpuList(reqVO));
}
你可能会好奇 👇
✅ 为什么加上 @Valid
注解就能自动校验参数?
✅ 错误提示是从哪里来的?
✅ 怎么自定义规则,比如“结束时间不能早于开始时间”?
这篇文章就带你从入门到精通,彻底搞懂芋道的参数校验体系。
🧩 一、基础概念:@Valid 是做什么的?
在 Spring Boot 项目中,@Valid
或 @Validated
用于触发参数自动校验机制。
只要在 Controller 的入参上加上它:
public CommonResult<?> test(@Valid XxxReqVO reqVO)
Spring 会在调用方法前自动验证 reqVO
里的字段,
如果不符合规则,直接抛出异常(由全局异常处理器拦截返回友好提示)。
🧱 二、核心校验注解讲解
我们看下实际的例子:
@Schema(description = "用户 APP - 活动商品查询请求")
@Data
public class AppProductActivityListReqVO {@Schema(description = "开始日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2025-01-01")@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)@NotNull(message = "开始日期不能为空")private LocalDate startTime;@Schema(description = "结束日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "2025-01-31")@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)@NotNull(message = "结束日期不能为空")private LocalDate endTime;@Schema(description = "商品分类编号,可选")private Long categoryId;
🔹 每个注解的含义如下:
注解 | 作用 | 示例 |
---|---|---|
@Schema | 仅用于 Swagger/OpenAPI 文档描述 | 自动生成接口文档字段说明 |
@DateTimeFormat | 指定前端传入日期的格式 | 避免格式错误,如 "2025-01-01" |
@NotNull | 校验字段不为空 | "开始日期不能为空" |
@Valid | 触发整个对象的校验 | 用在 Controller 入参上 |
@Data | Lombok 注解,自动生成 getter/setter | 简化代码 |
🧮 三、进阶校验:自定义逻辑(@AssertTrue)
除了基本的非空、长度、正则验证外,芋道还经常使用自定义逻辑校验。
看下面两个方法 👇
@AssertTrue(message = "结束时间不能早于开始时间")
@JsonIgnore
public boolean isEndNotBeforeStart() {if (startTime == null || endTime == null) {return true; // 交给 @NotNull 提示}return !endTime.isBefore(startTime);
}@AssertTrue(message = "时间范围不能超过90天")
@JsonIgnore
public boolean isRangeWithinLimit() {if (startTime == null || endTime == null) {return true;}return ChronoUnit.DAYS.between(startTime, endTime) <= 90;
}
✨ 含义解析:
注解/方法 | 含义 |
---|---|
@AssertTrue | 表示该方法返回 true 时校验通过;返回 false 时提示错误信息 |
@JsonIgnore | 防止这个方法被序列化到 JSON 中(否则会在响应中看到它) |
方法名通常以 is...() 开头 | Java Bean Validation 默认识别布尔校验方法 |
这样写的好处:
- 不用写自定义 Validator;
- 校验逻辑与字段关系紧密;
- 一目了然,错误提示友好。
🧰 四、Spring 如何处理这些错误?
当参数不符合要求时(例如 endTime
早于 startTime
),
Spring 会抛出 MethodArgumentNotValidException
,
芋道框架的全局异常处理器会捕获它,返回统一格式:
{"code": 400,"message": "结束时间不能早于开始时间"
}
这部分逻辑在:
yudao-framework -> web -> core -> handler -> GlobalExceptionHandler.java
中实现,统一把校验错误转为 CommonResult
的标准结构。
🔧 五、如何在自己的项目中使用?
你只要做到以下几步就能复用:
✅ 1. 在依赖中引入 validation
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>
</dependency>
✅ 2. 在 Controller 入参上加上 @Valid
@PostMapping("/create")
public CommonResult<?> create(@Valid @RequestBody OrderCreateReqVO reqVO) {return success(orderService.create(reqVO));
}
✅ 3. 在 VO 上使用注解声明规则
public class OrderCreateReqVO {@NotBlank(message = "订单编号不能为空")private String orderNo;@Min(value = 1, message = "数量必须大于0")private Integer count;
}
✅ 4. 自定义复杂逻辑时用 @AssertTrue
或写自定义校验器
💡 六、额外技巧:可选 vs 必填字段
有些字段并不是必须的,比如 categoryId
。
如果不加任何注解,Spring 就不会校验它。
要让它“可选但有条件约束”,可以结合 @AssertTrue
动态判断,比如:
@AssertTrue(message = "如果传入分类ID,必须大于0")
@JsonIgnore
public boolean isCategoryIdValid() {return categoryId == null || categoryId > 0;
}
🧭 七、总结
功能 | 用法 | 示例 |
---|---|---|
非空验证 | @NotNull , @NotBlank | 字符串、数字、对象等 |
范围验证 | @Min , @Max , @Size | 限定长度或数值范围 |
格式验证 | @Email , @Pattern | 邮箱、手机号等 |
自定义逻辑 | @AssertTrue + 布尔方法 | 校验时间、组合条件 |
全局统一返回 | GlobalExceptionHandler | 自动包装友好提示 |
✅ 八、总结一句话
芋道的参数校验机制本质上是:
Spring Boot + Hibernate Validator + 自定义异常处理器
组合实现的一套「自动参数校验 + 友好提示」体系。
你只要在入参 VO 上写好注解,
在 Controller 上加 @Valid
,
剩下的校验、错误提示、格式化返回,系统都会帮你自动完成。