第二十一节 在Springboot2项目中的gateway网关集成knif4j统一文档

亮子 | 2025-12-02 09:12:14 | 107 | 0 | 0 | 0

Spring Boot 2.x + Spring Cloud Gateway(基于 WebFlux) 的项目中集成 Knife4j,由于 Spring Boot 2 使用的是 Servlet API(javax) 而不是 Jakarta,且 Gateway 是响应式(WebFlux)架构,不能直接使用传统的 Swagger2(Springfox),推荐使用 Springdoc OpenAPI v1.x + Knife4j 3.x 的组合。

✅ 注意:Spring Boot 2.x 不兼容 Knife4j 4.x(Jakarta 版本),必须使用 Knife4j 3.x


🧩 一、整体思路

  1. 各微服务(如 user-service)使用 springdoc-openapi-webmvc-core 暴露 /v3/api-docs
  2. 网关(Gateway)通过路由转发访问各服务的 OpenAPI 文档;
  3. 网关自身集成 springdoc-openapi-webflux + knife4j-spring-boot-starter(3.x)提供统一 UI;
  4. 使用 GroupedOpenApi 聚合多个服务的文档。

🔧 二、微服务端配置(以 user-service 为例)

1. 添加依赖(Spring Boot 2.x)

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-webmvc-core</artifactId>
    <version>1.7.0</version>
</dependency>

<!-- 可选:如果需要 Swagger UI(微服务单独访问) -->
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-ui</artifactId>
    <version>1.7.0</version>
</dependency>

2. 配置(application.yml)

springdoc:
  api-docs:
    path: /v3/api-docs
  swagger-ui:
    path: /swagger-ui.html

启动后可通过 http://user-service:port/v3/api-docs 获取 JSON 文档。


🔧 三、网关(Gateway)端集成 Knife4j

1. 添加依赖(关键!使用 Knife4j 3.x)

<!-- Springdoc WebFlux 支持(用于 Gateway) -->
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-webflux-core</artifactId>
    <version>1.7.0</version>
</dependency>

<!-- Knife4j 增强 UI(Spring Boot 2 兼容版) -->
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-boot-starter</artifactId>
    <version>3.0.3</version> <!-- 最高支持到 3.x -->
</dependency>

⚠️ 切勿使用 knife4j-openapi3-jakarta-spring-boot-starter(这是给 Spring Boot 3 用的)!


2. 配置 Gateway 路由(application.yml)

确保能访问下游服务的 OpenAPI 文档:

spring:
  cloud:
    gateway:
      routes:
        # 用户服务
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/user-service/**
          filters:
            - StripPrefix=1

        # 订单服务
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/order-service/**
          filters:
            - StripPrefix=1

        # 转发 Swagger 文档(关键!)
        - id: user-service-api-docs
          uri: lb://user-service
          predicates:
            - Path=/user-service/v3/api-docs

        - id: order-service-api-docs
          uri: lb://order-service
          predicates:
            - Path=/order-service/v3/api-docs

这样可以通过:
- http://gateway:port/user-service/v3/api-docs
- http://gateway:port/order-service/v3/api-docs

访问各服务的 OpenAPI 文档。


3. 创建聚合配置类(SwaggerResourceConfig)

在网关项目中创建如下配置类:

@Configuration
public class SwaggerResourceConfig {

    // 手动定义需要聚合的服务列表
    private static final List<String> SERVICES = Arrays.asList("user-service", "order-service");

    @Bean
    public RouteLocator routeLocator(RouteLocatorBuilder builder) {
        return builder.routes().build(); // 仅用于注入 RouteLocator
    }

    /**
     * 提供聚合后的 OpenAPI 资源(用于 Knife4j 分组)
     */
    @Bean
    public List<GroupedOpenApi> groupedOpenApis() {
        return SERVICES.stream()
            .map(serviceName -> GroupedOpenApi.builder()
                .group(serviceName)
                .pathsToMatch("/" + serviceName + "/**")
                .build())
            .collect(Collectors.toList());
    }
}

说明:GroupedOpenApi 会自动为每个 group 生成对应的 /v3/api-docs/{groupName},但实际文档仍需通过路由转发到下游服务。因此更推荐使用 自定义 OpenAPI 聚合方式(见下文进阶方案)


🔄 四、【推荐】进阶方案:自定义聚合 OpenAPI 文档(解决 GroupedOpenApi 无法拉取远程文档的问题)

⚠️ 注意:GroupedOpenApi 在 Gateway 中 不会自动拉取远程服务的 OpenAPI 内容,它只适用于本地 Controller。
因此,要真正聚合多个微服务的文档,需要 手动拉取远程 /v3/api-docs 并合并

方案:使用 SwaggerResourcesProvider(兼容 Springdoc)

但由于 Springdoc 已取代 Swagger2,更推荐使用 knife4j-gateway 官方提供的聚合方式。

✅ 推荐做法:使用 knife4j 提供的 OpenApiAggregator

  1. 添加工具类(用于拉取远程 OpenAPI):
@Component
@RequiredArgsConstructor
public class OpenApiAggregator {

    private final WebClient.Builder webClientBuilder;

    public Map<String, Object> getOpenApiFromService(String serviceUrl) {
        WebClient client = webClientBuilder.build();
        try {
            return client.get()
                .uri(serviceUrl + "/v3/api-docs")
                .retrieve()
                .bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {})
                .block(Duration.ofSeconds(5));
        } catch (Exception e) {
            log.warn("Failed to fetch OpenAPI from {}", serviceUrl, e);
            return Collections.emptyMap();
        }
    }
}
  1. 创建一个 Controller 暴露聚合接口(可选,用于调试)

但更简单的方式是:**直接让 Knife4j UI 通过网关路由访问各服务的 /v3/api-docs**,并在前端选择不同服务。


🌐 五、启用 Knife4j UI 并访问

1. 配置 Knife4j(application.yml)

knife4j:
  enable: true
  production: false
  basic:
    enable: true
    username: admin
    password: 123456

2. 访问地址

启动网关后,访问:

http://localhost:8080/doc.html

在 Knife4j 页面顶部的 “分组”下拉框 中,会显示 user-serviceorder-service 等分组(前提是配置了 GroupedOpenApi)。

💡 但注意:此时点击分组,Knife4j 会请求 /v3/api-docs/user-service,而该路径在网关本地并不存在!

✅ 正确做法:**不依赖 GroupedOpenApi 聚合,而是直接在 doc.html 中配置多个文档地址**

替代方案:使用 Knife4j 的 多实例文档 功能

doc.html 页面中,Knife4j 支持手动添加多个 OpenAPI 地址:

  1. 访问 http://gateway:8080/doc.html
  2. 点击右上角 “文档管理”(或“离线文档”图标)
  3. 添加多个 URL:
  • 名称:用户服务,URL:/user-service/v3/api-docs
  • 名称:订单服务,URL:/order-service/v3/api-docs

即可切换查看不同服务的 API。

这是最简单、最可靠的方式,无需复杂聚合逻辑。


✅ 六、最终建议配置总结

组件 依赖版本
Spring Boot 2.7.x
Spring Cloud 2021.0.x
springdoc-openapi 1.7.0
knife4j-spring-boot-starter 3.0.3

网关核心依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-webflux-core</artifactId>
    <version>1.7.0</version>
</dependency>
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-boot-starter</artifactId>
    <version>3.0.3</version>
</dependency>

路由配置确保 /xxx/v3/api-docs 可访问;

直接通过 doc.html 手动添加多个文档地址,实现聚合效果。


📚 参考资料

  • Knife4j 官方文档(Spring Boot 2 示例):https://doc.xiaominfo.com/knife4j/documentation/
  • Springdoc OpenAPI for WebFlux:https://springdoc.org/

如有需要,也可考虑使用 smart-doc + [smart-doc-maven-plugin] 自动生成静态文档,避免运行时聚合问题。