最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring?Cloud?Gateway?整合?knife4j?聚合接口文檔功能

 更新時間:2022年02月14日 09:59:17   作者:張維鵬  
這篇文章主要介紹了Spring?Cloud?Gateway?整合?knife4j?聚合接口文檔的相關(guān)知識,我們可以基于?Spring?Cloud?Gateway?網(wǎng)關(guān)?+?nacos?+?knife4j?對所有微服務(wù)項目的接口文檔進行聚合,從而實現(xiàn)我們想要的文檔管理功能,需要的朋友可以參考下

當系統(tǒng)中微服務(wù)數(shù)量越來越多時,如果任由這些服務(wù)散落在各處,那么最終管理每個項目的接口文檔將是一件十分麻煩的事情,單是記住所有微服務(wù)的接口文檔訪問地址就是一件苦差事了。當如果能夠?qū)⑺形⒎?wù)項目的接口文檔都統(tǒng)一匯總在同一個可視化頁面,那么將大大減少我們的接口文檔管理維護工作,為此,我們可以基于 Spring Cloud Gateway 網(wǎng)關(guān) + nacos + knife4j 對所有微服務(wù)項目的接口文檔進行聚合,從而實現(xiàn)我們想要的文檔管理功能

注:本案例需要 springboot 提前整合 nacos 作為注冊中心,springcloud 整合 nacos 注冊中心部分內(nèi)容歡迎閱讀這篇文章:Nacos注冊中心的部署與用法詳細介紹

1、Spring Cloud Gateway 網(wǎng)關(guān)整合 Knife4j:

(1)開啟gateway自動路由功能:

隨著我們的系統(tǒng)架構(gòu)不斷地發(fā)展,系統(tǒng)中微服務(wù)的數(shù)量肯定會越來越多,我們不可能每添加一個服務(wù),就在網(wǎng)關(guān)配置一個新的路由規(guī)則,這樣的維護成本很大;特別在很多種情況,我們在請求路徑中會攜帶一個路由標識方便進行轉(zhuǎn)發(fā),而這個路由標識一般都是服務(wù)在注冊中心中的服務(wù)名,因此這是我們就可以開啟 spring cloud gateway 的自動路由功能,網(wǎng)關(guān)自動根據(jù)注冊中心的服務(wù)名為每個服務(wù)創(chuàng)建一個router,將以服務(wù)名開頭的請求路徑轉(zhuǎn)發(fā)到對應(yīng)的服務(wù),配置如下:

# enabled:默認為false,設(shè)置為true表明spring cloud gateway開啟服務(wù)發(fā)現(xiàn)和路由的功能,網(wǎng)關(guān)自動根據(jù)注冊中心的服務(wù)名為每個服務(wù)創(chuàng)建一個router,將以服務(wù)名開頭的請求路徑轉(zhuǎn)發(fā)到對應(yīng)的服務(wù)
spring.cloud.gateway.discovery.locator.enabled = true
# lowerCaseServiceId:啟動 locator.enabled=true 自動路由時,路由的路徑默認會使用大寫ID,若想要使用小寫ID,可將lowerCaseServiceId設(shè)置為true
spring.cloud.gateway.discovery.locator.lower-case-service-id = true

        這里需要注意的是,如果我們的配置了 server.servlet.context-path 屬性,這會導致自動路由失敗的問題,因此我們需要做如下兩個修改:

# 重寫過濾鏈,解決項目設(shè)置了 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 屬性配置的項目路徑,防止對后續(xù)路由策略產(chǎn)生影響,因為 gateway 網(wǎng)關(guān)不支持 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());
        };
    }
}

至此,網(wǎng)關(guān)將自動根據(jù)注冊中心的服務(wù)名為每個服務(wù)創(chuàng)建一個router,將以服務(wù)名開頭的請求路徑轉(zhuǎn)發(fā)到對應(yīng)的服務(wù)。

(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 網(wǎng)關(guān)的時候,會出現(xiàn)沒有 basePath 的情況,例如定義的 /user、/order 等微服務(wù)前綴,因此我們需要在 Gateway 網(wǎng)關(guān)添加一個 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 等單體架構(gòu)集成 swagger 時,我們是基于包路徑進行業(yè)務(wù)分組,然后在前端進行不同模塊的展示,而在微服務(wù)架構(gòu)下,一個服務(wù)就類似于原來我們寫的一個業(yè)務(wù)組。springfox-swagger 提供的分組接口是 swagger-resource,返回的是分組接口名稱、地址等信息,而在Spring Cloud微服務(wù)架構(gòu)下,我們需要重寫該接口,改由通過網(wǎng)關(guān)的注冊中心動態(tài)發(fā)現(xiàn)所有的微服務(wù)文檔,代碼如下:

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單體架構(gòu)集成swagger時,是通過包路徑進行業(yè)務(wù)分組,然后在前端進行不同模塊的展示,而在微服務(wù)架構(gòu)下,單個服務(wù)類似于原來業(yè)務(wù)組;
 * springfox-swagger提供的分組接口是swagger-resource,返回的是分組接口名稱、地址等信息;
 * 在Spring Cloud微服務(wù)架構(gòu)下,需要swagger-resource重寫接口,由網(wǎng)關(guān)的注冊中心動態(tài)發(fā)現(xiàn)所有的微服務(wù)文檔
 */
@Primary
@Configuration
public class SwaggerResourceConfig implements SwaggerResourcesProvider
{
    @Autowired
    private RouteLocator routeLocator;
    
    // 網(wǎng)關(guān)應(yīng)用名稱
    @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<>();
        //服務(wù)名稱列表
        List<String> routeHosts = new ArrayList<>();
        // 獲取所有可用的應(yīng)用名稱
        routeLocator.getRoutes()
                .filter(route -> route.getUri().getHost() != null)
                .filter(route -> !applicationName.equals(route.getUri().getHost()))
                .subscribe(route -> routeHosts.add(route.getUri().getHost()));
        // 去重,多負載服務(wù)只添加一次
        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、微服務(wù)架構(gòu)中其他項目接入knife4j:

<!-- knife4j文檔,微服務(wù)架構(gòu) -->
<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())
                // 如果為生產(chǎn)環(huán)境,則不創(chuàng)建swagger
                .enable(!"real".equals(env));
        // 在knife4j前端頁面的地址路徑中添加gateway網(wǎng)關(guān)的項目名,解決在調(diào)試接口、發(fā)送請求出現(xiàn)404的問題
        docket.pathProvider(new RelativePathProvider(servletContext)
        {
            @Override
            public String getApplicationBasePath()
            {
                return "/" + serviceNameForGateway + super.getApplicationBasePath();
            }
        });
        return docket;
    }
}

3、最終效果:

文章的最后,再介紹 knife4j 官方提供的另一種接口文檔聚合的方式:Aggregation微服務(wù)聚合組件,官方地址:https://doc.xiaominfo.com/knife4j/resources/,感興趣的讀者可以去官方看下如何使用

到此這篇關(guān)于Spring Cloud Gateway 整合 knife4j 聚合接口文檔的文章就介紹到這了,更多相關(guān)Spring Cloud Gateway 整合 knife4j內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解JAVA中priorityqueue的具體使用

    詳解JAVA中priorityqueue的具體使用

    這篇文章主要介紹了詳解JAVA中priorityqueue的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-01-01
  • JDK版本修改不生效的解決方法

    JDK版本修改不生效的解決方法

    本文主要介紹了在配置新電腦環(huán)境時遇到JDK版本切換失敗的問題,文中通過圖文介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-03-03
  • java編程中字節(jié)流轉(zhuǎn)換成字符流的實現(xiàn)方法

    java編程中字節(jié)流轉(zhuǎn)換成字符流的實現(xiàn)方法

    下面小編就為大家?guī)硪黄猨ava編程中字節(jié)流轉(zhuǎn)換成字符流的實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • java參數(shù)傳值代碼舉例

    java參數(shù)傳值代碼舉例

    在編程中往方法中傳遞參數(shù)的方法往往有兩種,一種是值傳遞,一種是引用傳遞,而在java中所有的參數(shù)傳遞全部都是值傳遞,這篇文章主要給大家介紹了關(guān)于java參數(shù)傳值的相關(guān)資料,需要的朋友可以參考下
    2024-03-03
  • 6種SpringBoot中自定義starter的方式介紹

    6種SpringBoot中自定義starter的方式介紹

    在SpringBoot生態(tài)中,starter是一種特殊的依賴,它能夠自動裝配相關(guān)組件,簡化項目配置,本文將詳細介紹6種不同的自定義starter開發(fā)方法,有需要的可以了解下
    2025-04-04
  • java調(diào)用python代碼的兩種實現(xiàn)方式:Runtime.exec()和Jython

    java調(diào)用python代碼的兩種實現(xiàn)方式:Runtime.exec()和Jython

    在Java中調(diào)用Python代碼有多種方法,包括使用Runtime.exec()和第三方庫如Jython,Runtime.exec()通過系統(tǒng)命令執(zhí)行Python腳本,適用于簡單的調(diào)用場景,Jython則是一個Python的Java實現(xiàn),允許在Java中直接運行Python代碼,適用于更深層次的集成需求
    2025-01-01
  • Java如何獲取Json中的數(shù)據(jù)實例代碼

    Java如何獲取Json中的數(shù)據(jù)實例代碼

    這篇文章主要給大家介紹了關(guān)于Java如何獲取Json中數(shù)據(jù)的相關(guān)資料,我們在日常開發(fā)中少不了和JSON數(shù)據(jù)打交道,那么我們來看看JAVA中常用的JSON獲取方式,需要的朋友可以參考下
    2023-09-09
  • Java中的升序和降序問題

    Java中的升序和降序問題

    這篇文章主要介紹了Java中的升序和降序問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • 吊打Java面試官之Lambda表達式 Stream API

    吊打Java面試官之Lambda表達式 Stream API

    這篇文章主要介紹了吊打Java之jdk8的新特性包括Lambda表達式、函數(shù)式接口、Stream API全面刨析,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • Java使用百度AI接口實現(xiàn)智能機器人對話系統(tǒng)

    Java使用百度AI接口實現(xiàn)智能機器人對話系統(tǒng)

    AI已經(jīng)在各行各業(yè)中廣泛應(yīng)用,助力于各式各樣的業(yè)務(wù),而在機器人對話中,我們可以通過利用百度AI中的自然語言處理、問答知識圖譜等技術(shù),使機器人可以更加智能化、自然化的為用戶服務(wù),本文介紹Java利用百度AI接口實現(xiàn)智能機器人對話系統(tǒng)
    2024-01-01

最新評論

赤水市| 札达县| 扬中市| 屯昌县| 手机| 义马市| 周宁县| 日喀则市| 苍梧县| 东至县| 右玉县| 图片| 金坛市| 汤阴县| 云浮市| 延吉市| 肃北| 沅江市| 麦盖提县| 佛冈县| 肇源县| 武功县| 抚宁县| 松潘县| 凤庆县| 松江区| 青田县| 蓬莱市| 清水县| 云龙县| 昌都县| 安图县| 诏安县| 榆树市| 东兴市| 五大连池市| 界首市| 涟源市| 仙桃市| 邹平县| 安顺市|