如何在Springdoc中使用validation-api分组校验?
问题:Springdoc无法识别Validation分组注解导致DTO字段必填标识错误
在Spring Boot应用中使用validation-api与Springdoc时,希望通过复用单个DTO类处理相似请求。Springdoc能识别@NotBlank、@NotNull等校验注解,但无法识别注解的groups分组属性(如@NotBlank(groups = {GetGroup.class}))。
代码示例
public class MyController { @GetMapping public MyResponseDto getFoo(@ParameterObject @Validated(GetGroup.class) MyRequestDto request) { ... } @PostMapping public Long postFoo(@ParameterObject @Validated(PostGroup.class) MyRequestDto request) { ... } } public class MyRequestDto { @NotNull(groups = {GetGroup.class}) private String field01; @NotNull(groups = {PostGroup.class}) private String field02; }
未集成Springdoc时,@Validated(GetGroup.class)会校验field01必填,@Validated(PostGroup.class)会校验field02必填,但Springdoc会将这两个字段都标记为必填项,需要解决此问题。
解决方案
方法1:自定义OperationCustomizer处理分组校验
通过实现OperationCustomizer接口,根据控制器方法上的@Validated分组信息,过滤DTO中不属于当前分组的校验注解,修正OpenAPI的参数必填标识:
@Component public class ValidatedGroupOperationCustomizer implements OperationCustomizer { @Override public Operation customize(Operation operation, HandlerMethod handlerMethod) { // 获取方法上的@Validated注解 Validated validated = handlerMethod.getMethodAnnotation(Validated.class); if (validated == null || validated.value().length == 0) { return operation; } Class<?>[] groups = validated.value(); // 获取请求参数对应的DTO类型 MethodParameter methodParam = handlerMethod.getMethodParameters()[0]; Class<?> dtoClass = methodParam.getParameterType(); // 遍历DTO所有字段,校验分组匹配情况 for (Field field : dtoClass.getDeclaredFields()) { // 处理@NotNull注解 processValidationAnnotation(operation, field, NotNull.class, groups); // 处理@NotBlank注解 processValidationAnnotation(operation, field, NotBlank.class, groups); // 按需添加其他校验注解类型(如@NotEmpty) } return operation; } private <T extends Annotation> void processValidationAnnotation(Operation operation, Field field, Class<T> annotationClass, Class<?>[] targetGroups) { T annotation = field.getAnnotation(annotationClass); if (annotation == null) { return; } try { // 通过反射获取注解的groups属性 Method groupsMethod = annotationClass.getMethod("groups"); Class<?>[] annotationGroups = (Class<?>[]) groupsMethod.invoke(annotation); // 判断当前字段的校验注解是否属于目标分组 boolean isMatch = Arrays.stream(annotationGroups) .anyMatch(group -> Arrays.asList(targetGroups).contains(group)); if (!isMatch) { // 找到对应参数并设置为非必填 operation.getParameters().stream() .filter(param -> param.getName().equals(field.getName())) .findFirst() .ifPresent(param -> param.setRequired(false)); } } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { // 异常处理 e.printStackTrace(); } } }
方法2:使用@Schema注解手动指定字段必填性
在DTO字段上通过@Schema的requiredMode属性,结合分组场景控制不同接口下的必填显示:
public class MyRequestDto { @NotNull(groups = {GetGroup.class}) @Schema(requiredMode = RequiredMode.NOT_REQUIRED) private String field01; @NotNull(groups = {PostGroup.class}) @Schema(requiredMode = RequiredMode.NOT_REQUIRED) private String field02; }
同时配合自定义逻辑,在不同接口方法上动态设置对应字段的必填性,或者结合Springdoc的参数过滤功能实现分组匹配。
方法3:升级Springdoc至最新稳定版
Springdoc后续版本(如v1.6.0及以上)对Validation分组注解的支持有优化,升级后可能无需额外配置即可自动识别分组信息,正确标记对应字段的必填性。建议优先尝试升级版本。
内容的提问来源于stack exchange,提问作者Rurien
相关产品推荐
相关产品推荐

