SpringCloudGateway+Discovery+Swagger 搭建服务文档中心

2021-12-07 16:32:22 浏览数 (1)

思路

  1. 在每个服务使用swagger暴露API定义信息
  2. 在SpringCloudGateway通过swagger-ui生成所有服务的文档并汇聚发布

效果

  • select a definition可选择不同服务打开对应服务的API文档
  • servers处服务地址为通过gateway路由访问的地址,隐藏服务真实地址

实现

版本

spring cloud 2020.3 swagger 3 springdoc-openapi 1.5.10

应用服务

依赖

代码语言:javascript复制
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-webmvc-core</artifactId>
    <version>1.5.10</version>
</dependency>
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-security</artifactId>
    <version>1.5.10</version>
</dependency>

配置

代码语言:javascript复制
@Bean
public GroupedOpenApi groupedApi() {
    return GroupedOpenApi.builder()
            .group("my-api")
            .pathsToMatch("/api/**")
            .build();
}

@Bean
public OpenAPI api() {
    return new OpenAPI()
            .info(new Info().title("My API")
                    .description("My sample application")
                    .version("v0.0.1")
                    .license(new License().name("Apache 2.0").url("https://blog.csdn.net/zhoudingding")))
            .externalDocs(new ExternalDocumentation()
                    .description("My Blog")
                    .url("https://blog.csdn.net/zhoudingding"));
}

效果

可通过/v3/api-docs访问API定义信息

网关服务

依赖

代码语言:javascript复制
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-webflux-ui</artifactId>
    <version>1.5.10</version>
</dependency>

配置

代码语言:javascript复制
@Configuration
public class SwaggerConfig {
    @Autowired
    RouteDefinitionLocator locator;
    @Autowired
    DiscoveryClient discoveryClient;
    @Autowired
    ApplicationContext applicationContext;

    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
	// 手动根据路由定义的服务,创建分组API文档
    @Bean
    public List<GroupedOpenApi> apis() {
        List<GroupedOpenApi> groups = new ArrayList<>();
        List<RouteDefinition> definitions = locator.getRouteDefinitions().collectList().block();
        definitions.stream().forEach(routeDefinition -> {
            String name = routeDefinition.getUri().getHost();
            GroupedOpenApi groupedOpenApi =
                    GroupedOpenApi.builder()
                            .group(name)
                            .pathsToMatch(
                                    routeDefinition.getPredicates().get(0).getArgs().get("pattern")
                            ).build();
            groups.add(groupedOpenApi);
        });
        return groups;
    }
	// 重载默认的多重API定义接口,如果请求的分组为注册的服务ID,则返回对应服务的API定义
    @Bean
    MultipleOpenApiWebFluxResource multipleOpenApiResource(List<GroupedOpenApi> groupedOpenApis,
                                                           ObjectFactory<OpenAPIService> defaultOpenAPIBuilder, AbstractRequestService requestBuilder,
                                                           GenericResponseService responseBuilder, OperationService operationParser,
                                                           RequestMappingInfoHandlerMapping requestMappingHandlerMapping,
                                                           SpringDocConfigProperties springDocConfigProperties,
                                                           Optional<ActuatorProvider> actuatorProvider) {

        return new MultipleOpenApiWebFluxResource(groupedOpenApis,
                defaultOpenAPIBuilder, requestBuilder,
                responseBuilder, operationParser,
                requestMappingHandlerMapping,
                springDocConfigProperties,
                actuatorProvider) {
            @Override
            public Mono<String> openapiJson(ServerHttpRequest serverHttpRequest, String apiDocsUrl, String group) throws JsonProcessingException {
                List<ServiceInstance> serviceInstances = discoveryClient.getInstances(group);
                if (CollectionUtils.isNotEmpty(serviceInstances)) {
                    String gatewayUri = serverHttpRequest.getURI().getScheme()   "://"   serverHttpRequest.getURI().getHost();
                    if (serverHttpRequest.getURI().getPort() != -1) {
                        gatewayUri  = ":"   serverHttpRequest.getURI().getPort();
                    }
                    gatewayUri  = "/"   group;
                    String serviceUri = serviceInstances.get(0).getUri().toString();
                    String url = serviceUri   "/v3/api-docs";
                    String openapiJson = restTemplate().getForObject(url, String.class);
                    openapiJson = openapiJson.replace(serviceUri, gatewayUri);
                    return Mono.just(openapiJson);
                }
                return super.openapiJson(serverHttpRequest, apiDocsUrl, group);
            }
        };
    }
}

注:以下gateway路由配置不会生效,因为对应路径会被openapi自动配置的请求映射优先处理

代码语言:javascript复制
spring:
  cloud:
    gateway:
      routes:
      - id: openapi
        uri: http://localhost:${server.port}
        predicates:
        - Path=/v3/api-docs/**
        filters:
        - RewritePath=/v3/api-docs/(?<path>.*), /${path}/v3/api-docs

0 人点赞