3、微服务整合Swagger3.0 - 网关Gateway聚合接口
一、实现的效果
访问http://{ip}:{port}/swagger-ui/index.html
springfox-swagger 提供的分组接口
二、方案
在网关聚合接口,采用路由id做资源名称,predicates.Path做映射的方式。如果需要自定义资源名称,可以单独配置一个集合(route.id,name),创建swaggerResource时,通过route.id获取name。例如:
swagger:
route_names:
-name: 订单
id: order_route
-name: 订单1
id: order_route1
spring:
cloud:
gateway:
routes:
-id: order_route
-id: order_route1
1、在网关的pom.xml添加依赖
<!-- SpringCloud Gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Swagger UI -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.fox.version}</version>
</dependency>
<!-- Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.fox.version}</version>
</dependency>
2、重写 springfox-swagger 提供的分组接口
package com.cch.gateway.config;
import org.springframework.beans.factory.annotation.Autowired;
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.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.config.ResourceHandlerRegistry;
import org.springframework.web.reactive.config.WebFluxConfigurer;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
import java.util.ArrayList;
import java.util.List;
/**
* @author cch
* @create 2024-01-25 21:51
*/
@Component
public class SwaggerProvider implements SwaggerResourcesProvider, WebFluxConfigurer {
/**
* Swagger2默认的url后缀
*/
public static final String SWAGGER2URL = "/v2/api-docs";
/**
* 网关路由
*/
@Lazy
@Autowired
private RouteLocator routeLocator;
@Autowired
private GatewayProperties gatewayProperties;
/**
* 聚合其他服务接口(swagger右上角下拉框,可聚合其它服务)
* springfox-swagger 提供的分组接口是 swagger-resource,
* 返回的是分组接口名称、地址等信息,而在Spring Cloud微服务架构下,
* 我们需要重写该接口,改由通过网关的注册中心动态发现所有的微服务文档
* @return
*/
@Override
public List<SwaggerResource> get()
{
//接口资源列表
List<SwaggerResource> resourceList = new ArrayList<>();
//服务名称列表
List<String> routes = new ArrayList<>();
// 获取网关中配置的route
// 1. 获取路由 - id => 为服务名 => order-route
routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
//结合配置的route-路径(Path)和route过滤,只获取有效的route节点
gatewayProperties.getRoutes().stream()
.filter(routeDefinition -> routes
.contains(routeDefinition.getId()))
.forEach(routeDefinition -> routeDefinition.getPredicates().stream()
.filter(predicateDefinition -> "Path".equalsIgnoreCase(predicateDefinition.getName()))
//去掉auth-service服务
.filter(predicateDefinition -> !"auth-service".equalsIgnoreCase(routeDefinition.getId()))
.forEach(predicateDefinition -> resourceList
.add(swaggerResource(routeDefinition.getId(), predicateDefinition.getArgs()
//处理为默认的url后缀, /system/v2/api-docs
.get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("/**", SWAGGER2URL)))));
return resourceList;
}
private SwaggerResource swaggerResource(String name, String location)
{
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name); // 设置名称
swaggerResource.setLocation(location);// 设置访问地址
swaggerResource.setSwaggerVersion("3.0.0");
return swaggerResource;
}
// swagger 资源映射路径,3.0.0版本访问是: /swagger-ui/index.html
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
/** swagger-ui 地址 */
registry.addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
}
}
3、创建聚合接口类SwaggerHandler.java,获取api接口信息
package com.cch.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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.*;
import java.util.Optional;
@RestController
@RequestMapping("/swagger-resources")
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("/configuration/security")
public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration()
{
return Mono.just(new ResponseEntity<>(
Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()),
HttpStatus.OK));
}
@GetMapping("/configuration/ui")
public Mono<ResponseEntity<UiConfiguration>> uiConfiguration()
{
return Mono.just(new ResponseEntity<>(
Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
}
@SuppressWarnings("rawtypes")
@GetMapping("")
public Mono<ResponseEntity> swaggerResources()
{
return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
}
}