概要
现在相信大部分公司的系统架构都是分布式,微服务 ,在使用swagger文档时,前后端联调或者测试接口每次都要打开各个微服务的文档去找对应的接口比较麻烦,在这里给大家讲讲如何在gateway中集成各个服务的接口文档
整体技术方案
使用gateway+nacos+swagger集成微服务接口文档
实现步骤
- 业务服务集成swagger文档
@Configuration
@EnableSwagger2WebMvc
public class Knife4jConfiguration {
@Bean(value = "defaultApi2")
public Docket defaultApi2() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
//.title("swagger-bootstrap-ui-demo RESTful APIs")
.description("# swagger-bootstrap-ui-demo RESTful APIs")
.termsOfServiceUrl("http://www.xx.com/")
.contact("xx@qq.com")
.version("1.0")
.build())
.select()
//这里指定Controller扫描包路径
.apis(RequestHandlerSelectors.basePackage("asset.product.api"))
.paths(PathSelectors.any())
.build();
}
}
- 使用nacos注册服务
cloud:
nacos:
server-addr: xx.xx.x.xx:30887
config:
namespace: xx.xx.x.xx
group: ${spring.application.name}
refresh-enabled: true
file-extension: yml
discovery:
namespace: xx.xx.x.xx
group: ${spring.profiles.active}
register-enabled: true
- 配置gateway路由
# 基本配置
server:
servlet:
context-path: /api/asset-gateway
spring:
application:
name: asset-gateway
profiles:
active: dev
jackson:
time-zone: GMT+8
cloud:
gateway:
discovery:
locator:
lower-case-service-id: true
routes:
#交易服务
- id: asset-transaction-svc
uri: lb://asset-transaction-svc
predicates:
- Path=/api/asset-transaction-svc/**
filters:
- SwaggerHeaderFilter
#产品服务
- id: asset-product-svc
uri: lb://asset-product-svc
predicates:
- Path=/api/asset-product-svc/**
filters:
- SwaggerHeaderFilter
#客户管理服务
- id: asset-client-management
uri: lb://asset-client-management
predicates:
- Path=/api/asset-client-management/**
filters:
- SwaggerHeaderFilter
#公共服务
- id: asset-public-svc
uri: lb://asset-public-svc
predicates:
- Path=/api/asset-public-svc/**
filters:
- SwaggerHeaderFilter
#流程引擎
- id: asset-svc-activiti
uri: lb://asset-svc-activiti
predicates:
- Path=/api/asset-svc-activiti/**
filters:
- SwaggerHeaderFilter
- 重写swagger
@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)));
}
}
@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);
};
}
}
@Component
@Primary
public class SwaggerResourceConfig implements SwaggerResourcesProvider {
/**
* RouteLocator,GatewayProperties这两个类都是springcloud提供的springbean对象直接注入即可
*/
private final RouteLocator routeLocator;
/**
* gateway配置文件
*/
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()));
// 从配置文件中获取并配置SwaggerResource
gatewayProperties.getRoutes().stream()
// 过滤路由
.filter(routeDefinition -> routes.contains(routeDefinition.getId()))
// 循环添加,从路由的断言中获取
.forEach(route -> {
route.getPredicates().stream()
// 获取Path信息 .
.filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
// 开始添加SwaggerResource
.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) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion("2.0");
return swaggerResource;
}
@Autowired
public SwaggerResourceConfig(RouteLocator routeLocator, GatewayProperties gatewayProperties) {
this.routeLocator = routeLocator;
this.gatewayProperties = gatewayProperties;
}
}
- 打开文档
http://localhost:8081/doc.html
需要用到的jar
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.7</version>
</dependency>
<!-- nacos注册中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.2.9.RELEASE</version>
</dependency>
<!-- nacos配置中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2.2.9.RELEASE</version>
</dependency>
<!--gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>