如何为GroupedOpenApi设置特定前缀调整Springdoc OpenAPI上下文路径
解决方案:为特定GroupedOpenApi移除路径前缀
要实现将GroupedOpenApi的路径前缀(如/v1/legacy-api-1)从OpenAPI定义和Swagger-UI的操作路径中移除,同时保留servers配置,核心是通过自定义OpenApiCustomiser对分组后的路径进行批量替换。
步骤1:实现路径前缀移除的自定义器
创建一个通用的自定义处理器,接收要移除的前缀参数,遍历并修改OpenAPI的路径集合:
import org.springdoc.core.customizers.OpenApiCustomiser; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.PathItem; import java.util.HashMap; import java.util.Map; public class PathPrefixRemoverCustomiser implements OpenApiCustomiser { private final String prefixToRemove; public PathPrefixRemoverCustomiser(String prefixToRemove) { // 统一前缀格式,确保以/开头,避免匹配错误 this.prefixToRemove = prefixToRemove.startsWith("/") ? prefixToRemove : "/" + prefixToRemove; } @Override public void customise(OpenAPI openApi) { Map<String, PathItem> modifiedPaths = new HashMap<>(); openApi.getPaths().forEach((path, pathItem) -> { // 移除指定前缀,保留剩余路径部分 if (path.startsWith(prefixToRemove)) { String newPath = path.substring(prefixToRemove.length()); // 处理移除前缀后为空的情况,替换为根路径/ modifiedPaths.put(newPath.isEmpty() ? "/" : newPath, pathItem); } else { modifiedPaths.put(path, pathItem); } }); openApi.setPaths(modifiedPaths); } }
步骤2:配置GroupedOpenApi时引入自定义器
在创建每个GroupedOpenApi的Bean时,将自定义器与servers配置结合,针对不同分组单独处理:
import org.springdoc.core.GroupedOpenApi; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import io.swagger.v3.oas.models.servers.Server; import java.util.List; @Configuration public class OpenApiConfig { // 替换为实际的环境变量或配置值 private static final String API_MANAGER_BASE_URL = "{API_MANAGER_BASE_URL}"; private static final String OLD_LEGACY_API_1_URL = "{OLD_LEGACY_API_1_URL}"; private static final String CONSOLIDATED_API_BASE_URL = "{CONSOLIDATED_API_BASE_URL}"; @Bean public GroupedOpenApi legacyApi1Group() { String targetPrefix = "/v1/legacy-api-1"; return GroupedOpenApi.builder() .group("legacy-api-1") .pathsToMatch(targetPrefix + "/**") // 过滤该分组的路径 .addOpenApiCustomiser(new PathPrefixRemoverCustomiser(targetPrefix)) // 移除前缀 .addOpenApiCustomiser(openApi -> { // 保留原有的servers配置 List<Server> servers = List.of( new Server().url(API_MANAGER_BASE_URL + "/legacy-api-1"), new Server().url(OLD_LEGACY_API_1_URL), new Server().url(CONSOLIDATED_API_BASE_URL + targetPrefix) ); openApi.setServers(servers); }) .build(); } // 同理配置legacy-api-2分组 @Bean public GroupedOpenApi legacyApi2Group() { String targetPrefix = "/v1/legacy-api-2"; return GroupedOpenApi.builder() .group("legacy-api-2") .pathsToMatch(targetPrefix + "/**") .addOpenApiCustomiser(new PathPrefixRemoverCustomiser(targetPrefix)) .addOpenApiCustomiser(openApi -> { List<Server> servers = List.of( new Server().url(API_MANAGER_BASE_URL + "/legacy-api-2"), new Server().url("{OLD_LEGACY_API_2_URL}"), new Server().url(CONSOLIDATED_API_BASE_URL + targetPrefix) ); openApi.setServers(servers); }) .build(); } // v2 API分组可按需选择是否移除前缀 @Bean public GroupedOpenApi v2ApiGroup() { String targetPrefix = "/v2"; return GroupedOpenApi.builder() .group("v2-api") .pathsToMatch(targetPrefix + "/**") // 如果不需要移除v2前缀,注释掉下面一行 // .addOpenApiCustomiser(new PathPrefixRemoverCustomiser(targetPrefix)) .addOpenApiCustomiser(openApi -> { List<Server> servers = List.of( new Server().url(CONSOLIDATED_API_BASE_URL + targetPrefix) ); openApi.setServers(servers); }) .build(); } }
关键说明
- 分组隔离:自定义器仅作用于当前GroupedOpenApi的路径,不会影响其他分组的API定义
- 路径兼容性:自动处理前缀格式和空路径场景,符合OpenAPI规范
- 无侵入性:无需修改原@RestController的@RequestMapping配置,仅通过OpenAPI自定义逻辑调整展示效果
- 调用正确性:servers配置中的URL已包含完整的前缀/转发地址,Swagger-UI调用时会自动拼接成正确的请求URL(如
{API_MANAGER_BASE_URL}/legacy-api-1/document)
内容的提问来源于stack exchange,提问作者Sean Dukehart
相关产品推荐
相关产品推荐

