SpringCloud微服务实战——搭建企业级开发框架(十九):Gateway使用knife4j聚合微服务文档

  本章介绍Spring Cloud Gateway网关如何集成knife4j,通过网关聚合所有的Swagger微服务文档

1、gitegg-gateway中引入knife4j依赖,如果没有后端代码编写的话,仅仅引入一个swagger的前端ui模块就可以了

        <dependency>
<groupid>io.springfox</groupid>
<artifactid>springfox-swagger2</artifactid>
</dependency>
<dependency>
<groupid>com.github.xiaoymin</groupid>
<artifactid>knife4j-spring-ui</artifactid>
</dependency>

2、修改配置文件,增加knife4j、Swagger2的配置

server:
port: 80
spring:
application:
name: gitegg-service-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
group: DEFAULT_GROUP
enabled: true
gateway:
discovery:
locator:
enabled: true
routes:
- id: gitegg-service-system
uri: lb://gitegg-service-system
predicates:
- Path=/gitegg-system/**
filters:
- SwaggerHeaderFilter
- StripPrefix=1
- id: gitegg-service-base
uri: lb://gitegg-service-base
predicates:
- Path=/gitegg-base/**
filters:
- SwaggerHeaderFilter
- StripPrefix=1
文档聚合业务编码

在我们使用Spring Boot等单体架构集成swagger项目时,是通过对包路径进行业务分组,然后在前端进行不同模块的展示,而在微服务架构下,我们的一个服务就类似于原来我们写的一个业务组

springfox-swagger提供的分组接口是swagger-resource,返回的是分组接口名称、地址等信息

在Spring Cloud微服务架构下,我们需要重写该接口,主要是通过网关的注册中心动态发现所有的微服务文档,代码如下:

package com.gitegg.gateway.config;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.route.RouteLocator;
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; @Slf4j
@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?group=1.X版本"))));
}); 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("1.0.0");
return swaggerResource;
}
}
package com.gitegg.gateway.filter;

import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange; @Component
public class SwaggerHeaderFilter extends AbstractGatewayFilterFactory {
private static final String HEADER_NAME = "X-Forwarded-Prefix"; private static final String URI = "/v2/api-docs"; @Override
public GatewayFilter apply(Object config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
if (!StringUtils.endsWithIgnoreCase(path,URI )) {
return chain.filter(exchange);
}
String basePath = path.substring(0, path.lastIndexOf(URI));
ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, basePath).build();
ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
return chain.filter(newExchange);
};
}
}
package com.gitegg.gateway.handler;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.*; import java.util.Optional; @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)));
}
}

3、访问gitegg-gateway服务地址http://127.0.0.1/doc.html,可以看到聚合后的文档

SpringCloud微服务实战——搭建企业级开发框架(十九):Gateway使用knife4j聚合微服务文档

本文源码在https://gitee.com/wmz1930/GitEgg 的chapter-19分支。

上一篇:SpringCloud微服务实战——搭建企业级开发框架(十六):集成Sentinel高可用流量管理框架【自定义返回消息】


下一篇:SpringCloud微服务实战——搭建企业级开发框架(十):使用Nacos分布式配置中心