• Gateway整合Swagger


    原文链接:https://blog.csdn.net/ttzommed/article/details/81103609

    【源码中的Spring Boot版本为2.1.3,更新了一点小细节,主要是看思路吧】最近在学习SpringBoot2和Spring Cloud.Finchley版,网上资料也是少的可怜,大部分还是通过一些github或者码云上的一些开源框架来学习,途中出现的一些bug也只能自己看看源码尝试解决。最近使用Spring Cloud Gateway替换Zuul的时候发现Swagger并不支持以WebFlux为底层的Gateway,无法集成,运行报错。下面分享我愚钝的解决思路,和关键代码,若有改进之处,望大佬指点,详细代码可以下载源码查看。

    贴上源码https://gitee.com/wxdfun/sw

    首先是子项目Spring Boot项目正常集成Swagger。在业务项目Admin中添加Swagger依赖包(使用Eureka为注册中心,文章未展示多余部分)。

    1.  
      <dependency>
    2.  
      <groupId>io.springfox</groupId>
    3.  
      <artifactId>springfox-swagger2</artifactId>
    4.  
      <version>2.9.2</version>
    5.  
      </dependency>

    添加测试Controller。

    1.  
      @RestController
    2.  
      @RequestMapping("/test")
    3.  
      @Api("测试")
    4.  
      public class TestController {
    5.  
       
    6.  
      @ApiOperation(value = "计算+", notes = "加法")
    7.  
      @ApiImplicitParams({
    8.  
      @ApiImplicitParam(name = "a", paramType = "path", value = "数字a", required = true, dataType = "Long"),
    9.  
      @ApiImplicitParam(name = "b", paramType = "path", value = "数字b", required = true, dataType = "Long")
    10.  
      })
    11.  
      @GetMapping("/{a}/{b}")
    12.  
      public Integer get(@PathVariable Integer a, @PathVariable Integer b) {
    13.  
      return a + b;
    14.  
      }
    15.  
      }

    配置Swagger使API注解生效。

    1.  
      @Configuration
    2.  
      @EnableSwagger2
    3.  
      public class SwaggerConfig {
    4.  
      @Bean
    5.  
      public Docket createRestApi() {
    6.  
      return new Docket(DocumentationType.SWAGGER_2)
    7.  
      .apiInfo(apiInfo())
    8.  
      .select()
    9.  
      .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
    10.  
      .paths(PathSelectors.any())
    11.  
      .build();
    12.  
      }
    13.  
      private ApiInfo apiInfo() {
    14.  
      return new ApiInfoBuilder()
    15.  
      .title("Swagger API")
    16.  
      .description("test")
    17.  
      .termsOfServiceUrl("")
    18.  
      .contact(new Contact("wd", "", ""))
    19.  
      .version("2.0")
    20.  
      .build();
    21.  
      }
    22.  
      }

    此时启动Admin项目后应该能正常访问admin-ip:admin:port/swagger-ui.html。下面是网关gateway部分。

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

    1.  
      <dependency>
    2.  
      <groupId>org.springframework.cloud</groupId>
    3.  
      <artifactId>spring-cloud-starter-gateway</artifactId>
    4.  
      </dependency>
    5.  
      <dependency>
    6.  
      <groupId>org.springframework.boot</groupId>
    7.  
      <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    8.  
      </dependency>
    9.  
      <dependency>
    10.  
      <groupId>io.springfox</groupId>
    11.  
      <artifactId>springfox-swagger-ui</artifactId>
    12.  
      <version>2.9.2</version>
    13.  
      </dependency>
    14.  
      <dependency>
    15.  
      <groupId>io.springfox</groupId>
    16.  
      <artifactId>springfox-swagger2</artifactId>
    17.  
      <version>2.9.2</version>
    18.  
      </dependency>

    添加gateway路由配置

    1.  
      server:
    2.  
      port: 3333
    3.  
       
    4.  
      spring:
    5.  
      application:
    6.  
      name: wd-gateway
    7.  
      cloud:
    8.  
      gateway:
    9.  
      locator:
    10.  
      enabled: true
    11.  
      routes:
    12.  
      - id: wd-admin
    13.  
      uri: lb://wd-admin
    14.  
      predicates:
    15.  
      - Path=/admin/**
    16.  
      filters:
    17.  
      - SwaggerHeaderFilter
    18.  
      - StripPrefix=1
    19.  
       
    20.  
      eureka:
    21.  
      instance:
    22.  
      prefer-ip-address: true
    23.  
      client:
    24.  
      service-url:
    25.  
      defaultZone: http://localhost:8060/eureka/
    26.  
       

    filter配置StripPrefix=1的意思:把path的前1个路径截掉

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

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

    1.  
      @Component
    2.  
      @Primary
    3.  
      @AllArgsConstructor
    4.  
      public class SwaggerProvider implements SwaggerResourcesProvider {
    5.  
      public static final String API_URI = "/v2/api-docs";
    6.  
      private final RouteLocator routeLocator;
    7.  
      private final GatewayProperties gatewayProperties;
    8.  
       
    9.  
       
    10.  
      @Override
    11.  
      public List<SwaggerResource> get() {
    12.  
      List<SwaggerResource> resources = new ArrayList<>();
    13.  
      List<String> routes = new ArrayList<>();
    14.  
      //取出gateway的route
    15.  
      routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
    16.  
      //结合配置的route-路径(Path),和route过滤,只获取有效的route节点
    17.  
      gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId()))
    18.  
      .forEach(routeDefinition -> routeDefinition.getPredicates().stream()
    19.  
      .filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
    20.  
      .forEach(predicateDefinition -> resources.add(swaggerResource(routeDefinition.getId(),
    21.  
      predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0")
    22.  
      .replace("/**", API_URI)))));
    23.  
      return resources;
    24.  
      }
    25.  
       
    26.  
      private SwaggerResource swaggerResource(String name, String location) {
    27.  
      SwaggerResource swaggerResource = new SwaggerResource();
    28.  
      swaggerResource.setName(name);
    29.  
      swaggerResource.setLocation(location);
    30.  
      swaggerResource.setSwaggerVersion("2.0");
    31.  
      return swaggerResource;
    32.  
      }
    33.  
      }

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

    1.  
      @RestController
    2.  
      @RequestMapping("/swagger-resources")
    3.  
      public class SwaggerHandler {
    4.  
      @Autowired(required = false)
    5.  
      private SecurityConfiguration securityConfiguration;
    6.  
      @Autowired(required = false)
    7.  
      private UiConfiguration uiConfiguration;
    8.  
      private final SwaggerResourcesProvider swaggerResources;
    9.  
       
    10.  
      @Autowired
    11.  
      public SwaggerHandler(SwaggerResourcesProvider swaggerResources) {
    12.  
      this.swaggerResources = swaggerResources;
    13.  
      }
    14.  
       
    15.  
       
    16.  
      @GetMapping("/configuration/security")
    17.  
      public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
    18.  
      return Mono.just(new ResponseEntity<>(
    19.  
      Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));
    20.  
      }
    21.  
       
    22.  
      @GetMapping("/configuration/ui")
    23.  
      public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
    24.  
      return Mono.just(new ResponseEntity<>(
    25.  
      Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
    26.  
      }
    27.  
       
    28.  
      @GetMapping("")
    29.  
      public Mono<ResponseEntity> swaggerResources() {
    30.  
      return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
    31.  
      }
    32.  
      }

    【Spring Boot版本超过2.0.6的应该可以跳过这一步,最新源码也更新了。Spring修复了bug给我们添加上了这个Header】另外,我发现在路由为admin/test/{a}/{b},在swagger会显示为test/{a}/{b},缺少了admin这个路由节点。断点源码时发现在Swagger中会根据X-Forwarded-Prefix这个Header来获取BasePath,将它添加至接口路径与host中间,这样才能正常做接口测试,而Gateway在做转发的时候并没有这个Header添加进Request,所以发生接口调试的404错误。解决思路是在Gateway里加一个过滤器来添加这个header。

    1.  
      //@Component
    2.  
      public class SwaggerHeaderFilter extends AbstractGatewayFilterFactory {
    3.  
      private static final String HEADER_NAME = "X-Forwarded-Prefix";
    4.  
       
    5.  
      @Override
    6.  
      public GatewayFilter apply(Object config) {
    7.  
      return (exchange, chain) -> {
    8.  
      ServerHttpRequest request = exchange.getRequest();
    9.  
      String path = request.getURI().getPath();
    10.  
      if (!StringUtils.endsWithIgnoreCase(path, SwaggerProvider.API_URI)) {
    11.  
      return chain.filter(exchange);
    12.  
      }
    13.  
      String basePath = path.substring(0, path.lastIndexOf(SwaggerProvider.API_URI));
    14.  
      ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, basePath).build();
    15.  
      ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
    16.  
      return chain.filter(newExchange);
    17.  
      };
    18.  
      }
    19.  
      }

    在配置文件中为admin节点添加过滤器生效

    1.  
      routes:
    2.  
      - id: wd-admin
    3.  
      uri: lb://wd-admin
    4.  
      predicates:
    5.  
      - Path=/admin/**
    6.  
      filters:
    7.  
      - SwaggerHeaderFilter
    8.  
      - StripPrefix=1

    这时启动Gateway,访问gateway-ip:gateway-port/swagger-ui.html时,即可正常使用swagger。大家可以多加几个API服务试试效果

    最后附上效果图

  • 相关阅读:
    数据结构:静态查找表
    数据结构:二叉查找树(C语言实现)
    自创open vp n windows步骤
    web application 访问控制
    postman trigger xdebug session in phpstorm
    sql查询学习和实践点滴积累
    如何写一个能在gulp build pipe中任意更改src内容的函数
    使用Virtual Audio Cable软件实现电脑混音支持电脑录音
    webpack学习笔记丁点积累
    centos 7.2 Apache+mysql+php step by step备忘
  • 原文地址:https://www.cnblogs.com/fswhq/p/13720162.html
Copyright © 2020-2023  润新知