文章目录

  • 1:环境准备
  • 2:gateway服务设置
    • 1:导包
    • 2:yml配置
    • 3:添加配置类,从网关服务中获取服务列表
    • 4:重写并覆盖/swagger-resources接口
  • 3:其他业务逻辑服务设置
    • 1:其他服务导包
    • 2:其他服务配置yml
    • 3:其他服务设置swagger配置类
  • 4:优化:将swagger配置作为一个微服务
    • 1:创建code-swagger服务
    • 2:导包
    • 3:写配置文件
      • 配置1:swagger的实体类,这个是对应在配置文件中写的
      • 配置二:swagger的配置类
    • 4:在 META-INF 添加spring配置
    • 5:其他服务引用这个swagger微服务
      • 6:各模块的配置参数

当我们使用Knife4j来对服务的接口文档进行管理时是非常美观和舒服的;但是当系统中的微服务越来越多的时候,我们需要访问十几个端口,这是非常痛苦的;
有没有一种办法可以将所有微服务的接口文档在同一个可视化页面进行展示,这样我们就可以统一管理了;为此我们可以通过SpringCloudGateway网关+注册中心nacos+Knige4j对所有微服务的接口文档进行统一管理

1:环境准备

本文章的前置基础是默认大家已经会了Gateway网关,Nacos注册中心,swagger和Knife4j配置,如果不太清楚,环境阅读这些文章:

Gateway-02-gateway路由规则和过滤器
Nacos-02-Nacos的配置中心和服务发现
swagger-springboot详解
swagger-优美的Knife4j文档

2:gateway服务设置

1:导包

 <dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><!--在引用时请在maven中央仓库搜索3.X最新版本号--><version>3.0.2</version></dependency>

2:yml配置

server:port: 18080spring:application:name: code-gatewaycloud:nacos:discovery:server-addr: ip:8848namespace: 61f8c730-8be2-4caf-967f-9950107f8e66config:server-addr: ip:8848namespace: 61f8c730-8be2-4caf-967f-9950107f8e66name: dev.ymlfile-extension: ymlgateway:discovery:locator:# enabled:默认为false,设置为true表明spring cloud gateway开启服务发现和路由的功能,网关自动根据注册中心的服务名为每个服务创建一个router,将以服务名开头的请求路径转发到对应的服务enabled: true# lowerCaseServiceId:启动 locator.enabled=true 自动路由时,路由的路径默认会使用大写ID,若想要使用小写ID,可将lowerCaseServiceId设置为truelower-case-service-id: trueroutes:- id: code-orderuri: lb://code-orderpredicates:- Path=/code-order/**filters:- StripPrefix=1- id: code-useruri: lb://code-userpredicates:- Path=/code-user/**filters:- StripPrefix=1

3:添加配置类,从网关服务中获取服务列表

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

package com.wkl.codegateway.config;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
{/*** swagger2默认的url后缀*/private static final String SWAGGER2_URL = "/v2/api-docs";/*** 路由定位器*/@Autowiredprivate RouteLocator routeLocator;/*** 网关应用名称*/@Value("${spring.application.name}")private String gatewayName;/*** 获取 Swagger 资源*/@Overridepublic List<SwaggerResource> get() {//接口资源列表List<SwaggerResource> resources = new ArrayList<>();//服务名称列表List<String> routeHosts = new ArrayList<>();// 1. 获取路由Uri 中的Host=> 服务注册则为服务名=》app-service001routeLocator.getRoutes().filter(route -> route.getUri().getHost() != null).filter(route -> !gatewayName.equals(route.getUri().getHost())).subscribe(route -> routeHosts.add(route.getUri().getHost()));// 2. 创建自定义资源Set<String> existsServer = new HashSet<>();     // 去重,多负载服务只添加一次for (String routeHost : routeHosts) {String serviceUrl = "/" + routeHost + SWAGGER2_URL; // 后台访问添加服务名前缀if(!existsServer.contains(serviceUrl)){existsServer.add(serviceUrl); //加过的放在set中SwaggerResource swaggerResource = new SwaggerResource(); // 创建Swagger 资源swaggerResource.setUrl(serviceUrl); // 设置访问地址swaggerResource.setName(routeHost); // 设置名称swaggerResource.setSwaggerVersion("2.0");resources.add(swaggerResource);}}return resources;}
}

4:重写并覆盖/swagger-resources接口

  • 使用Spring Boot单体架构集成swagger时,是通过包路径进行业务分组,然后在前端进行不同模块的展示,而在微服务架构下,单个服务类似于原来业务组;
  • springfox-swagger提供的分组接口是swagger-resource,返回的是分组接口名称、地址等信息;
  • 在Spring Cloud微服务架构下,需要swagger-resource重写接口,由网关的注册中心动态发现所有的微服务文档
package com.wkl.codegateway.handle;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;@Autowiredpublic 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)));}
}

至此gateway服务方面的配置结束

3:其他业务逻辑服务设置

当我们设置好gateway服务后,其他配置服务无非就是配置一下Knige4j原本的信息,比如我有两个服务一个是user(人员)模块,一个是order(订单)模块

1:其他服务导包

<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><!--在引用时请在maven中央仓库搜索3.X最新版本号--><version>3.0.2</version></dependency>

2:其他服务配置yml

其他服务的yml配置跟gateway无关,只需要配置正常的nacos注册中心即可;保证服务注册到nacos,可以被网关gateway读取到。

server:port: 18081
spring:application:name: code-ordercloud:nacos:#注册中心discovery:server-addr: ip:8848namespace: 61f8c730-8be2-4caf-967f-9950107f8e66config:server-addr: ip:8848namespace: 61f8c730-8be2-4caf-967f-9950107f8e66name: dev.ymlfile-extension: yml

3:其他服务设置swagger配置类

package com.example.codeorder.config;import org.springframework.beans.factory.annotation.Value;
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.service.VendorExtension;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;import java.util.ArrayList;/*** @author Boss* ip:port/doc.html*/
@Configuration
@EnableSwagger2
public class SwaggerConfig {@Value("${spring.application.name}")private String serviceName;//配置swagger的Docket的bean实例@Beanpublic Docket docket() {return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()//注意basePackage改成自己每个项目的路径.apis(RequestHandlerSelectors.basePackage("com.example.codeorder.controller")).paths(PathSelectors.any()).build();}//配置swagger信息private ApiInfo apiInfo() {Contact contact = new Contact("作者姓名", "", "");return new ApiInfo(serviceName+"接口文档","Api Documentation","1.0","urn:tos",contact,"Apache 2.0","http://www.apache.org/licenses/LICENSE-2.0",new ArrayList<VendorExtension>());}
}

4:优化:将swagger配置作为一个微服务

按照上述的方法,我需要每个微服务都创建一个swaggerconfig类,那么当微服务特别多的时候,这样就不合适了;
我们可以将swagger这个配置,抽取成一个微服务,其他服务引入他即可

1:创建code-swagger服务

2:导包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.wkl</groupId><artifactId>gateway-nacos-knife4j</artifactId><version>1.0-SNAPSHOT</version></parent><groupId>com.wkl</groupId><artifactId>code-swagger</artifactId><version>0.0.1-SNAPSHOT</version><name>code-swagger</name><description>code-swagger</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><!--在引用时请在maven中央仓库搜索3.X最新版本号--><version>3.0.2</version></dependency></dependencies></project>

3:写配置文件

配置1:swagger的实体类,这个是对应在配置文件中写的

package com.wkl.codeswagger.config;import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
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.ApiSelectorBuilder;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;/*** @author Boss* ip:port/doc.html*/
//@Configuration
@Configuration
//@EnableSwagger2
@EnableKnife4j
@ConditionalOnProperty(name = "swagger.enabled", matchIfMissing = true)
public class SwaggerConfig {/*** 默认的排除路径,排除Spring Boot默认的错误处理路径和端点*/private static final List<String> DEFAULT_EXCLUDE_PATH = Arrays.asList("/error", "/actuator/**");private static final String BASE_PATH = "/**";@Bean@ConditionalOnMissingBeanpublic SwaggerProperties swaggerProperties() {return new SwaggerProperties();}//配置swagger的Docket的bean实例@Beanpublic Docket docket(SwaggerProperties swaggerProperties) {// base-path处理if (swaggerProperties.getBasePath().isEmpty()) {swaggerProperties.getBasePath().add(BASE_PATH);}// noinspection uncheckedList<Predicate<String>> basePath = new ArrayList<Predicate<String>>();swaggerProperties.getBasePath().forEach(path -> basePath.add(PathSelectors.ant(path)));// exclude-path处理if (swaggerProperties.getExcludePath().isEmpty()) {swaggerProperties.getExcludePath().addAll(DEFAULT_EXCLUDE_PATH);}List<Predicate<String>> excludePath = new ArrayList<>();swaggerProperties.getExcludePath().forEach(path -> excludePath.add(PathSelectors.ant(path)));ApiSelectorBuilder builder = new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo(swaggerProperties)).select().apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage())).paths(PathSelectors.any());swaggerProperties.getBasePath().forEach(p -> builder.paths(PathSelectors.ant(p)));swaggerProperties.getExcludePath().forEach(p -> builder.paths(PathSelectors.ant(p).negate()));return builder.build();}private ApiInfo apiInfo(SwaggerProperties swaggerProperties) {return new ApiInfoBuilder().title(swaggerProperties.getTitle()).description(swaggerProperties.getDescription()).license(swaggerProperties.getLicense()).licenseUrl(swaggerProperties.getLicenseUrl()).termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl()).contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(), swaggerProperties.getContact().getEmail())).version(swaggerProperties.getVersion()).build();}
}

配置二:swagger的配置类

package com.wkl.codeswagger.config;import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
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.ApiSelectorBuilder;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;/*** @author Boss* ip:port/doc.html*/
//@Configuration
@Configuration
//@EnableSwagger2
@EnableKnife4j
@ConditionalOnProperty(name = "swagger.enabled", matchIfMissing = true)
public class SwaggerConfig {/*** 默认的排除路径,排除Spring Boot默认的错误处理路径和端点*/private static final List<String> DEFAULT_EXCLUDE_PATH = Arrays.asList("/error", "/actuator/**");private static final String BASE_PATH = "/**";@Bean@ConditionalOnMissingBeanpublic SwaggerProperties swaggerProperties() {return new SwaggerProperties();}//配置swagger的Docket的bean实例@Beanpublic Docket docket(SwaggerProperties swaggerProperties) {// base-path处理if (swaggerProperties.getBasePath().isEmpty()) {swaggerProperties.getBasePath().add(BASE_PATH);}// noinspection uncheckedList<Predicate<String>> basePath = new ArrayList<Predicate<String>>();swaggerProperties.getBasePath().forEach(path -> basePath.add(PathSelectors.ant(path)));// exclude-path处理if (swaggerProperties.getExcludePath().isEmpty()) {swaggerProperties.getExcludePath().addAll(DEFAULT_EXCLUDE_PATH);}List<Predicate<String>> excludePath = new ArrayList<>();swaggerProperties.getExcludePath().forEach(path -> excludePath.add(PathSelectors.ant(path)));ApiSelectorBuilder builder = new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo(swaggerProperties)).select().apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage())).paths(PathSelectors.any());swaggerProperties.getBasePath().forEach(p -> builder.paths(PathSelectors.ant(p)));swaggerProperties.getExcludePath().forEach(p -> builder.paths(PathSelectors.ant(p).negate()));return builder.build();}private ApiInfo apiInfo(SwaggerProperties swaggerProperties) {return new ApiInfoBuilder().title(swaggerProperties.getTitle()).description(swaggerProperties.getDescription()).license(swaggerProperties.getLicense()).licenseUrl(swaggerProperties.getLicenseUrl()).termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl()).contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(), swaggerProperties.getContact().getEmail())).version(swaggerProperties.getVersion()).build();}
}

4:在 META-INF 添加spring配置

因为code-swagger模块时一个公共模块,并且不是一个web工程,想要让模块内的配置类生效并且加入ioc容器中,必须在resources目录下先建文件夹 META-INF,文件夹下创建 spring.factories 文件 ,内容如下

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.wkl.codeswagger.config.SwaggerConfig

5:其他服务引用这个swagger微服务

其他服务模块在pom中将swagger服务当做一个微服务进行引用即可

   <!--引入swagger模块配置代码--><dependency><groupId>com.wkl</groupId><artifactId>code-swagger</artifactId><version>0.0.1-SNAPSHOT</version></dependency>

6:各模块的配置参数

因为其他业务模块已经引入了swagger模块的配置类,所以只需要在yml文件中进行配置即可,或者直接在nacos中进行配置,这样后续也方便维护和修改

# swagger配置
swagger:enabled: truetitle: user模块接口文档license: Powered By ruoyilicenseUrl: https://ruoyi.vipbasePackage: com.wkl.codeuser.controller

注:其他配置参数可以参考4.3中配置一的实体类中的参数进行配置,只需要保证参数名和实体类的名称一样即可;

Spring Cloud Gateway 网关整合 Knife4j相关推荐

  1. Spring Cloud Gateway网关

    Spring Cloud Gateway网关 1. 简介 Spring Cloud Gateway是Spring官网基于Spring 5.0. Spring Boot 2.0.Project Reac ...

  2. Spring Cloud Gateway网关实现短网址生成、解析、转发

    Spring Cloud Gateway网关实现短网址生成.解析.转发 1.概述 2.基础实现 3.路由处理HandlerFunction 4.配置路由 5.测试 1.概述 在一些生成二维码等场景中, ...

  3. 从0开始构建你的api网关--Spring Cloud Gateway网关实战及原理解析

    API 网关 API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题 ...

  4. 【硬核】Spring Cloud Gateway(网关)

    概念 Gateway是基于异步非阻塞模型上进行开发的,有springcloud团队开发.用来代替Zuul. 近几个月收集了收集了N份精校过的PDF版的Java八股文大全,涉及Java后端的方方面面,分 ...

  5. spring cloud gateway 网关_微服务网关Spring Cloud Gateway全搞定

    一.微服务网关Spring Cloud Gateway 1.1 导引 文中内容包含:微服务网关限流10万QPS.跨域.过滤器.令牌桶算法. 在构建微服务系统中,必不可少的技术就是网关了,从早期的Zuu ...

  6. Spring Cloud Gateway — 网关基本功能API暴露

    API网关 API网关是一种设计模式,一种在微服务体系下的经典构件.要了解最新API网关模式可以参考敖小剑写的<Service Mesh和Api Gateway关系深度探讨> 早期SOA阶 ...

  7. spring cloud gateway网关和链路监控

    文章目录 目录 文章目录 前言 一.网关 1.1 gateway介绍 1.2 如何使用gateway 1.3 网关优化 1.4自定义断言和过滤器 1.4.1 自定义断言 二.Sleuth--链路追踪 ...

  8. Spring Cloud Gateway网关实战

    文章目录 介绍 基础示例 spring-cloud-gateway-service spring-cloud-gateway-sample网关 介绍 Spring Cloud Gateway是Spri ...

  9. 微服务架构spring cloud - gateway网关限流

    1.算法 在高并发的应用中,限流是一个绕不开的话题.限流可以保障我们的 API 服务对所有用户的可用性,也可以防止网络攻击. 一般开发高并发系统常见的限流有:限制总并发数(比如数据库连接池.线程池). ...

最新文章

  1. 【CV】深度学习中Epoch, Batch, Iteration的含义
  2. iOS 关闭页面侧滑手势
  3. 看,这就是你心心念的研究生生活
  4. 简单介绍Git合并分支的流程步骤
  5. flex 字体加载方式4
  6. 学Python10大理由:功能多、资源多、挣钱多!
  7. java 在线电影_java电影在线影评管理系统
  8. 推荐算法炼丹笔记:序列化推荐算法Bert4Rec
  9. wxWidgets:wxJoystickEvent类用法
  10. oracle 值集附加列,EBS值集知识小结
  11. 怎么获取php文件,学习猿地-php怎么获取文件修改时间?
  12. 系统脆弱性检测 (sysytem vulnerability detection) 的研究分类
  13. android 静态_Google静态地图Android
  14. tortoiseHg查看后一个版本和parent版本的不同
  15. Oracle查看表空间及使用情况
  16. retainall java_java用retainALL 处理两个具有相同元素的list,竟然返回false,这是为什么?...
  17. 【转载】华为荣耀V9的手机录屏功能如何开启
  18. 第二届全国大学生网络安全精英赛初赛错题笔记
  19. Python爬虫笔记【一】模拟用户访问之验证码清理(4)
  20. Facebook 如何管理 150亿张照片

热门文章

  1. 抖音下载的视频电脑可以去水印吗,怎么去掉视频水印
  2. C# Excel插入图形,添加文本,填充颜色和图片
  3. 考研408笔试之排序算法代码实现汇总
  4. C++十进制二进制十六进制转换
  5. AI 与经济生产力的这场革命,怕是革不动
  6. CRC循环冗余校验---模2除法解析
  7. JavaScript 计算时间差并格式化输出
  8. android与H5交互调用js方法无效问题
  9. 前端(js/css/html)那些小的知识点,持续更新......
  10. SP公司新人培训教案