没有做 API 文档聚合,访问每个服务的 API 文档都需要访问单独的 swagger-ui.html
页面,既然我们使用了微服务,就应该有统一的 API 文档入口,而 knife4j
有这方面的支持,本文将详细介绍其实现,希望对大家有所帮助!
我们将采用 Nacos 作为注册中心,Gateway 作为网关,使用 knife4j
来生成 API 文档。
应用架构
我们理想的解决方案应该是这样的,网关作为 API 文档的统一入口,网关聚合所有微服务的文档,通过在网关进行切换来实现对其他服务 API 文档的访问。
相关服务划分:
knife4j-gateway:网关服务,作为微服务 API 文档的访问入口,聚合所有 API 文档,需要引入文档前端 UI 包;
knife4j-user:用户服务,普通 API 服务,不需要引入文档前端 UI 包;
knife4j-order:订单服务,普通 API 服务,不需要引入文档前端 UI 包。
具体实现
下面详细介绍下 Spring Cloud Gateway + knife4j 聚合 API 文档的具体实现,依次搭建用户服务、订单服务和网关服务。
创建 knife4j-user 项目模块 我们首先来搭建用户服务,一个普通的 API 服务,很简单,仅需三步即可集成 knife4j。
在 pom.xml 中添加相关依赖,一个 Spring Boot 的 web 功能依赖,knife4j 的微服务依赖(不包含 API 文档的前端 UI 包):
1 2 3 4 5 6 7 8 9 10 <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > com.github.xiaoymin</groupId > <artifactId > knife4j-micro-spring-boot-starter</artifactId > </dependency > </dependencies >
在 application.yml
中添加相关配置,配置一下 Nacos 注册中心即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 server: port: 9501 spring: profiles: active: dev application: name: knife4j-user cloud: nacos: discovery: server-addr: localhost:8848 management: endpoints: web: exposure: include: "*"
添加 Swagger 相关配置,非常常规的配置,添加 @EnableKnife4j
注解开启 knife4j 的增强功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Configuration @EnableSwagger 2@EnableKnife 4jpublic class Swagger2Config { @Bean public Docket createRestApi () { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.macro.cloud.controller" )) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo () { return new ApiInfoBuilder() .title("knife4j-user" ) .description("用户服务API文档" ) .contact("antonio" ) .version("1.0" ) .build(); } }
创建 knife4j-order 项目模块 我们接下来搭建订单服务,一个普通的 API 服务,直接参考上面用户服务的搭建即可。
创建 knife4j-gateway 项目模块 最后我们搭建网关服务,作为微服务 API 文档的的统一入口,聚合所有微服务的 API 文档。
在 pom.xml 中添加相关依赖,Gateway 相关依赖和 knife4 j的 Starter(包含 API 文档的前端 UI 包):
1 2 3 4 5 6 7 8 9 10 <dependencies > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-gateway</artifactId > </dependency > <dependency > <groupId > com.github.xiaoymin</groupId > <artifactId > knife4j-spring-boot-starter</artifactId > </dependency > </dependencies >
在 application.yml
这添加相关配置,配置一下 Nacos 注册中心,用户服务和订单服务的路由即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 server: port: 9201 spring: profiles: active: dev application: name: knife4j-gateway cloud: nacos: discovery: server-addr: localhost:8848 gateway: routes: - id: user-service uri: lb://knife4j-user predicates: - Path=/user-service/** filters: - StripPrefix=1 - id: order-service uri: lb://knife4j-order predicates: - Path=/order-service/** filters: - StripPrefix=1 discovery: locator: enabled: true lower-case-service-id: true
在网关上添加 Swagger 资源配置,用于聚合其他微服务中 Swagger 的 api-docs
访问路径:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 @Slf 4j@Component @Primary @AllArgsConstructor public class SwaggerResourceConfig implements SwaggerResourcesProvider { private final RouteLocator routeLocator; private final GatewayProperties gatewayProperties; @Override public List<SwaggerResource> get () { List<SwaggerResource> resources = new ArrayList<>(); List<String> routes = new ArrayList<>(); routeLocator.getRoutes().subscribe(route -> routes.add(route.getId())); gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId())).forEach(route -> { route.getPredicates().stream() .filter(predicateDefinition -> ("Path" ).equalsIgnoreCase(predicateDefinition.getName())) .forEach(predicateDefinition -> resources.add(swaggerResource(route.getId(), predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0" ) .replace("**" , "v2/api-docs" )))); }); return resources; } private SwaggerResource swaggerResource (String name, String location) { log.info("name:{},location:{}" , name, location); SwaggerResource swaggerResource = new SwaggerResource(); swaggerResource.setName(name); swaggerResource.setLocation(location); swaggerResource.setSwaggerVersion("2.0" ); return swaggerResource; } }
什么是 Swagger 的 api-docs
访问路径?该路径会返回 JSON 格式数据,Swagger 渲染 API 文档页面的所有数据就是来源于此,比如我们的用户服务会返回如下信息,访问地址:http://localhost:9201/user-service/v2/api-docs
接下来我们需要自定义 Swagger 各个配置的节点,简单来说就是自定义 Swagger 内部的各个获取数据的接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 @RestController public class SwaggerHandler { @Autowired (required = false ) private SecurityConfiguration securityConfiguration; @Autowired (required = false ) private UiConfiguration uiConfiguration; private final SwaggerResourcesProvider swaggerResources; @Autowired public SwaggerHandler (SwaggerResourcesProvider swaggerResources) { this .swaggerResources = swaggerResources; } @GetMapping ("/swagger-resources/configuration/security" ) public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() { return Mono.just(new ResponseEntity<>( Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK)); } @GetMapping ("/swagger-resources/configuration/ui" ) public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() { return Mono.just(new ResponseEntity<>( Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK)); } @GetMapping ("/swagger-resources" ) public Mono<ResponseEntity> swaggerResources () { return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK))); } }
比如说 swagger-resources
这个接口,可用于获取所有微服务的 api-docs
访问路径,获取信息如下,访问地址:http://localhost:9201/swagger-resources
功能演示
接下来我们来演示下微服务 API 文档聚合的功能,仅需要访问网关的 API 文档页面即可,可自行切换到相关服务的 API 文档。
在此之前先启动我们的 Nacos 注册中心,然后依次启动 knife4j-user
、knife4j-order
及 knife4j-gateway
服务:
从网关访问 API 文档,访问地址:http://localhost:9201/doc.html
我们通过左上角的切换组件即可切换到对应服务的API文档:
查看 API 文档,我们可以发现所有接口都已经添加了对应的访问前缀,可以正常访问。
切换回 Swagger UI
如果你不想使用 knife4j 的界面,想用原来的 Swagger 界面,也是可以支持的,切换方法非常简单,下面我们来讲讲。
首先我们需要在 pom.xml
中去除 knife4j 的相关依赖,主要就是下面两个依赖:
1 2 3 4 5 6 7 8 <dependency > <groupId > com.github.xiaoymin</groupId > <artifactId > knife4j-micro-spring-boot-starter</artifactId > </dependency > <dependency > <groupId > com.github.xiaoymin</groupId > <artifactId > knife4j-spring-boot-starter</artifactId > </dependency >
在 pom.xml
中添加 Swagger 相关依赖,并去除原来使用的 @EnableKnife4j
注解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <dependencies > <dependency > <groupId > io.springfox</groupId > <artifactId > springfox-swagger2</artifactId > <version > 2.9.2</version > </dependency > <dependency > <groupId > io.springfox</groupId > <artifactId > springfox-swagger-ui</artifactId > <version > 2.9.2</version > </dependency > <dependency > <groupId > io.swagger</groupId > <artifactId > swagger-models</artifactId > <version > 1.6.0</version > </dependency > <dependency > <groupId > io.swagger</groupId > <artifactId > swagger-annotations</artifactId > <version > 1.6.0</version > </dependency > </dependencies >
重新启动所有服务,访问网关的 API 文档路径即可查看:http://localhost:9201/swagger-ui.html
更多干货请移步:https://antoniopeng.com
If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !