Spring Cloud Gateway聚合Swagger文檔

前言

2020年7月份Springfox 3.0.0發佈了,增長了對Webflux、OpenApi 3的支持,適應Gateway,微服務中爲方便管理各微服務的接口文檔,特此來摸索一下Spring Cloud Gateway集成管理,整個過程沒什麼代碼,簡單易用html

一、環境及工具介紹

一、gradle,一個基於 JVM 的富有突破性構建工具,簡化maven的xml繁瑣配置
二、nacos,阿里開發的動態服務發現、配置和服務管理平臺,appllo不喜歡用就它了
三、knife4j,Java MVC框架集成Swagger生成Api文檔的加強解決方案,前身是swagger-bootstrap-ui(swagger2用的好好的爲啥要用這玩意???原皮看厭倦了換上新鮮的感受)
四、Spring Cloud版本用的是Hoxton.RELEASE,SpringBoot版本2.2.1.RELEASE
以上gradle、nacos環境自行百度搭建,比較簡單,不作贅述了前端

二、微服務端

  2.一、先寫兩個簡單的微服務,這裏起個很隨便的名字(example、cart-service)

端口分別設置爲8081和8082java

server: 
  port: 8081

build.gradle:git

plugins {
    id 'org.springframework.boot' version '2.2.1.RELEASE'
    id 'io.spring.dependency-management' version '1.0.9.RELEASE'
    id 'java'
}


group 'com.asan.cart'
version '1.0.0-SNAPSHOT'
sourceCompatibility = 1.8

ext {
    set('springBootVersion', "2.2.1.RELEASE")
    set('springCloudVersion', "Hoxton.RELEASE")
    set('alibabaCloudVersion', "2.2.1.RELEASE")
}
repositories {
    mavenLocal()
    maven {
        url 'http://maven.aliyun.com/nexus/content/groups/public/'
    }
}
configurations {
    compile.exclude module: 'tomcat-embed-el'
    compile.exclude module: 'spring-boot-starter-tomcat'
}
dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.12'
    compile (
            /** 微服務api文檔,不須要引入前端ui包 */
            'com.github.xiaoymin:knife4j-micro-spring-boot-starter:3.0.2',
            /**  nacos配置中心 */
            'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-config',
            /**  nacos註冊與發現中心 */
            'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery',
            'org.springframework.boot:spring-boot-starter-web',
            'org.springframework.boot:spring-boot-starter-undertow' 
    )
}    
dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springBootVersion}"
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
        mavenBom "com.alibaba.cloud:spring-cloud-alibaba-dependencies:${alibabaCloudVersion}"
    }
}

這裏主要就是啓動微服務集成knife4j文檔,由於tomcat老報錯,容器就用的undertow,web默認用的tomcat,若是須要須要使用undertow,增長以下內容排除tomcat依賴:github

configurations {
    compile.exclude module: 'tomcat-embed-el'
    compile.exclude module: 'spring-boot-starter-tomcat'
}

兩個微服務客戶端增長一個配置類:web

package com.asan.example.config;

import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc
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.Docket;


@Configuration
@EnableSwagger2WebMvc
public class Swagger2Config {

@Bean
public Docket createRestApi(){
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.asan.example.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        Contact contact = new Contact("阿三", "http://www.asan.com", "asan@163.com");
        return new ApiInfoBuilder()
                .title("example服務文檔")
                .description("example服務API文檔")
                .contact(contact)
                .version("1.0")
                .build();
    }
}

增長啓動類ExampleApplicationredis

package com.asan.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class ExampleApplication {
    public static void main(String[] args) {
        SpringApplication.run(ExampleApplication.class, args);
    }

}

接着來一個Controller作文檔展現:spring

Controller這裏本身隨便寫吧,能看到就行,這裏也貼一下吧顯得不那麼空json

package com.asan.example.controller;

import com.alibaba.fastjson.JSON;
import com.asan.example.entity.Cat;
import com.asan.example.pojo.dto.CatDto;
import com.asan.example.pojo.vo.PageResult;
import com.asan.example.pojo.vo.ResultVO;
import com.asan.example.service.impl.CatServiceImpl;
import com.asan.example.util.BeanCopierUtil;
import com.asan.example.util.RedisClient;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import tk.mybatis.mapper.entity.Example;

@RestController
@RequestMapping("/v1/example/cat")
@Slf4j
public class CatController {

    @Autowired
    private CatServiceImpl catService;
    @Autowired
    private RedisClient redisClient;

    @ApiOperation("獲取信息")
    @GetMapping
    public ResultVO<String> getCat(@ApiParam("主鍵") @RequestHeader("cid") Integer cid) {
        Cat cat = catService.selectById(cid);
        if (cat != null) {
            // 測試緩存
            redisClient.setForTimeMIN("SOA:TEXMPLE:CAT:"+cid.toString(), JSON.toJSONString(cat), 30);
        }
        return new ResultVO(cat);
    }

    @ApiOperation("新增信息")
    @PostMapping
    public ResultVO<String> addCat(@RequestBody CatDto catDto) {
        Cat cat = new Cat();
        BeanCopierUtil.copy(catDto, cat);
        catService.insert(cat);
        return new ResultVO(Constants.RESULT_SUCCESS);
    }

    @ApiOperation("修改信息")
    @PutMapping
    public ResultVO<String> updateCat(@RequestBody CatDto catDto) {
        Cat cat = new Cat();
        BeanCopierUtil.copy(catDto, cat);
        catService.updateById(cat);
        return new ResultVO(Constants.RESULT_SUCCESS);
    }

    @ApiOperation("刪除信息")
    @DeleteMapping
    public ResultVO<String> deleteCat(@ApiParam("主鍵") @RequestHeader("cid") Integer cid) {
        catService.deleteById(cid);
        return new ResultVO(Constants.RESULT_SUCCESS);
    }
}

而後複製項目更更名稱爲cart-service,settings-gradle記得也改下
controller裏僅修改了路徑和類名CartControllerbootstrap

三、gateway集成微服務端

啓動類同樣複製一個過來,更名GatewayApplication
build.gradle文件增長依賴

compile (
            /** api文檔,包含前端ui包 */
            'com.github.xiaoymin:knife4j-spring-boot-starter:3.0.2',
            /**  nacos配置中心 */
            'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-config',
            /**  nacos註冊與發現中心 */
            'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery',
            'javax.servlet:javax.servlet-api:3.1.0',
            'org.springframework.cloud:spring-cloud-starter-gateway'
    )

下面增長一個配置類

package com.asan.gateway.config;

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.Configuration;
import org.springframework.context.annotation.Primary;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebFlux;

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

/**
 * @author Jaakko
 */
@Configuration
@Primary
@EnableSwagger2WebFlux
public class SwaggerResourceConfig implements SwaggerResourcesProvider {
    public static final String API_URI = "v2/api-docs";

    private final RouteLocator routeLocator;
    private final GatewayProperties gatewayProperties;

    public SwaggerResourceConfig(RouteLocator routeLocator, GatewayProperties gatewayProperties) {
        this.routeLocator = routeLocator;
        this.gatewayProperties = gatewayProperties;
    }

    @Override
    public List<SwaggerResource> get() {
        List<SwaggerResource> resources = new ArrayList<>();
        List<String> routes = new ArrayList<>();
        //獲取全部路由的ID
        routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
        //過濾出配置文件中定義的路由->過濾出Path Route Predicate->根據路徑拼接成api-docs路徑->生成SwaggerResource
        gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId())).forEach(route ->
            route.getPredicates().stream()
                    .filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
                    .forEach(predicateDefinition -> resources.add(swaggerResource(route.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;
    }
}

gateway nacos配置 

server: 
  port: 9200 
spring: 
  cloud: 
  gateway:
    #配置路由路徑 
    routes:
    - id: example 
      uri: lb://example 
      predicates: 
      - Path=/example/** 
      filters: 
      - StripPrefix=1 
    - id: cart-service 
      uri: lb://cart-service 
      predicates: 
      - Path=/cart-service/** 
      filters: 
      - StripPrefix=1 
    discovery: 
      locator: 
        #開啓從註冊中心動態建立路由的功能
        enabled: true
        #使用小寫服務名,默認是大寫
        lower-case-service-id: true

啓動兩個微服務端,再啓動gateway服務

瀏覽器訪問:localhost:9200/doc.html

這裏某些依賴手動加進去的,並未實際驗證!!!(你可能以爲坑,但八九不離十),可能存在兼容問題,大體應該能夠,有問題能夠留言討論!!!

效果圖這裏就不截了,自行玩耍

相關文章
相關標籤/搜索