基于Gateway网关实现接口文档聚合

250 阅读3分钟

基于Gateway网关实现Swagger接口文的聚合

码友们大家好!

鲸鱼今天又来更新了,这几天一直在尝试搭建自己的项目框架,也蛮久没没有更新了。 在搭建GateWay网关时,也踩了很多坑,接下来让鲸鱼带大家尝试一下Gateway网关聚合接口文档

版本参照表

<!-- spring 版本控制区 -->
<spring-cloud.verison>Hoxton.SR3</spring-cloud.verison>
<spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
<spring-boot.version>2.2.5.RELEASE</spring-boot.version>
使用依赖使用版本
Spring Boot2.2.5.RELEASE
spring-cloud-alibaba2.2.1.RELEASE
spring-cloudHoxton.SR3
loadbalancer2.2.2.RELEASE

以上就是我们本次搭建Gateway聚合Swagger的Spring版本啦 接下来是本次使用的Swagger版本

<!-- springfox swagger ui界面依赖 -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>${springfox.swagger.version}</version>
</dependency>

<!-- Spring fox 公共版本定义 -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>${springfox.swagger.version}</version>
</dependency>

具体版本号为:3.0.0,大家可以自己选择,我觉得这个UI要好看些,所以就用了这个

自定义spring-swagger-starter

  1. 创建新的maven项目,注意:这里需要指定parent标签,使用spring-boot-starter-parent即可
<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>2.2.5.RELEASE</version>
   <relativePath/>
</parent>
<groupId>com.cattywhale</groupId>
<artifactId>hommie-component-swagger-starter</artifactId>
<version>1.0.0-Final-SNAPSHOT</version>
<name>hommie-component-swagger-starter</name>
<description>Swagger Project for Spring Boot</description>
  1. 导入依赖
<properties>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <springfox.swagger.version>3.0.0</springfox.swagger.version>
    <!-- swagger.version -->
    <xiaoymin.swagger.version>1.9.6</xiaoymin.swagger.version>
    <!-- lombok.version -->
    <lombok.version>1.18.18</lombok.version>
    <spring-boot.version>2.2.5.RELEASE</spring-boot.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.cattywhale</groupId>
            <artifactId>hommie-component-bom</artifactId>
            <version>${project.version}</version>
        </dependency>

        <!--swagger-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-boot-starter</artifactId>
            <version>${springfox.swagger.version}</version>
        </dependency>

        <!--swagger-ui  这里是用了一个好看一点ui界面-->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>swagger-bootstrap-ui</artifactId>
            <version>${xiaoymin.swagger.version}</version>
        </dependency>

        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>${spring-boot.version}</version>
        </dependency>

    </dependencies>
</dependencyManagement>


<!-- 当前项目依赖 -->
<dependencies>
    <!--swagger-->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-boot-starter</artifactId>
    </dependency>

    <!--swagger-ui  这里是用了一个好看一点ui界面-->
    <dependency>
        <groupId>com.github.xiaoymin</groupId>
        <artifactId>swagger-bootstrap-ui</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>

    <!-- 自动配置 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-autoconfigure</artifactId>
    </dependency>
</dependencies>
  1. 创建SwaggerAutoConfiguration自动配置类,这部分的配置是与后面我们在微服务项目中基于yml文件进行配置的基础Swagger信息,由于依赖了SwaggerProperties,因此我们还需要自己封装一个SwaggerProperties的实体类。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

/**
 * project name:<font size = "1"><b>swagger启动具体配置类</b></font><br>
 * file name:<font size = "1"><b>SwaggerAutoConfiguration</b></font><br>
 * description:<font size = "1"><b>swagger启动具体配置类</b></font><br>
 * @version 1.0.0<br>
 * @update [1] [2024/4/1 9:51] [CattyWhale] [新建] <br>
 */
@Configuration
public class SwaggerAutoConfiguration {
    /* 引入当前SwaggerProperties参数配置 */
    @Autowired(required = true)
    private SwaggerProperties swaggerProperties;
    /* 注入Docket对象 */
    @Bean
    public Docket docket() {
        Set<String> set = new HashSet<>();
        set.add("http");
        set.add("https");
        return new Docket(DocumentationType.SWAGGER_2).pathMapping("/")
                .enable(true)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()))
                .paths(PathSelectors.any())
                .build()
                .protocols(set);

    }
    /**
     * title:<font size = "1"><b>apiInfo</b></font><br>
     * description:<font size = "1"><b> 配置Swagger信息 = ApiInfo </b></font><br>
     * @param null <br>
     * @return <br>
     * @update [1] [2024/4/1 14:58] [xuzihan] [新建] <br>
     */
    private ApiInfo apiInfo() {

        // 作者信息
        Contact contact = new Contact(swaggerProperties.getAuthor().getName(),
                swaggerProperties.getAuthor().getUrl(),
                swaggerProperties.getAuthor().getEmail());
        return new ApiInfo(swaggerProperties.getApiInfo().getTitle(),
                swaggerProperties.getApiInfo().getDescription(),
                swaggerProperties.getApiInfo().getVersion(),
                swaggerProperties.getApiInfo().getTermsOfServiceUrl(),
                contact,
                swaggerProperties.getApiInfo().getLicense(),
                swaggerProperties.getApiInfo().getLicenseUrl(),
                new ArrayList<>());
    }
}

4.封装SwaggerProperties的实体类

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * project name:<font size = "1"><b>Swagger参数配置信息类</b></font><br>
 * file name:<font size = "1"><b>SwaggerProperties</b></font><br>
 * description:<font size = "1"><b>Swagger参数配置信息类</b></font><br>
 * @version 1.0.0<br>
 * @update [1] [2024/4/1 9:51] [CattyWhale] [新建] <br>
 */
@Data
@ConfigurationProperties(prefix = SwaggerProperties.PREFIX)
@Component
@EnableConfigurationProperties
public class SwaggerProperties {
    public static final String PREFIX = "spring.swagger";

    // 包
    private String basePackage;

    // 作者相关信息
    private Author author;

    // API相关信息
    private ApiInfo apiInfo;

    @Data
    public static class ApiInfo{
        String title;
        String description;
        String version;
        String termsOfServiceUrl;
        String license;
        String licenseUrl;
    }
    @Data
    public static class Author{
        private String name;

        private String email;

        private String url;
    }
}
  1. 重点:基于Srping的自动配置原理,在当前项目的resorces目录下书写META-INF/spring.factories文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration = \
  com.cattywhale.swagger.starter.config.SwaggerAutoConfiguration

以上就是我们的的自定义starter的过程,实现完上述步骤后,基于maven install打包即可

image.png

做完以上内容,我们的准备工作就结束了,开始搭建自己的微服务及网关

搭建微服务与网关的过程在这里就不予赘述啦,直接进入正题:如何在Gateway网关中聚合文档实现网关访问多个服务实例接口文档

  1. 网关导入依赖:
<!--swagger-->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
</dependency>

<!--swagger-ui  这里是用了一个好看一点ui界面-->
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>swagger-bootstrap-ui</artifactId>
</dependency>

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

这里有一个坑,在Spring Cloud Nacos中,由于原版的nacos使用的是ribbon实现的负载均衡,所以在搭建网关进行服务发现时需要排除nacos中的ribbon组件

<!-- nacos 注册中心 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </exclusion>
    </exclusions>
</dependency>
  1. 书写SwaggerResourceProvider实现网关动态获取服务实例的定义接口
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.Primary;
import org.springframework.stereotype.Component;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Component
@Primary
public class GatewaySwaggerResourcesProvider implements SwaggerResourcesProvider {
   /* 访问后缀名 */
   private static final String SWAGGER2URL = "/v2/api-docs";

   /* 网关路由 */
   @Autowired
   private RouteLocator routeLocator;

   /* 网关应用名 */
   @Value("${spring.application.name}")
   private String self;

   /* 让swagger可以找到其对应的服务 */
   @Override
   public List<SwaggerResource> get() {
       List<SwaggerResource> resources = new ArrayList<>();
       List<String> routeHosts = new ArrayList<>();

       // 获取当前所有的可用host : serverID
       routeLocator.getRoutes().filter(route -> route.getUri().getHost() != null)
               .filter(route -> !self.equals(route.getUri().getHost()))
               .subscribe(route -> routeHosts.add(route.getUri().getHost()));

       // 记录已经添加过的server
       Set<String> alreadyAddServers = new HashSet<>();
       routeHosts.forEach(instance -> {
           String url = "/" + instance.toLowerCase() + SWAGGER2URL;
           if (!alreadyAddServers.contains(url)){
               alreadyAddServers.add(url);
               SwaggerResource swaggerResource = new SwaggerResource();
               swaggerResource.setUrl(url);
               swaggerResource.setName(instance);
               resources.add(swaggerResource);
           }
       });
       return resources;
   }
}
  1. 在具体的微服务中导入自定义starter,并书写接口及注解标记
  2. 书写具体微服务的配置文件:
# 配置服务名,nacos发现地址
spring:
  application:
    name: server-name
  cloud:
    nacos:
      discovery:
        namespace: configFile-namespace
        server-addr: host : port
  # 自定义starter会获取以下信息作为参数进行配置
  swagger:
    basePackage: 控制层接口所在的包路径
    author:
      name: CattyWhale
      email: email
      url: 访问url 域名
    apiInfo:
      title: Swagger测试服务
      description: Swagger测试相关接口
      version: 1.0
      termOfServiceUrl: http://127.0.0.1:${server.port}/${spring.application.name}
      license: license
      licenseUrl: licenseUrl
# 声明服务端口
server:
  port: 30001
  1. 书写Gateway网关配置
# 声明网关端口
server:
  port: 10001
  # 网关具体配置
spring:
  cloud:
    gateway:
      discovery:
        locator:
          # 开启从注册中心动态创建路由的功能,利用微服务名进行路由
          enabled: true
      routes:
        - id: server-name
          # 匹配后提供服务路由地址
          uri: lb://server-name
          # 断言
          filters:
            - StripPrefix=1
          predicates:
            - Path=/swagger/**
  1. 启动Gateway及对应微服务测试

image.png 最终结果如果是上述结果就是正确的了! 这部分可能会出现503或者是404的报错,小伙伴可以自己尝试解决一下,如果有问题可以私信或是评论哦,我会努力解决的!

今天的Gateway集成Swagger实现基于网关访问接口文档就到此为止啦!

最后希望各位大佬或者是正在一起学习的小伙伴节节高升!技术突飞猛进!如果喜欢鲸鱼的文章可以伸伸小手点点关注,各位的关注就是鲸鱼持续更新的动力!!!!