Spring Boot 默认不校验 @RequestBody List<T> 中每个元素字段,需用 ValidList 封装、DTO 字段加 @Valid、分组校验或自定义 ConstraintValidator 实现递归校验。

Spring Boot 默认不校验 @RequestBody List<T> 中每个元素的字段,因为 @Valid 无法穿透原生集合类型。要让每个对象都触发 @NotNull、@Size 等注解,关键在于“让校验框架能识别并递归校验集合里的每个元素”。
用 ValidList 封装集合(最常用)
定义一个自定义类实现 List<E> 接口,并在内部持有的真实列表上加 @Valid:
- 必须实现
List<E>接口,否则 Spring 无法将 JSON 数组反序列化为该类型 - 推荐用 Lombok 的
@Delegate简化代理逻辑,避免手写大量转发方法 - Controller 参数类型需显式改为
ValidList<ItemDTO>,不能仍是List<ItemDTO>
示例:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
@Data
public class ValidList<E> implements List<E> {
@Valid
@Delegate
private List<E> list = new ArrayList<>();
}
在 DTO 字段上直接标注 @Valid(适合嵌套场景)
如果集合是某个 DTO 的字段,可在该字段声明处加 @Valid,并确保 DTO 类本身被 @Validated 或 @Valid 触发:
- 适用于
OrderDTO包含List<ItemDTO>这类结构 - 需在
ItemDTO内部字段上添加具体约束,如@NotBlank、@Min - 注意:仅加
@Valid不够,Controller 方法参数仍需@Validated启用校验
示例:
public class OrderDTO {
@NotEmpty(message = "商品列表不能为空")
@Size(min = 1, max = 100)
private List<@Valid ItemDTO> items;
}
配合分组校验控制触发时机
当集合元素需按不同业务场景启用不同规则时,可用分组校验精准控制:
- 定义分组接口,如
Create.class、Update.class - 在
ItemDTO字段上按分组标注约束,例如创建时不校验 ID,更新时要求非空 - Controller 方法中使用
@Validated(Create.class)显式指定分组
示例:
public class ItemDTO {
@Null(groups = Create.class)
@NotNull(groups = Update.class)
private Long id;
@NotBlank(groups = {Create.class, Update.class})
private String name;
}
自定义 ConstraintValidator 处理复杂逻辑
当内置注解无法满足需求(如校验多个字段间依赖关系),可编写自定义校验器:
- 实现
ConstraintValidator<YourAnnotation, ItemDTO> - 在
isValid()方法中编写校验逻辑,支持访问整个对象实例 - 在
ItemDTO类上标注该自定义注解,无需额外修改集合封装方式
例如:校验 item 的 price 和 discount 是否满足“折扣后价格不低于成本价”,这类跨字段逻辑只能靠自定义校验器实现。

















