zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Ubuntu apt-get "Hash Sum mismatch" 问题解决方法
    模型压缩相关工作
    bn两个参数的计算以及layer norm、instance norm、group norm
    cascade rcnn论文总结
    c++ 堆和栈以及区别
    c++ 浅拷贝和深拷贝 指针和引用的区别 malloc(free)和new(delete)的区别 重载重写重定义
    c++ 多态,虚函数、重载函数、模版函数
    c++问题整理
    repulsion-loss
    smooth l1
  • 原文地址:https://www.cnblogs.com/duanxz/p/14777724.html
Copyright © 2011-2022 走看看