SpringCloudGateway+Discovery+Swagger 搭建服务文档中心
思路
- 在每个服务使用swagger暴露API定义信息
- 在SpringCloudGateway通过swagger-ui生成所有服务的文档并汇聚发布
效果
- select a definition可选择不同服务打开对应服务的API文档
- servers处服务地址为通过gateway路由访问的地址,隐藏服务真实地址
实现
版本
spring cloud 2020.3
swagger 3
springdoc-openapi 1.5.10
应用服务
依赖
<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>
配置
@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定义信息
网关服务
依赖
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webflux-ui</artifactId>
<version>1.5.10</version>
</dependency>
配置
@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自动配置的请求映射优先处理
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