使用SpringBoot,Gateway和SpringFox Swagger在MicroServices中集中化Swagger

时间:2019-05-29 21:58:53

标签: spring cloud swagger swagger-ui gateway

我的用户Spring Cloud Gateway是基于Webflux的,在我的MicroService开发中,每个Service都有一个带有UI的Swagger ...到目前为止没有问题。现在,我将所有Swagger集中到我的网关中,我发现了大量Zuul网关的示例代码...我认为这可以工作。但是找不到关于spring.cloud.Gateway的任何示例,它基于反应式Webflux接口,具有'springfox:springfox-spring-webflux:3.0.0-SNAPSHOT'依赖关系,我得到了SwaggerUI,但无法集中所有我从其他MicroService获得的Swagger我不知道如何配置SwaggerResourcesProvider ...

我不知道我是否应该做一个自己的MicroService(没有Webflux)来处理所有Swaggers,我认为这不是问题。 问题是WebFlux的问题:-)

也许有人建议我做一个自己的MicroService(这应该可以,但是我不确定这是否是最重要的)。或者有人可以解决我的问题。

2 个答案:

答案 0 :(得分:1)

我使用Spring Fox与Spring Fox网关创建了醒目的UI。

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-boot-starter</artifactId>
  <version>3.0.0</version>
</dependency>
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;

@Primary
@Configuration
public class SwaggerConfig implements SwaggerResourcesProvider {
  @Autowired
  private RouteLocator routeLocator;

  @Override
  public List<SwaggerResource> get() {
    List<SwaggerResource> resources = new ArrayList<>();

// I used service names with lowercase hence the toLowerCase.
// Remove the toLowerCase if you use service name with caps as is default with eureka.
    routeLocator.getRoutes().subscribe(route -> {
      String name = route.getId().split("_")[1];
      resources.add(swaggerResource(name, "/" + name.toLowerCase() + "/v3/api-docs", "1.0"));
    });

    return resources;
  }

  private SwaggerResource swaggerResource(final String name, final String location,
      final String version) {
    SwaggerResource swaggerResource = new SwaggerResource();
    swaggerResource.setName(name);
    swaggerResource.setLocation(location);
    swaggerResource.setSwaggerVersion(version);
    return swaggerResource;
  }
}

答案 1 :(得分:0)

我遇到了同样的问题,但找不到一个干净的解决方案,因为SwaggerWebflux之间还没有集成。

另一方面,我成功设置了一个最小的配置来为swagger创建代理。

首先,您需要创建一个公开Swagger API和资源的控制器:


@Controller
public class SwaggerController {
    private final JsonSerializer jsonSerializer;
    private final SwaggerResourcesProvider swaggerResources;

    @Autowired
    public SwaggerController(JsonSerializer jsonSerializer, SwaggerResourcesProvider swaggerResources) {
        this.jsonSerializer = jsonSerializer;
        this.swaggerResources = swaggerResources;
    }

    @RequestMapping({"/swagger-resources/configuration/security"})
    @ResponseBody
    public ResponseEntity<SecurityConfiguration> securityConfiguration() {
        return ResponseEntity.ok(SecurityConfigurationBuilder.builder().build());
    }

    @RequestMapping({"/swagger-resources/configuration/ui"})
    @ResponseBody
    public ResponseEntity<UiConfiguration> uiConfiguration() {
        return ResponseEntity.ok(UiConfigurationBuilder.builder().build());
    }

    @RequestMapping({"/swagger-resources"})
    @ResponseBody
    public ResponseEntity<List<SwaggerResource>> swaggerResources() {
        return ResponseEntity.ok(this.swaggerResources.get());
    }

    @RequestMapping(
        value = {"/v2/api-docs"},
        method = {RequestMethod.GET},
        produces = {"application/json", "application/hal+json"}
    )
    @ResponseBody
    public ResponseEntity<Json> getDocumentation() {
        Swagger swagger = new Swagger();
        return ResponseEntity.ok(this.jsonSerializer.toJson(swagger));
    }
}

接下来,您需要一个swagger配置来从您的微服务创建Swagger资源:

package fr.samse.bravo.rechercheProduit.gateway.config;

import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import springfox.documentation.spring.web.json.JacksonModuleRegistrar;
import springfox.documentation.spring.web.json.JsonSerializer;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

@Configuration
public class SwaggerConfig {

    private final GatewayProperties properties;

    public SwaggerConfig(GatewayProperties properties) {
        this.properties = properties;
    }

    @Bean
    public JsonSerializer jsonSerializer(List<JacksonModuleRegistrar> moduleRegistrars) {
        return new JsonSerializer(moduleRegistrars);
    }

    @Primary
    @Bean
    @Lazy
    public SwaggerResourcesProvider swaggerResourcesProvider() {
        return () -> properties.getRoutes().stream()
            .map(route -> createResource(route.getId(), getRouteLocation(route), "2.0"))
            .filter(Objects::nonNull)
            .collect(Collectors.toList());
    }

    // You will certainly need to edit this
    private String getRouteLocation(RouteDefinition route) {
        return Optional.ofNullable(route.getPredicates().get(0).getArgs().values().toArray()[0])
            .map(String::valueOf)
            .map(s -> s.replace("*", ""))
            .orElse(null);
    }

    private SwaggerResource createResource(String name, String location, String version) {
        SwaggerResource swaggerResource = new SwaggerResource();
        swaggerResource.setName(name);
        swaggerResource.setLocation(location + "/v2/api-docs");
        swaggerResource.setSwaggerVersion(version);
        return swaggerResource;
    }
}

我认为,如果您使用服务发现服务器,则此解决方案将不起作用,但就我而言,我不需要这样做,因为我有spring.cloud.gateway.routes的配置:

 - id: api-client
   uri: lb://client
   predicates:
      - Path=/api/client/**

这很容易从Eureka或Consul获取服务位置。

让我知道它是否有效。如果有人找到了另一种选择,我很感兴趣。