每个服务都有自己的接口,通过 Swagger 来管理接口文档。在服务较多的时候我们希望有一个统一的入口来进行文档的查看,这个时候可以在 zuul 中进行文档的聚合显示。
下面来看下具体的整合步骤以及采坑记录。Cloud 版本:Finchley.SR2,Boot 版本:2.0.6
加入 Swagger 的依赖:
<!-- Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
增加聚合代码:
@EnableSwagger2
@Component
@Primary
public class DocumentationConfig implements SwaggerResourcesProvider {
@Autowired
private DiscoveryClient discoveryClient;
@Value("${spring.application.name}")
private String applicationName;
@Override
public List<SwaggerResource> get() {List<SwaggerResource> resources = new ArrayList<>();
// 排除自身,将其他的服务添加进去
discoveryClient.getServices().stream().filter(s -> !s.equals(applicationName)).forEach(name -> {resources.add(swaggerResource(name, "/" + name + "/v2/api-docs", "2.0"));
});
return resources;
}
private SwaggerResource swaggerResource(String name, String location, String version) {SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion(version);
return swaggerResource;
}
}
我这边直接用 DiscoveryClient 获取服务列表进行聚合,当然你也可以固定写上你的服务列表,或者对接配置中心都可以。
其实除了 DiscoveryClient 获取服务列表,我们也可以根据 zuul 中路由的配置来获取,可以使用 RouteLocator 来操作。方式很多,用哪种都可以。
正常情况下上面的整合步骤没任何问题,今天有朋友在星球提问,说自己的业务服务加了 context-path,Zull 中聚合的 Swagger 文档无法显示,因为路径错了,少了配置的 context-path。效果如下图:
也就是说在进行资源添加的时候需要将 context-path 加进去,也就是需要改动下面的代码:
resources.add(swaggerResource(name, "/" + name + "/v2/api-docs", "2.0"));
最简单的就是加一个配置,配置好每个服务对应的 context-path,这样在这里直接拼接上去就完事了。但这样显得有点低端呀,哈哈。
DiscoveryClient 是很强大的,我们可以用 DiscoveryClient 来获取 Eureka 中的信息,此时我有了一个想法,那就是业务服务将自身的 context-path 放入 Eureka 的 metadata-map 中,然后 Zuul 中聚合的时候从 metadata-map 中获取 context-path 就行了。
业务服务加配置:
server.servlet.context-path=/yinjihuan
eureka.instance.metadata-map.context-path=${server.servlet.context-path}
Zull 中改造:
@Override
public List<SwaggerResource> get() {List<SwaggerResource> resources = new ArrayList<>();
// 排除自身,将其他的服务添加进去
discoveryClient.getServices().stream().filter(s -> !s.equals(applicationName)).forEach(name -> {Optional<ServiceInstance> instanceOptional = discoveryClient.getInstances(name).stream().findFirst();
if (instanceOptional.isPresent() && instanceOptional.get().getMetadata().containsKey("context-path")) {String contexPath = instanceOptional.get().getMetadata().get("context-path");
resources.add(swaggerResource(name, "/" + name + contexPath + "/v2/api-docs", "2.0"));
} else {resources.add(swaggerResource(name, "/" + name + "/v2/api-docs", "2.0"));
}
});
return resources;
}
这样就完美解决了增加 context-path 导致的问题,加入星球我们一起学习吧。
欢迎加入我的知识星球,一起交流技术,免费学习猿天地的课程(http://cxytiandi.com/course)
PS:目前星球中正在星主的带领下组队学习 Spring Cloud,等你哦!