1. 程式人生 > >白話SpringCloud | 第十一章:路由閘道器(Zuul):利用swagger2聚合API文件

白話SpringCloud | 第十一章:路由閘道器(Zuul):利用swagger2聚合API文件

前言

通過之前的兩篇文章,可以簡單的搭建一個路由網關了。而我們知道,現在都奉行前後端分離開發,前後端開發的溝通成本就增加了,所以一般上我們都是通過swagger進行api文件生成的。現在由於使用了統一路由網關了,都希望各微服務的api文件統一的聚合在閘道器服務中,也方便前端使用者查閱,不需要每個服務單獨檢視。當然了,也是可以做一個文件索引網頁進行各微服務的api文件連結的。今天,我們就來講下使用swagger實現自動化聚合微服務文件功能。

注:關於Swagger的介紹和使用,由於在之前的SpringBoot系列文章中有提及,這裡就不在過多闡述了,不理解的可以點選:第十章:Swagger2的整合和使用

進行檢視,瞭解下基本用法。

Zuul聚合示例

為了實現自動聚合功能,簡單來說就是通過Zuulapi獲取所有的路由資訊,根據其具體地址進行自動轉配到SwaggerSwaggerResource下。

另外,為了專案的獨立,本章節建立個maven多模組工程專案。整體結構如下:

專案結構

微服務端

為了演示,建立兩個微服務spring-cloud-zuul-service-onespring-cloud-zuul-service-two

這裡以構建spring-cloud-zuul-service-one為例,spring-cloud-zuul-service-two

基本上是一樣的,可以檢視原始碼示例。

0.引入相關依賴

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 客戶端依賴 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>       
        <!--swagger -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.0</version>
        </dependency> 

1.編寫swagger配置類。

/**
 * swagger配置類
 * @author oKong
 *
 */
@EnableSwagger2
@Configuration
public class SwaggerConfig {

    //是否開啟swagger,正式環境一般是需要關閉的,可根據springboot的多環境配置進行設定
    @Value(value = "${swagger.enabled}")
    Boolean swaggerEnabled;

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
                // 是否開啟
                .enable(swaggerEnabled).select()
                // 掃描的路徑包
                .apis(RequestHandlerSelectors.basePackage("cn.lqdev.learning.springcloud.zuul.service"))
                // 指定路徑處理PathSelectors.any()代表所有的路徑
                .paths(PathSelectors.any()).build().pathMapping("/");
    }

    //設定api資訊
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("路由閘道器(Zuul):利用swagger2聚合API文件-service-one")
                .description("oKong | 趔趄的猿")
                // 作者資訊
                .contact(new Contact("oKong", "https://blog.lqdev.cn/", "[email protected]"))
                .version("1.0.0")
                .build();
    }
}

2.編寫控制層,設定對外api服務資訊,同時建立了請求響應的實體類。

DemoController.java

/**
 * demo示例
 * @author oKong
 *
 */
@RestController
@Api(tags="servicie-one服務")
@Slf4j
public class DemoController {

    @GetMapping("/hello")
    @ApiOperation(value="demo示例")
    public DemoResp hello(DemoReq demoReq) {
        log.info("DemoReq:{}", demoReq);
        
        return DemoResp.builder()
                .code(demoReq.getCode())
                .name(demoReq.getName())
                .remark(demoReq.getRemark())
                .build();
    }
}

DemoReq.java

/**
 * 請求實體
 * @author oKong
 *
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ApiModel
public class DemoReq {

    @ApiModelProperty(name="code",value="編碼",example="oKong")
    String code;
    
    @ApiModelProperty(name="name",value="名稱",example="趔趄的猿")
    String name;
    
    @ApiModelProperty(name="remark",value="備註",example="blog:blog.lqdev.cn")
    String remark;
}

DemoResp.java

/**
 * 響應實體
 * @author Okong
 *
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ApiModel
public class DemoResp {

    @ApiModelProperty(name="code",value="編碼",example="oKong")
    String code;
    
    @ApiModelProperty(name="name",value="名稱",example="趔趄的猿")
    String name;
    
    @ApiModelProperty(name="remark",value="備註",example="blog:blog.lqdev.cn")
    String remark;
}

3.編寫啟動類。

/**
 * api服務1 示例
 * @author oKong
 *
 */
@SpringBootApplication
@EnableDiscoveryClient
@Slf4j
public class ServiceOneApplication {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(ServiceOneApplication.class, args);
        log.info("spring-cloud-zuul-service-one啟動!");
    }
}

4.新增配置資訊。

spring.application.name=api-service-one
server.port=789

# 註冊中心地址 -此為單機模式
eureka.client.service-url.defaultZone=http://127.0.0.1:1000/eureka
# 啟用ip配置 這樣在註冊中心列表中看見的是以ip+埠呈現的
eureka.instance.prefer-ip-address=true
# 例項名稱  最後呈現地址:ip:2000
eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
# swagger開關
swagger.enabled=true

5.啟動應用,訪問:http://127.0.0.1:789/swagger-ui.html 就可以單應用api文件配置成功了

service-one-swagger

路由閘道器端

建立專案:spring-cloud-zuul-gateway

0.引入相關依賴。

        <!-- zuul 依賴 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
        <!-- 客戶端依賴 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--swagger -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.0</version>
        </dependency>

1.新增相關配置資訊。

spring.application.name=zuul-gateway
server.port=8899

# 註冊中心地址 -此為單機模式
eureka.client.service-url.defaultZone=http://127.0.0.1:1000/eureka
# 啟用ip配置 這樣在註冊中心列表中看見的是以ip+埠呈現的
eureka.instance.prefer-ip-address=true
# 例項名稱  最後呈現地址:ip:15678
eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}

# swagger開啟開關
swagger.enabled=true

2.編寫swagger配置類(重點)

@EnableSwagger2
@Configuration
@Primary //多個bean時 此類優先使用
public class SwaggerConfig implements SwaggerResourcesProvider{

    //是否開啟swagger,正式環境一般是需要關閉的,可根據springboot的多環境配置進行設定
    @Value(value = "${swagger.enabled}")
    Boolean swaggerEnabled;

    @Autowired
    RouteLocator routeLocator;
    
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
                // 是否開啟
                .enable(swaggerEnabled).select()
                // 掃描的路徑包
                .apis(RequestHandlerSelectors.basePackage("cn.lqdev.learning.springcloud.zuul.swagger2"))
                // 指定路徑處理PathSelectors.any()代表所有的路徑
                .paths(PathSelectors.any()).build().pathMapping("/");
    }

    //設定api資訊
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("路由閘道器(Zuul):利用swagger2聚合API文件")
                .description("oKong | 趔趄的猿")
                // 作者資訊
                .contact(new Contact("oKong", "https://blog.lqdev.cn/", "[email protected]"))
                .version("1.0.0")
                .termsOfServiceUrl("https://github.com/xie19900123/")
                .build();
    }

    @Override
    public List<SwaggerResource> get() {
        //利用routeLocator動態引入微服務
        List<SwaggerResource> resources = new ArrayList<>();
        resources.add(swaggerResource("zuul-gateway","/v2/api-docs","1.0"));
        //迴圈 使用Lambda表示式簡化程式碼
        routeLocator.getRoutes().forEach(route ->{
            //動態獲取
            resources.add(swaggerResource(route.getId(),route.getFullPath().replace("**", "v2/api-docs"), "1.0"));
        });
        //也可以直接 繼承 Consumer介面
//      routeLocator.getRoutes().forEach(new Consumer<Route>() {
//
//          @Override
//          public void accept(Route t) {
//              // TODO Auto-generated method stub
//              
//          }
//      });
        return resources;
    }
    
    private SwaggerResource swaggerResource(String name,String location, String version) {
        SwaggerResource swaggerResource = new SwaggerResource();
        swaggerResource.setName(name);
        swaggerResource.setLocation(location);
        swaggerResource.setSwaggerVersion(version);
        return swaggerResource;
    }
}

這裡繼承SwaggerResourcesProvider介面是實現聚合api的關鍵,另外通過RouteLocator類獲取路由列表是實現自動聚合的關鍵。

當然,這裡也是可以手動進行新增的。

3.編寫zuul內部控制層。

/**
 * zuul 內部提供對外服務示例
 * @author oKong
 *
 */
@RestController
@RequestMapping("/demo")
@Api(tags="zuul內部rest api")
public class DemoController {

    @GetMapping("/hello")
    @ApiOperation(value="demo示例",notes="demo示例")
    @ApiImplicitParam(name="name",value="名稱",example="oKong")
    public String hello(String name) {
        return "hi," + name + ",this is zuul api! ";
    }
}

4.編寫啟動類。

/**
 * zuul使用swagger2聚合微服務api示例
 * @author oKong
 *
 */
@SpringBootApplication
@EnableZuulProxy
@EnableDiscoveryClient
@Slf4j
public class ZuulSwaggerApplication {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(ZuulSwaggerApplication.class, args);
        log.info("spring-cloud-zuul-gateway啟動!");
    }
}

5.啟動應用,訪問:http://127.0.0.1:8899/swagger-ui.html 可以看見頁面顯示的是閘道器專案的swagger文件資訊。

zuul-gate-swagger-ui

現在看看右上角的Select a spec下拉框,可以看見下拉框中包含了註冊中心下的所有微服務了。

Select a spec

此時,我們切換下api-service-one,可以看見api-service-one的api列表了。

api-service-one

切換到api-service-two,也可以看見都要的api列表資訊。

api-service-two

參考資料

總結

本章節主要簡單介紹瞭如何在Zuul路由閘道器服務利用Swagger2進行微服務api的聚合功能。這樣檢視各微服務的api文件就很方便,集中,不需要在切換不同文件地址了。

最後

目前網際網路上大佬都有分享SpringCloud系列教程,內容可能會類似,望多多包涵了。原創不易,碼字不易,還希望大家多多支援。若文中有錯誤之處,還望提出,謝謝。

老生常談

  • 個人QQ:499452441
  • 微信公眾號:lqdevOps

公眾號

以下教程可能你會感興趣:

原文地址:https://blog.lqdev.cn/2018/10/19/SpringCloud/chapter-eleven/