SpringBoot中OpenAPI在Swagger文档生成重复API问题
- Java: 21
- SpringBoot: 3.2.1
OpenApi依赖
<dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <version>2.1.0</version> </dependency>
OpenAPI YAML 文件内容
openapi: 3.0.3 info: title: 示例接口集 description: |- 一组简单的示例API集合 version: 1.0-SNAPSHOT servers: - url: http://127.0.1:8091/api/v1 description: 本地服务器(使用测试数据) - url: https://example-dev.com/api/v1 description: UAT服务器(使用测试数据) - url: https://example.com/api/v1 description: 生产服务器(使用真实数据) tags: - name: 示例 description: 示例接口 paths: /examples: get: summary: 获取示例数据 description: 获取示例数据 operationId: getExample responses: 200: description: 请求成功 content: application/json: schema: $ref: '#/components/schemas/Example' 404: description: 未找到目标数据 content: application/json: schema: $ref: '#/components/schemas/ExampleNotFoundError' components: schemas: Example: type: object properties: creatorId: type: string description: 创建者ID hipiCoins: type: number description: 虚拟货币数量 ExampleNotFoundError: type: object properties: creatorId: type: string description: 创建者ID hipiCoins: type: number description: 虚拟货币数量
Controller 代码
@Generated( value = "org.openapitools.codegen.languages.SpringCodegen", date = "2024-01-15T23:26:32.308871+05:30[Asia/Kolkata]") @Controller public class ExampleController implements ExampleApi { private final ExampleApiDelegate delegate; public ExampleController( @org.springframework.beans.factory.annotation.Autowired(required = false) ExampleApiDelegate delegate) { this.delegate = Optional.ofNullable(delegate).orElse(new ExampleApiDelegate() {}); } @Override public ExampleApiDelegate getDelegate() { return delegate; } }
Application.properties 配置
spring.application.name=example-service server.port=8091 springdoc.enable-native-support=true springdoc.swagger-ui.path=/swagger-ui logging.level.root=INFO
Swagger文档中同时展示了两个重复的API接口:GET /api/v1/examples 和 GET /examples,需求是仅保留带前缀的GET /api/v1/examples接口,但尝试过Stack Overflow上的相关解决方案后仍未解决该问题。
出现重复接口的核心原因是:OpenAPI YAML定义的基础路径为/examples,同时Spring Boot自动扫描生成了不带前缀的接口,再加上servers配置中的/api/v1前缀,导致两种路径都被渲染到Swagger文档中。以下是几种可行的解决方式:
方式一:配置Spring Boot上下文路径
在application.properties中添加上下文路径配置,让所有接口自动带上/api/v1前缀:
server.servlet.context-path=/api/v1
此配置会让Spring Boot的所有接口统一使用该前缀,OpenAPI文档会自动匹配该路径,不再展示不带前缀的/examples接口。
方式二:指定springdoc的接口文档路径前缀
如果不想修改全局上下文路径,可以单独配置springdoc的接口文档路径:
springdoc.api-docs.path=/api/v1/v3/api-docs springdoc.swagger-ui.url=/api/v1/v3/api-docs
确保该前缀与OpenAPI YAML中servers配置的路径一致,Swagger UI就只会加载带前缀的接口文档。
方式三:调整OpenAPI Generator生成参数
如果接口代码是通过OpenAPI Generator生成的,在生成时可以指定api-prefix参数,让生成的接口自动带上/api/v1前缀:
--api-prefix /api/v1
这样生成的ExampleApi接口会直接包含前缀,不会出现不带前缀的路径定义。
方式四:自定义过滤规则移除无效路径
如果以上方法都不生效,可以通过自定义OpenApiCustomiser过滤掉不带前缀的路径:
import org.springdoc.core.customizers.OpenApiCustomiser; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class OpenApiConfig { @Bean public OpenApiCustomiser removeNonPrefixedPaths() { return openApi -> { openApi.getPaths().keySet().removeIf(path -> !path.startsWith("/api/v1")); }; } }
该配置会移除所有不以/api/v1开头的路径,确保Swagger文档中只保留符合要求的接口。
内容的提问来源于stack exchange,提问作者Prafulla Kumar Sahu

