springboot 2.0 + springcloud alibaba 整合gateway(二)swagger分發(fā)

前言:

在實際開發(fā)當中前后端對接的時候吗讶,經(jīng)常會用到swagger,但是如果使用了路由的話曹抬,如果不用路由網(wǎng)關(guān)去分發(fā)swagger的話溉瓶,前后端對解決的時候會很麻煩急鳄,微服務(wù)的接口增多對于對接的成本就會變高,那么這一節(jié)就寫一寫gatewaty轉(zhuǎn)發(fā)swagger

代碼配置:

具體微服務(wù)

需要用到swagger的微服務(wù)上添加swagger的依賴堰酿,為了方便我這邊直接就使用上一章用到的那個test接口的nacos客戶端的項目

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>com.gitee.simons.cloud</groupId>
        <artifactId>simons-cloud</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <artifactId>simons-nacos</artifactId>
    <name>${project.artifactId} [web]</name>
    <packaging>jar</packaging>

    <!-- 版本疾宏,字段關(guān)鍵字 -->
    <properties>
        <start-class>com.gitee.simons.nacos.NacosApplication</start-class>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

        <!--swagger相關(guān) -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

<profiles>
        <profile>
            <id>spring-boot</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                        <version>${spring-boot.version}</version>
                        <configuration>
                            <mainClass>${start-class}</mainClass>
                        </configuration>
                        <executions>
                            <execution>
                                <goals>
                                    <goal>repackage</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>


    </profiles>


    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <!--解決持續(xù)集成無法找到main類 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>${start-class}</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

主要就是加上swagger,由于swagger的配置版本越高触创,功能越全面這邊建議無腦最新relase坎藐,反正不在生產(chǎn)環(huán)境上出現(xiàn)的東西,怎么方便怎么來哼绑。

接下來就是要加上一些跨域和swagger的配置岩馍,直接復制我的代碼即可

swagger的配置類,要注意的是抖韩,return的docket里面有個basePackagex需要根據(jù)實際的包路徑填寫的
復制的時候注意一下即可

package com.gitee.simons.nacos.swagger.config;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Value;
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.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.web.DocExpansion;
import springfox.documentation.swagger.web.OperationsSorter;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger.web.UiConfigurationBuilder;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.ArrayList;
import java.util.List;

/**
 * SwaggerConfig api文檔地址:/swagger-ui.html
 *
 * @author JSM
 */

@Configuration
public class SwaggerConfig {

    @Value("${spring.application.name}")
    private String applicationName;

    @Bean
    public Docket createRestApi() {
        // 構(gòu)造token給測試的時候填寫
        ParameterBuilder tokenPar = new ParameterBuilder();
        List<Parameter> pars = new ArrayList<Parameter>();
        tokenPar.name("token").description("用戶令牌(不需用戶鑒權(quán)的不需要傳)").modelRef(new ModelRef("string")).parameterType("header")
                .required(false).build();
        pars.add(tokenPar.build());

        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(defaultTitleInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.gitee.simons"))
                .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                .paths(PathSelectors.any())
                .build().globalOperationParameters(pars);
    }

    /**
     * 默認標題信息
     *
     * @return
     */
    private ApiInfo defaultTitleInfo() {
        // 大標題
        return new ApiInfoBuilder().title("")
                // 詳細描述
                .description("")
                .contact(new Contact("", "", ""))
                // 版本
                .version("4.0")
                .build();
    }

    @Bean
    UiConfiguration uiConfig() {
        return UiConfigurationBuilder.builder().docExpansion(DocExpansion.LIST).operationsSorter(OperationsSorter.ALPHA).build();
    }
}

swagger的資源過濾配置

package com.gitee.simons.nacos.swagger.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * test
 *
 * @author: jsm
 * @date: 2018/11/16 10:40
 *
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    /**
     * 跨域支持
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(true)
                .allowedMethods("*")
                .maxAge(3600)
                .allowedHeaders("X-Requested-With", "Content-Type","token");
    }

    /**
     * 添加靜態(tài)資源--過濾swagger-api (開源的在線API文檔)
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/js/**").addResourceLocations("classpath:/js/");
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");

    }

}

全局跨域配置

package com.gitee.simons.nacos.swagger.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CrosAppConfig implements WebMvcConfigurer {
    
    @Autowired
    private CrosInterceptor crosInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 配置全局 的cros
        registry.addInterceptor(crosInterceptor).addPathPatterns("/**/**");
    }



}

跨域的詳細信息設(shè)置

package com.gitee.simons.nacos.swagger.config;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class CrosInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //處理跨域名問題
        response.setHeader("Access-Control-Allow-Origin", "*");  
        response.setHeader("Access-Control-Allow-Methods", "*");  
        response.setHeader("Access-Control-Max-Age", "3600");    
        response.setHeader("Access-Control-Allow-Headers", "X-Requested-With,Content-Type,token");  
        response.setHeader("Access-Control-Allow-Credentials", "true");
        return true;
    }
}

那么只要復制了這些文件之后蛀恩,在applicaiton文件上面加上@EnableSwagger2標簽就可以的了

package com.gitee.simons.nacos;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.ComponentScan;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@SpringBootApplication
@EnableDiscoveryClient
@ComponentScan("com.gitee")
@EnableSwagger2
public class NacosApplication {

    public static void main(String[] args) {
        SpringApplication.run(NacosApplication.class, args);
    }
}

配置完這些信息之后,啟動application在瀏覽器輸入http://localhost:8112/swagger-ui.html
就可以直接請求到swagger的頁面

image.png

gateway轉(zhuǎn)發(fā)配置

這一步之后具體的微服務(wù)就可以實現(xiàn)請求了,但是我們的目標是需要可以做到gateway轉(zhuǎn)發(fā), 那么應(yīng)該還要再gateway項目下做一些操作

如果用過zuul做過路由轉(zhuǎn)發(fā)的朋友掠械,應(yīng)該知道zuul是用的路由頁面跳轉(zhuǎn)的方式,這種方式得在serlvet的方式下才可以進行顽馋,但gateway是一個用netty框架為基礎(chǔ)的服務(wù),那么他就無法使用zuul的方式進行路由幌羞,但可以使用另外的方式寸谜,就是獲取gateway路由參數(shù)中的服務(wù),然后顯示在select a spec上属桦,通過請求swagger的v2/api-docs接口返回json數(shù)據(jù)熊痴,再放進swagger的頁面中,大概這種思路

那么直接上配置

首先給gateway加上swagger的pom 依賴

        <!--swagger相關(guān) -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

對swagger路由的配置

package com.sunmnet.mediaroom.gateway.config;

import lombok.AllArgsConstructor;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.support.NameUtils;
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.List;

/**
 * @author Sywd
 */
@Component
@Primary
@AllArgsConstructor
public class SwaggerProvider implements SwaggerResourcesProvider {
    public static final String API_URI = "/v2/api-docs";
    private final RouteLocator routeLocator;
    private final GatewayProperties gatewayProperties;


    @Override
    public List<SwaggerResource> get() {
        List<SwaggerResource> resources = new ArrayList<>();
        List<String> routes = new ArrayList<>();
        routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
        gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId()))
                .forEach(routeDefinition -> routeDefinition.getPredicates().stream()
                        .filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
                        .forEach(predicateDefinition -> resources.add(swaggerResource(routeDefinition.getId(),
                                predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0")
                                        .replace("/**", API_URI)))));
        return resources;
    }

    private SwaggerResource swaggerResource(String name, String location) {

        SwaggerResource swaggerResource = new SwaggerResource();
        swaggerResource.setName(name);
        swaggerResource.setLocation(location);
        swaggerResource.setSwaggerVersion("2.0");
        return swaggerResource;
    }
}

因為swagger打開頁面的時候地啰,會默認請求一系列的請求愁拭,這些請求會返回頁面信息的基本構(gòu)成內(nèi)容讲逛,
但由于gateway上用的是webflux亏吝,swagger是無法獲取到這些信息的,那么我們只能自己偽造一個這些接口并返回成功的空信息盏混,以此繞過報錯蔚鸥,然后具體資源信息通過轉(zhuǎn)發(fā)的請求各個微服務(wù)中獲取

swagger資源報錯信息繞過

package com.gitee.simons.gateway.config;

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;

@RestController
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("/swagger-resources/configuration/security")
    public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
        return Mono.just(new ResponseEntity<>(
                Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));
    }

    @GetMapping("/swagger-resources/configuration/ui")
    public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
        return Mono.just(new ResponseEntity<>(
                Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
    }

    @GetMapping("/swagger-resources")
    public Mono<ResponseEntity> swaggerResources() {
        return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
    }

    @GetMapping("/")
    public Mono<ResponseEntity> swaggerResourcesN() {
        return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
    }

    @GetMapping("/csrf")
    public Mono<ResponseEntity> swaggerResourcesCsrf() {
        return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
    }
}

配置完之后,就可以啟動application许赃,請求通過swagger路由獲取到具體的信息了

image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末止喷,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子混聊,更是在濱河造成了極大的恐慌弹谁,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異预愤,居然都是意外死亡沟于,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門植康,熙熙樓的掌柜王于貴愁眉苦臉地迎上來旷太,“玉大人,你說我怎么就攤上這事销睁」╄担” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵冻记,是天一觀的道長睡毒。 經(jīng)常有香客問我,道長冗栗,這世上最難降的妖魔是什么吕嘀? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮贞瞒,結(jié)果婚禮上偶房,老公的妹妹穿的比我還像新娘。我一直安慰自己军浆,他們只是感情好棕洋,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著乒融,像睡著了一般掰盘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赞季,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天愧捕,我揣著相機與錄音,去河邊找鬼申钩。 笑死次绘,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的撒遣。 我是一名探鬼主播邮偎,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼义黎!你這毒婦竟也來了禾进?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤廉涕,失蹤者是張志新(化名)和其女友劉穎泻云,沒想到半個月后艇拍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡宠纯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年淑倾,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片征椒。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡娇哆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出勃救,到底是詐尸還是另有隱情碍讨,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布蒙秒,位于F島的核電站勃黍,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏晕讲。R本人自食惡果不足惜覆获,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瓢省。 院中可真熱鬧弄息,春花似錦、人聲如沸勤婚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽馒胆。三九已至缨称,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間祝迂,已是汗流浹背睦尽。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留型雳,地道東北人当凡。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像四啰,于是被迫代替她去往敵國和親宁玫。 傳聞我的和親對象是個殘疾皇子粗恢,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355