网关层聚合Swagger接口文档编码
由于各个微服务实例都已经聚合了 Swagger
接口文档且一切功能正常,因此这里不再赘述。下面以商城端网关为例,直接讲解如何在网关层聚合对应的微服务实例 Swagger
接口文档。
第一步,添加 Swagger3
依赖。
打开商城端网关 newbee-mall-cloud-gateway-mall
项目下的 pom.xml
文件,增加 Swagger3
依赖,新增代码如下:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
</dependency>
第二步,增加专门的路由配置来处理 Swagger
接口文档聚合。
网上关于 “Spring Cloud Gateway 聚合 Swagger
接口文档” 这个知识点的教程挺多,但是大部分是小案例,聚合时也是将配置文件中的所有路由配置都读取并做聚合。具体的业务实现中会有些不同,如当前项目中会对一个服务做两个路由配置,代码如下:
# 分类接口的路由配置
spring.cloud.gateway.routes[2].id=goods-service-route
spring.cloud.gateway.routes[2].uri=lb://newbee-mall-cloud-goods-service
spring.cloud.gateway.routes[2].order=1
spring.cloud.gateway.routes[2].predicates[0]=Path=/categories/mall/**
# 商品接口的路由配置
spring.cloud.gateway.routes[3].id=goods-service-route2
spring.cloud.gateway.routes[3].uri=lb://newbee-mall-cloud-goods-service
spring.cloud.gateway.routes[3].order=1
spring.cloud.gateway.routes[3].predicates[0]=Path=/goods/mall/**
其实这两个路由配置都指向商品微服务,如果读取所有路由,那么在网关层 Swagger UI
页面中就有重复的 Swagger
资源。因此,笔者在这里做了一些调整,增加了几条针对 Swagger
接口文档聚合的路由配置,在 newbee-mall-cloud-gateway-mall
项目下的 application.properties
文件中增加如下内容:
# 商品微服务 Swagger 接口文档的路由配置
spring.cloud.gateway.routes[7].id=goods-service-swagger-route
spring.cloud.gateway.routes[7].uri=lb://newbee-mall-cloud-goods-service
spring.cloud.gateway.routes[7].order=1
spring.cloud.gateway.routes[7].predicates[0]=Path=/goods/swagger/**
spring.cloud.gateway.routes[7].filters[0]=StripPrefix=2
# 推荐微服务 Swagger 接口文档的路由配置
spring.cloud.gateway.routes[8].id=recommend-service-swagger-route
spring.cloud.gateway.routes[8].uri=lb://newbee-mall-cloud-recommend-service
spring.cloud.gateway.routes[8].order=1
spring.cloud.gateway.routes[8].predicates[0]=Path=/indexConfigs/swagger/**
spring.cloud.gateway.routes[8].filters[0]=StripPrefix=2
# 订单微服务 Swagger 接口文档的路由配置
spring.cloud.gateway.routes[9].id=order-service-swagger-route
spring.cloud.gateway.routes[9].uri=lb://newbee-mall-cloud-order-service
spring.cloud.gateway.routes[9].order=1
spring.cloud.gateway.routes[9].predicates[0]=Path=/orders/swagger/**
spring.cloud.gateway.routes[9].filters[0]=StripPrefix=2
# 用户微服务 Swagger 接口文档的路由配置
spring.cloud.gateway.routes[10].id=user-service-swagger-route
spring.cloud.gateway.routes[10].uri=lb://newbee-mall-cloud-user-service
spring.cloud.gateway.routes[10].order=1
spring.cloud.gateway.routes[10].predicates[0]=Path=/users/swagger/**
spring.cloud.gateway.routes[10].filters[0]=StripPrefix=2
# 购物车微服务 Swagger 接口文档的路由配置
spring.cloud.gateway.routes[11].id=shop-cart-service-swagger-route
spring.cloud.gateway.routes[11].uri=lb://newbee-mall-cloud-shop-cart-service
spring.cloud.gateway.routes[11].order=1
spring.cloud.gateway.routes[11].predicates[0]=Path=/carts/swagger/**
spring.cloud.gateway.routes[11].filters[0]=StripPrefix=2
第三步,增加聚合配置类。
在 ltd.gateway.cloud.newbee.config
包下新建 PolymerizeSwaggerProvider
配置类,重写 get()
方法,代码如下:
package ltd.gateway.cloud.newbee.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
import java.util.ArrayList;
import java.util.List;
/**
* 在网关层聚合微服务的 Swagger 资源
*/
@Primary
@Component
public class PolymerizeSwaggerProvider implements SwaggerResourcesProvider {
/**
* Swagger Doc 的 URL 后缀
*/
public static final String API_DOCS_URL = "/v3/api-docs";
@Autowired
private GatewayProperties gatewayProperties;
@Override
public List<SwaggerResource> get() {
List<SwaggerResource> resources = new ArrayList<>();
List<String> routes = new ArrayList<>();
//需要聚合的服务路由配置
routes.add("user-service-swagger-route");
routes.add("recommend-service-swagger-route");
routes.add("goods-service-swagger-route");
routes.add("order-service-swagger-route");
routes.add("shop-cart-service-swagger-route");
gatewayProperties.getRoutes().stream().filter(routeDefinition ->
routes.contains(routeDefinition.getId())).forEach(routeDefinition -> routeDefinition.getPredicates().stream()
.filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
.forEach(predicateDefinition -> {
resources.add (swaggerResource(routeDefinition.getId(),
predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0")
.replace("/**", API_DOCS_URL)));
return resources;
});
}
private SwaggerResource swaggerResource(String name, String url) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(url);
swaggerResource.setSwaggerVersion("3.0");
return swaggerResource;
}
}
这样,网关层 Swagger UI
页面在加载时请求的 /swagger-resources
得到的就不再是一条数据,而是上述代码中根据 5 条路由信息整合后的 5 条 Swagger
资源了。更通俗一些理解,就是将 http://localhost:29000/v3/api-docs、http://localhost:29010/v3/api-docs、http://localhost:29020/v3/api-docs、http://localhost:29030/v3/api-docs、http://localhost:29040/v3/api-docs 这 5 个 URL
组装到 Swagger
资源列表中。
第四步,网关层过滤器对 Swagger
资源聚合请求放行。
由于网关层都做了全局拦截器,因此对获取具体的 Swagger
接口信息的请求要放行,否则这些请求无法正常读取到数据。
在 ValidMallUserTokenGlobalFilter
类下的 filter()
方法中增加如下代码:
ignoreURLs.add("/indexConfigs/swagger/v3/api-docs");
ignoreURLs.add("/carts/swagger/v3/api-docs");
ignoreURLs.add("/orders/swagger/v3/api-docs");
ignoreURLs.add("/users/swagger/v3/api-docs");
ignoreURLs.add("/goods/swagger/v3/api-docs");
后台管理系统网关中聚合 Swagger
资源的编码步骤与此一致,这里不再赘述,读者可以直接下载本节源代码查看和学习。
最后来看一下实际效果。依次启动各个微服务架构项目及商城端网关,在浏览器中输入网关层 Swagger UI
页面的网址: http://localhost:29110/swagger-ui/index.html。
聚合后的接口文档页面如图 9-3 所示。

从图 9-3 中可以看出,Swagger UI
页面在加载时,对 /swagger-resources
请求得到的不再是一条数据,而是上述代码中根据 5 条路由信息整合后的 5 条 Swagger
资源,与预期的效果一致,编码完成。
网关层聚合 Swagger
资源虽然不是一个特别复杂的知识点,却是企业开发中或真实的项目开发中不可缺少的一个步骤。在本章中,笔者介绍了聚合的原因、实现思路及具体的实现原理,目的是让读者更了解整个流程,而不是给几行代码让读者知道是怎么做的,却不知道为什么要这样编码。当然,本章还根据实战项目做了一些编码调整,并没有直接读取所有的路由配置来组装 Swagger
资源,毕竟不同的项目有不同的实现方式。
本章主要是在微服务架构项目中加入 “网关层聚合 Swagger
资源” 相关编码,对实战部分的讲解做补充和优化。希望读者能够根据笔者提供的开发步骤顺利地完成本章的项目改造。