Spring Boot3升级后OpenAPI自定义Header参数生成顺序反转问题求助
问题场景
ServiceA通过GroupedOpenApi的addOperationCustomizer方法逐个添加自定义Header参数(parameterXXX、parameterYYY、parameterZZZ),在Spring Boot2 + springdoc-openapi-ui环境下,生成的OpenAPI定义中参数顺序为接口原生query参数id,随后是parameterXXX、parameterYYY、parameterZZZ,客户端生成的方法参数顺序符合预期。
升级到Spring Boot3 + springdoc-openapi-starter-webmvc-ui后,Header参数顺序反转成parameterZZZ、parameterYYY、parameterXXX,客户端生成的方法参数顺序随之颠倒。由于所有参数均为字符串类型,编译器无法检测此错误,可能导致调用时参数值传递错误。
解决方案
方案1:合并成单个OperationCustomizer统一控制顺序
将所有Header参数的添加逻辑合并到一个OperationCustomizer中,按期望顺序逐个添加参数,避免多个Customizer执行顺序变化带来的问题。
代码示例:
@Component public class CompositeHeaderParameterAdder implements OperationCustomizer { @Override public Operation customize(Operation operation, HandlerMethod handlerMethod) { // 严格按预期顺序添加Header参数 addHeaderParam(operation, "parameterXXX"); addHeaderParam(operation, "parameterYYY"); addHeaderParam(operation, "parameterZZZ"); return operation; } private void addHeaderParam(Operation operation, String paramName) { Parameter headerParam = new Parameter() .in(ParameterIn.HEADER.toString()) .name(paramName) .schema(new Schema().type("string")) .required(true); operation.addParametersItem(headerParam); } }
修改GroupedOpenApi配置,仅添加这个合并后的Customizer:
@Bean public GroupedOpenApi opeApiDefinitionBuilder(CompositeHeaderParameterAdder compositeAdder) { return GroupedOpenApi.builder() .addOperationCustomizer(compositeAdder) .build(); }
方案2:通过@Order注解指定Customizer执行顺序
如果需要保留多个独立的OperationCustomizer,可以使用@Order注解明确指定执行优先级,确保参数按期望顺序添加。
代码示例:
@Component @Order(1) // 优先级最高,最先执行 public class XXXHeaderParameterAdder implements OperationCustomizer { @Override public Operation customize(Operation operation, HandlerMethod handlerMethod) { Parameter param = new Parameter() .in(ParameterIn.HEADER.toString()) .name("parameterXXX") .schema(new Schema().type("string")) .required(true); operation.addParametersItem(param); return operation; } } @Component @Order(2) // 次之 public class YYYHeaderParameterAdder implements OperationCustomizer { // 实现逻辑同上,添加parameterYYY } @Component @Order(3) // 最后执行 public class ZZZHeaderParameterAdder implements OperationCustomizer { // 实现逻辑同上,添加parameterZZZ }
此时GroupedOpenApi的配置无需修改,springdoc会按@Order从小到大的顺序执行Customizer,参数会按添加顺序出现在OpenAPI定义中。
方案3:添加全局参数排序Customizer
创建一个最后执行的OperationCustomizer,对所有参数进行统一排序,强制符合预期顺序。
代码示例:
@Component @Order(Integer.MAX_VALUE) // 确保最后执行,覆盖之前的参数顺序 public class ParameterOrderingCustomizer implements OperationCustomizer { // 定义参数的预期顺序,先原生参数,再自定义Header参数 private static final List<String> EXPECTED_ORDER = Arrays.asList( "id", "parameterXXX", "parameterYYY", "parameterZZZ" ); @Override public Operation customize(Operation operation, HandlerMethod handlerMethod) { List<Parameter> params = operation.getParameters(); if (params == null || params.isEmpty()) { return operation; } List<Parameter> sortedParams = new ArrayList<>(); // 按预期顺序提取参数 for (String paramName : EXPECTED_ORDER) { params.stream() .filter(p -> paramName.equals(p.getName())) .findFirst() .ifPresent(sortedParams::add); } // 补充未在预期列表中的其他参数(如果有) params.stream() .filter(p -> !EXPECTED_ORDER.contains(p.getName())) .forEach(sortedParams::add); operation.setParameters(sortedParams); return operation; } }
将此Customizer添加到GroupedOpenApi配置中,即可强制参数按指定顺序排列。
问题原因
Spring Boot3版本的springdoc-openapi-starter-webmvc-ui对OperationCustomizer的执行顺序逻辑发生了变化:在Spring Boot2中,Customizer按addOperationCustomizer的调用顺序执行;而升级后,可能改为按Bean的注册逆序或集合遍历顺序反转执行,导致后添加的Customizer先执行,参数顺序随之颠倒。
内容的提问来源于stack exchange,提问作者Panicking Developer

