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;
    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/,感兴趣的读者可以去官方看下如何使用

到此这篇关于Spring Cloud Gateway 整合 knife4j 聚合接口文档的文章就介绍到这了,更多相关Spring Cloud Gateway 整合 knife4j内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • spring cloud gateway整合sentinel实现网关限流

    这篇文章主要介绍了spring cloud gateway整合sentinel实现网关限流,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 说明: sentinel可以作为各微服务的限流,也可以作为gateway网关的限流组件. spring cloud gateway有限流功能,但此处用sentinel来作为替待. 说明:sentinel流控可以放在gateway网关端,也可以放在各微服务端. 1,以父工程为基础,创建子工程 2,添加pom依赖

  • springcloud整合gateway实现网关的示例代码

    目录 1.项目目录: 2.代码实现: 3.实现效果: 1.项目目录: 创建项目gateway作为父类 2.代码实现: 父类依赖 ​ <parent>         <groupId>org.springframework.boot</groupId>         <artifactId>spring-boot-starter-parent</artifactId>         <version>2.6.2</versi

  • springcloud整合gateway实现网关全局过滤器功能

    目录 1.代码实现: 2.实现效果: springcloud整合gateway实现网关全局过滤器功能,在​ ​springcloud整合gateway实现网关 ​​基础功能上进行修改. 1.代码实现: 添加自定义全局过滤器 /**  * 自定义一个全局过滤器  * 实现 globalfilter , ordered接口  */ @Component public class LoginFilter implements GlobalFilter, Ordered {     /**      *

  • Spring Cloud Gateway 整合 knife4j 聚合接口文档功能

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

  • Spring Cloud Gateway整合sentinel 实现流控熔断的问题

    目录 一.什么是网关限流: 二.gateway 整合 sentinel 实现网关限流: 三.sentinel 网关流控规则的介绍: 3.1.网关流控规则: 3.2.API 分组管理: 四.sentinel 网关流控实现的原理: 五.网关限流了,服务就安全了吗? 六.自定义流控异常消息: 一.什么是网关限流: 在微服务架构中,网关层可以屏蔽外部服务直接对内部服务进行调用,对内部服务起到隔离保护的作用,网关限流,顾名思义,就是通过网关层对服务进行限流,从而达到保护后端服务的作用. Sentinel

  • Spring Boot 使用 Swagger 构建 RestAPI 接口文档

    源码地址:https://github.com/laolunsi/spring-boot-examples 目前SpringBoot常被用于开发Java Web应用,特别是前后端分离项目.为方便前后端开发人员进行沟通,我们在SpringBoot引入了Swagger. Swagger作用于接口,让接口数据可视化,尤其适用于Restful APi 本节分两部分介绍,第一部分是SpringBoot引入Swagger的两种方式,第二部分是详细介绍在Web接口上应用Swagger的注解. 本篇文章使用Sp

  • spring boot集成smart-doc自动生成接口文档详解

    目录 前言 功能特性 1 项目中创建 /src/main/resources/smart-doc.json配置文件 2 配置内容如下(指定文档的输出路径) 3 pom.xml下添加配置 4 运行插件 5 找到存放路径浏览器打开 6 测试结果 前言 smart-doc 是一款同时支持 java restful api 和 Apache Dubbo rpc 接口文档生成的工具,smart-doc 颠覆了传统类似 swagger 这种大量采用注解侵入来生成文档的实现方法. smart-doc 完全基于

  • SpringBoot整合Swagger3生成接口文档过程解析

    前后端分离的项目,接口文档的存在十分重要.与手动编写接口文档不同,swagger是一个自动生成接口文档的工具,在需求不断变更的环境下,手动编写文档的效率实在太低.与新版的swagger3相比swagger2配置更少,使用更加方便. 一.pom文件中引入Swagger3依赖 <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId

  • Spring Cloud Gateway 默认的filter功能和执行顺序介绍

    目录 Spring Cloud Gateway 默认的filter功能和执行顺序 有效性 调试方法 filters(按执行顺序) spring cloud gateway之filter实战 1.filter的作用和生命周期 2.AddRequestHeader GatewayFilter Factory Spring Cloud Gateway 默认的filter功能和执行顺序 有效性 Spring Cloud Gateway 2.0.0.RELEASE 调试方法 新建一个GlobalFilte

  • 浅析Spring Cloud Gateway中的令牌桶限流算法

    目录 前言 回顾限流算法 计数器/时间窗口法 漏桶法 令牌桶法 主要逻辑分析 前言 在一个分布式高并发的系统设计中,限流是一个不可忽视的功能点.如果不对系统进行有效的流量访问限制,在双十一和抢票这种流量洪峰的场景下,很容易就会把我们的系统打垮.而作为系统服务的卫兵的网关组件,作为系统服务的统一入口,更需要考虑流量的限制,直接在网关层阻断流量比在各个系统中实现更合适.Spring Cloud Gateway的实现中,就提供了限流的功能,下面主要分析下Spring Cloud Gateway中是如何

  • Spring Cloud Gateway 服务网关快速实现解析

    Spring Cloud Gateway 服务网关 API 主流网关有NGINX.ZUUL.Spring Cloud Gateway.Linkerd等:Spring Cloud Gateway构建于 Spring 5+,基于 Spring Boot 2.x 响应式的.非阻塞式的 API.同时,它支持 websockets,和 Spring 框架紧密集成,用来代替服务网关Zuul,开发体验相对来说十分不错. Spring Cloud Gateway 是 Spring Cloud 微服务平台的一个子

  • 详解Spring Cloud Gateway 数据库存储路由信息的扩展方案

    动态路由背景 ​ 无论你在使用Zuul还是Spring Cloud Gateway 的时候,官方文档提供的方案总是基于配置文件配置的方式 例如: # zuul 的配置形式 routes: pig-auth: path: /auth/** serviceId: pig-auth stripPrefix: true # gateway 的配置形式 routes: - id: pigx-auth uri: lb://pigx-auth predicates: - Path=/auth/** filte

随机推荐