Spring Cloud Gateway 整合 knife4j 聚合接口文档

        当系统中微服务数量越来越多时,如果任由这些服务散落在各处,那么最终管理每个项目的接口文档将是一件十分麻烦的事情,单是记住所有微服务的接口文档访问地址就是一件苦差事了。当如果能够将所有微服务项目的接口文档都统一汇总在同一个可视化页面,那么将大大减少我们的接口文档管理维护工作,为此,我们可以基于 Spring Cloud Gateway 网关 + nacos + knife4j 对所有微服务项目的接口文档进行聚合,从而实现我们想要的文档管理功能

注:本案例需要 springboot 提前整合 nacos 作为注册中心,springcloud 整合 nacos 注册中心部分内容欢迎阅读这篇文章:Nacos注册中心的部署与用法详细介绍

1、Spring Cloud Gateway 网关整合 Knife4j:

(1)开启gateway自动路由功能:

        随着我们的系统架构不断地发展,系统中微服务的数量肯定会越来越多,我们不可能每添加一个服务,就在网关配置一个新的路由规则,这样的维护成本很大;特别在很多种情况,我们在请求路径中会携带一个路由标识方便进行转发,而这个路由标识一般都是服务在注册中心中的服务名,因此这是我们就可以开启 spring cloud gateway 的自动路由功能,网关自动根据注册中心的服务名为每个服务创建一个router,将以服务名开头的请求路径转发到对应的服务,配置如下:

# enabled:默认为false,设置为true表明spring cloud gateway开启服务发现和路由的功能,网关自动根据注册中心的服务名为每个服务创建一个router,将以服务名开头的请求路径转发到对应的服务
spring.cloud.gateway.discovery.locator.enabled = true
# lowerCaseServiceId:启动 locator.enabled=true 自动路由时,路由的路径默认会使用大写ID,若想要使用小写ID,可将lowerCaseServiceId设置为true
spring.cloud.gateway.discovery.locator.lower-case-service-id = true

        这里需要注意的是,如果我们的配置了 server.servlet.context-path 属性,这会导致自动路由失败的问题,因此我们需要做如下两个修改:

# 重写过滤链,解决项目设置了 server.servlet.context-path 导致 locator.enabled=true 默认路由策略404的问题
spring.cloud.gateway.discovery.locator.filters[0] = PreserveHostHeader
@Configuration
public class GatewayConfig
{
    @Value ("${server.servlet.context-path}")
    private String prefix;

    /**
     * 过滤 server.servlet.context-path 属性配置的项目路径,防止对后续路由策略产生影响,因为 gateway 网关不支持 servlet
     */
    @Bean
    @Order (-1)
    public WebFilter apiPrefixFilter()
    {
        return (exchange, chain) ->
        {
            ServerHttpRequest request = exchange.getRequest();
            String path = request.getURI().getRawPath();

            path = path.startsWith(prefix) ? path.replaceFirst(prefix, "") : path;
            ServerHttpRequest newRequest = request.mutate().path(path).build();

            return chain.filter(exchange.mutate().request(newRequest).build());
        };
    }
}

        至此,网关将自动根据注册中心的服务名为每个服务创建一个router,将以服务名开头的请求路径转发到对应的服务。

(2)pom.xml 文件引入 knife4j 依赖:

		<dependency>
			<groupId>com.github.xiaoymin</groupId>
			<artifactId>knife4j-spring-boot-starter</artifactId>
			<version>2.0.4</version>
		</dependency>
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger-ui</artifactId>
		</dependency>
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger2</artifactId>
		</dependency>

(3)配置 SwaggerHeaderFilter:

        在集成 Spring Cloud Gateway 网关的时候,会出现没有 basePath 的情况,例如定义的 /user、/order 等微服务前缀,因此我们需要在 Gateway 网关添加一个 Filter 过滤器

import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;

@Configuration
public class SwaggerHeaderFilter extends AbstractGatewayFilterFactory
{
    private static final String HEADER_NAME = "X-Forwarded-Prefix";
    private static final String URI = "/v2/api-docs";

    @Override
    public GatewayFilter apply(Object config)
    {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            String path = request.getURI().getPath();

            if(StringUtils.endsWithIgnoreCase(path, URI))
            {
                String basePath = path.substring(0, path.lastIndexOf(URI));
                ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, basePath).build();
                ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
                return chain.filter(newExchange);
            }
            else
            {
                return chain.filter(exchange);
            }
        };
    }
}

(4)重写 swagger-resources:

        在使用 SpringBoot 等单体架构集成 swagger 时,我们是基于包路径进行业务分组,然后在前端进行不同模块的展示,而在微服务架构下,一个服务就类似于原来我们写的一个业务组。springfox-swagger 提供的分组接口是 swagger-resource,返回的是分组接口名称、地址等信息,而在Spring Cloud微服务架构下,我们需要重写该接口,改由通过网关的注册中心动态发现所有的微服务文档,代码如下:

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;

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

/**
 * 使用Spring Boot单体架构集成swagger时,是通过包路径进行业务分组,然后在前端进行不同模块的展示,而在微服务架构下,单个服务类似于原来业务组;
 * springfox-swagger提供的分组接口是swagger-resource,返回的是分组接口名称、地址等信息;
 * 在Spring Cloud微服务架构下,需要swagger-resource重写接口,由网关的注册中心动态发现所有的微服务文档
 */
@Primary
@Configuration
public class SwaggerResourceConfig implements SwaggerResourcesProvider
{
    @Autowired
    private RouteLocator routeLocator;
    
    // 网关应用名称
    @Value ("${spring.application.name}")
    private String applicationName;

    //接口地址
    private static final String API_URI = "/v2/api-docs";

    @Override
    public List<SwaggerResource> get() {
        //接口资源列表
        List<SwaggerResource> resources = new ArrayList<>();
        //服务名称列表
        List<String> routeHosts = new ArrayList<>();

        // 获取所有可用的应用名称
        routeLocator.getRoutes()
                .filter(route -> route.getUri().getHost() != null)
                .filter(route -> !applicationName.equals(route.getUri().getHost()))
                .subscribe(route -> routeHosts.add(route.getUri().getHost()));

        // 去重,多负载服务只添加一次
        Set<String> existsServer = new HashSet<>();
        routeHosts.forEach(host -> {
            // 拼接url
            String url = "/" + host + API_URI;
            //不存在则添加
            if (!existsServer.contains(url)) {
                existsServer.add(url);
                SwaggerResource swaggerResource = new SwaggerResource();
                swaggerResource.setUrl(url);
                swaggerResource.setName(host);
                resources.add(swaggerResource);
            }
        });
        return resources;
    }
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.*;

import java.util.Optional;

/**
 * 获取api接口信息
 */
@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)));
    }
}

2、微服务架构中其他项目接入knife4j:

<!-- knife4j文档,微服务架构 -->
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-micro-spring-boot-starter</artifactId>
    <version>2.0.4</version>
</dependency>
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.async.DeferredResult;
import springfox.documentation.builders.*;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.paths.RelativePathProvider;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import javax.servlet.ServletContext;

/**
 * @description: swagger配置文件
 **/
@Configuration
@EnableSwagger2
@EnableKnife4j
public class Swagger2Config
{
    @Value("${spring.profiles.active}")
    private String env;
    @Value("${spring.application.name}")
    private String serviceName;
    @Value("${gateway.service.name}")
    private String serviceNameForGateway;

    @Bean
    public Docket createDocket(ServletContext servletContext)
    {
        Docket docket = new Docket(DocumentationType.SWAGGER_2)
                .genericModelSubstitutes(DeferredResult.class)
                .forCodeGeneration(true)
                .pathMapping("/")
                .select()
                .build()
                .apiInfo(new ApiInfoBuilder()
                        .title(serviceName + "接口文档")
                        .version("1.0")
                        .contact(new Contact("xxx","",""))
                        .license("XXX有限公司")
                        .build())
                // 如果为生产环境,则不创建swagger
                .enable(!"real".equals(env));

        // 在knife4j前端页面的地址路径中添加gateway网关的项目名,解决在调试接口、发送请求出现404的问题
        docket.pathProvider(new RelativePathProvider(servletContext)
        {
            @Override
            public String getApplicationBasePath()
            {
                return "/" + serviceNameForGateway + super.getApplicationBasePath();
            }
        });

        return docket;
    }
}

3、最终效果:

文章的最后,再介绍 knife4j 官方提供的另一种接口文档聚合的方式:Aggregation微服务聚合组件,官方地址:https://doc.xiaominfo.com/knife4j/resources/,感兴趣的读者可以去官方看下如何使用


相关阅读:

常见的服务器架构入门:从单体架构、EAI 到 SOA 再到微服务和 ServiceMesh

常见分布式理论(CAP、BASE)和一致性协议(Gosssip协议、Raft一致性算法)

一致性哈希算法原理详解

Nacos注册中心的部署与用法详细介绍

Nacos配置中心用法详细介绍

SpringCloud OpenFeign 远程HTTP服务调用用法与原理

什么是RPC?RPC框架dubbo的核心流程

服务容错设计:流量控制、服务熔断、服务降级

sentinel 限流熔断神器详细介绍

Sentinel 规则持久化到 apollo 配置中心

Sentinel-Dashboard 与 apollo 规则的相互同步

Spring Cloud Gateway 服务网关的部署与使用详细介绍

Spring Cloud Gateway 整合 sentinel 实现流控熔断

Spring Cloud Gateway 整合 knife4j 聚合接口文档

常见分布式事务详解(2PC、3PC、TCC、Saga、本地事务表、MQ事务消息、最大努力通知)

分布式事务Seata原理

RocketMQ事务消息原理

  • 11
    点赞
  • 86
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
### 回答1: cloud-nacos-gateway-knife4j:swagger聚合文档是使用Spring Cloud和Nacos作为技术栈开发的一种解决方案。 Spring Cloud是一套开发分布式应用的工具集,它基于Spring Boot,用于构建微服务架构的应用程序。它提供了诸如服务注册与发现、服务追踪、负载均衡等功能,可以方便地实现微服务的开发和管理。在这个解决方案中,我们使用了Spring Cloud来构建和管理微服务。 Nacos是一个动态服务发现、配置管理和服务管理平台。它提供了服务注册与发现、配置管理、动态路由等功能,可以方便地实现微服务的注册与发现、配置的动态管理。在这个解决方案中,我们将使用Nacos作为服务注册与发现的中心。 GatewaySpring Cloud的网关组件,它以微服务的方式构建网关,提供了统一的入口和出口,可以对请求进行路由、过滤、聚合等多种操作。在这个解决方案中,我们使用Gateway作为网关组件,统一管理和分发请求。 Knife4j是一个开源的Swagger文档聚合工具,它可以将多个微服务的Swagger文档聚合在一起,提供一个统一的API文档入口。在这个解决方案中,我们使用Knife4j来聚合各个微服务的Swagger文档,方便开发人员查看和调试API接口。 综上所述,cloud-nacos-gateway-knife4j:swagger聚合文档使用了Spring Cloud、Nacos、GatewayKnife4j等技术,通过Spring Cloud构建和管理微服务,使用Nacos实现服务注册与发现,通过Gateway实现统一的请求分发和路由,再通过Knife4j将各个微服务的Swagger文档聚合在一起,方便开发人员进行API的查看和调试。这个解决方案可以提高开发效率、简化架构,使得微服务的开发和管理更加方便和高效。 ### 回答2: cloud-nacos-gateway-knife4j是基于Spring Cloud、Nacos、GatewayKnife4j等技术实现的Swagger聚合文档工具。 首先,这个工具使用了Spring Cloud框架,它是一种用于构建分布式系统的解决方案。Spring Cloud提供了一系列插件和组件,使得我们可以轻松地构建、部署和管理分布式应用。这些组件包括服务发现与注册、服务间调用、负载均衡、断路器等等。在cloud-nacos-gateway-knife4j中,我们使用Spring Cloud来实现服务注册与发现的功能,使得不同的微服务可以方便地相互调用。 其次,cloud-nacos-gateway-knife4j还使用了Nacos作为服务的注册中心。Nacos是一个开源的动态服务发现、配置和服务管理平台,它提供了服务注册、服务发现、服务配置、路由配置等功能。在cloud-nacos-gateway-knife4j中,我们使用Nacos作为服务注册中心,来管理微服务的地址和配置信息。 另外,cloud-nacos-gateway-knife4j还使用了Gateway作为API网关。API网关是系统的统一入口,它可以处理一些通用的非业务功能,如身份认证、请求转发、限流等等。在cloud-nacos-gateway-knife4j中,我们使用Gateway作为API网关,实现了请求的转发和一些基本的安全控制功能。 最后,cloud-nacos-gateway-knife4j还使用了Knife4j作为Swagger的UI界面。Swagger是一种用于构建、文档化和调试RESTful接口的工具,它提供了一套非常直观的界面来展示接口信息和测试接口。在cloud-nacos-gateway-knife4j中,我们使用Knife4j来生成并展示聚合文档,使得接口文档更加友好和易用。 总的来说,cloud-nacos-gateway-knife4j是一个基于Spring Cloud、Nacos、GatewayKnife4j等技术实现的Swagger聚合文档工具。它利用这些技术的优势,帮助开发者更好地管理和维护微服务,并提供了友好的界面来查看和测试接口文档。 ### 回答3: Cloud-Nacos-Gateway-Knife4j 是一个使用 Spring Cloud 和 Nacos 技术实现的聚合文档,其中集成了 Swagger。它可以帮助开发者更便捷地查看和管理项目的 API 文档Spring Cloud 是一个开发微服务架构的框架,提供了许多功能,例如服务注册与发现、配置管理、负载均衡等。Nacos 是一个用于服务注册与发现、动态配置管理的平台,可以实现服务的自动发现和配置更新。这两个技术结合起来,可以方便地构建和管理微服务架构。 Cloud-Nacos-Gateway-Knife4j 中的 Gateway 是一个 API 网关,它可以承担路由和负载均衡的作用,将外部请求转发给后端的微服务。Knife4j 是一个为 Swagger 提供增强功能的工具,可以生成美观的 API 文档,并提供了在线测试接口的功能。 在使用 Cloud-Nacos-Gateway-Knife4j 架构时,我们可以通过 Nacos 注册中心管理和发现微服务,以及实现动态的配置更新。Gateway 作为入口,将外部请求转发到相应的微服务。同时,我们可以使用 Knife4j 生成并展示微服务的 API 文档,便于开发者查看和调试接口。 总之,Cloud-Nacos-Gateway-Knife4j 提供了一种基于 Spring Cloud 和 Nacos 的微服务架构解决方案,提供了服务注册发现、配置管理、API 文档和在线测试等功能,为开发者带来了更加便捷和高效的开发体验。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张维鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值