springcloud-gateway整合Swagger聚合微服务系统API文档

最近使用Spring Cloud Gateway替换Zuul的时候发现Swagger并不支持以WebFlux为底层的Gateway,无法集成,运行报错。

首先是子项目Spring Boot项目正常集成Swagger。在业务项目Admin中添加Swagger依赖包(使用consul为注册中心),这里跳过。

 

 

 建立网关项目gateway,添加核心依赖包

buildscript {
    ext {
        springBootVersion = '2.3.8.RELEASE'
    }
    //...
}

dependencyManagement {
    imports {
        mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Hoxton.SR10'
    }
}


    compile 'org.springframework.cloud:spring-cloud-starter-config'
    compile 'org.springframework.cloud:spring-cloud-starter-consul-discovery'
    compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-gateway'
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-webflux'
    compile group: 'org.springframework.boot', name: 'spring-boot-autoconfigure'
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-logging'
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-aop'
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-actuator'
    compile group: 'org.springframework.boot', name: 'spring-boot-devtools'

    annotationProcessor 'org.projectlombok:lombok'

    //swagger
    implementation 'io.springfox:springfox-swagger2:2.9.2'
    implementation 'io.springfox:springfox-swagger-ui:2.9.2'
    implementation('com.github.xiaoymin:knife4j-spring-ui:2.0.8')

 

 添加gateway路由配置

spring:
  application:
    name: gateway # 服务名称
  cloud:
    consul:
      discovery:
        hostname: 本机ip
    config:
      name: ${spring.application.name}
      uri: http://ip:11111
      profile: default
      label: master
    gateway:
      discovery:
        locator:
          enabled: true  #表明gateway开启服务注册和发现的功能, 动态路由
          lowerCaseServiceId: true
          filters:
      routes:
        - id: test # 唯一id ,随便起,不能重复
          uri: lb://test # 匹配注册中心的服务
          predicates:
            - Path=/test/** # 匹配的规则
          filters:
            # 去掉路由前缀,访问 localhost:8088/test/v2/api 转发的就是 localhost:8089/v2/api
            # 1 : 代表剥离路径的个数
            - StripPrefix=1

 

 

因为Swagger暂不支持webflux项目所以Gateway里不能配置SwaggerConfig,也就是说Gateway无法提供自身API。但我想一般也不会在网关项目代码里写业务API代码吧。所以这里的集成只是基于基于WebMvc的微服务项目。

配置SwaggerProvider,获取Api-doc,即SwaggerResources。

@Component
@Primary
@AllArgsConstructor
public class SwaggerProvider implements SwaggerResourcesProvider {
    public static final String API_URI = "/v2/api-docs";
    private final RouteLocator routeLocator;
    private final GatewayProperties gatewayProperties;
 
 
    @Override
    public List<SwaggerResource> get() {
        List<SwaggerResource> resources = new ArrayList<>();
        List<String> routes = new ArrayList<>();
        //取出gateway的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()))
                        .forEach(predicateDefinition -> resources.add(swaggerResource(routeDefinition.getId(),
                                predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0")
                                        .replace("/**", API_URI)))));
        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;
    }
}

因为Gateway里没有配置SwaggerConfig,而运行Swagger-ui又需要依赖一些接口,所以我的想法是自己建立相应的swagger-resource端点。

@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));
    }
 
    @GetMapping("")
    public Mono<ResponseEntity> swaggerResources() {
        return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
    }
}

这时启动Gateway,访问gateway-ip:gateway-port/swagger-ui.html时,即可正常使用swagger。

补充一下SwaggerHeaderFilter类:

/**
 * @introduce: swagger请求头过滤器
 * @author: lk
 * @date: 2020/6/4
 **/
@Component
public class SwaggerHeaderFilter extends AbstractGatewayFilterFactory {

    private static final String HEADER_NAME = "X-Forwarded-Prefix";

    @Override
    public GatewayFilter apply(Object config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            String path = request.getURI().getPath();
            if (!StringUtils.endsWithIgnoreCase(path, SwaggerProvider.API_URI)) {
                return chain.filter(exchange);
            }
            String basePath = path.substring(0, path.lastIndexOf(SwaggerProvider.API_URI));
            ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, basePath).build();
            ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
            return chain.filter(newExchange);
        };
    }
}

 

参考:

https://blog.csdn.net/ttzommed/article/details/81103609?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-20.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-20.control

https://blog.csdn.net/qq_31748587/article/details/102563155

https://blog.csdn.net/lk1822791193/article/details/106540734?utm_medium=distribute.pc_relevant_download.none-task-blog-2~default~BlogCommendFromBaidu~default-1.nonecase&depth_1-utm_source=distribute.pc_relevant_download.none-task-blog-2~default~BlogCommendFromBaidu~default-1.nonecas

 

posted on 2021-05-17 17:19  duanxz  阅读(2192)  评论(0编辑  收藏  举报