Spring Cloud Gateway 整合 Springfox 3.0.0 實現OpenAPI 3 文檔管理


一、前言

OpenAPI 簡介

OpenAPI規范是一個由社區驅動的開放規范,這個規范定義了一個標准的、語言無關的 RESTful API 接口規范,它可以同時允許開發人員和操作系統查看並理解某個服務的功能,而無需訪問源代碼,文檔或網絡流量檢查。合理地定義OpenAPI規范,能使開發者更好的理解遠程服務和與之交互。目前最新的規范是OpenAPI Specification 3.0.3。

Swagger簡介

Swagger是一個規范和完整的框架,用於生成 、描述、調用和可視化 RESTful 風格的 Web 服務,簡化了開發者開發API。

Springfox簡介

SpringFox是 Spring 社區非官方維護的一個項目,主要就是幫助使用者將Swagger集成到Spring 中,在停更了2年多之后,近期終於推出了3.0.0版本,支持了開發者期盼已久的OpenApi 3規范。

二、Springfox 3.0.0 在Spring Boot 項目下的用法

導入依賴(Gradle)

implementation('io.springfox:springfox-boot-starter:3.0.0')

開啟注解

@EnableOpenApi

編寫配置類

/**
 * @author Vieruodis
 * @description Springfox openApi 3.0 的配置類
 * @date 2020/7/15  21:43
 */
@Configuration
@EnableOpenApi
public class SpringfoxOpenApiConfig {

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.OAS_30)
            .pathMapping("/")
                // 定義是否開啟swagger,false為關閉,可以通過變量控制
                .enable(true)
                // 將api的元信息設置為包含在json ResourceListing響應中。
                .apiInfo(apiInfo())
                // 選擇哪些接口作為swagger的doc發布
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.vieruodis.vmall.manage.product.controller"))
                .paths(PathSelectors.any())
                .build()
                .groupName("defaultBB")
                // 支持的通訊協議集合
                .protocols(Set.of("https", "http"))
                ;
    }

    /**
     * API 頁面上半部分展示信息
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .version("1.0.0")
                .title("Vieruodis Api Doc")
                .description("Vmall shop application")
                .contact(new Contact("Vieruodis", null, "huaiyuan0660@outlook.com"))
                .termsOfServiceUrl("http://localhost:88/")
                .license("Apache 2.0")
                .licenseUrl("https://www.apache.org/licenses/LICENSE-2.0.html")
                .build();
    }
}

編寫Controller的注解

@Api(value = "AlbumController")
public interface AlbumControllerApi {

    /**
     * Album 多條件分頁查詢
     *
     * @param page  頁碼
     * @param size  每頁數
     * @param album 查詢條件
     * @return 封裝了 【Album 分頁數據】 的響應結果
     */
    @ApiOperation(value = "Album條件分頁查詢",notes = "分頁條件查詢Album方法詳情",tags = {"AlbumController"})
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "path", name = "page", value = "當前頁", required = true, dataType = "Integer"),
            @ApiImplicitParam(paramType = "path", name = "size", value = "每頁顯示條數", required = true, dataType = "Integer")
    })
    PageResponseResult<Album> findPage(int page, int size, @ApiParam(name = "Album對象",value = "傳入JSON數據") Album album);

    /**
     * Album 分頁查詢
     *
     * @param page 頁碼
     * @param size 每頁數
     * @return 封裝了 【Album 分頁數據】 的響應結果
     */
    @ApiOperation(value = "Album分頁查詢",notes = "分頁查詢Album方法詳情",tags = {"AlbumController"})
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "path", name = "page", value = "當前頁", required = true, dataType = "Integer"),
            @ApiImplicitParam(paramType = "path", name = "size", value = "每頁顯示條數", required = true, dataType = "Integer")
    })
    PageResponseResult<Album> findPage(int page, int size);

    /**
     * Album 多條件查詢
     *
     * @param album 查詢條件
     * @return 封裝了 【Album 數據集】 的響應結果
     */

    @ApiOperation(value = "Album條件查詢",notes = "條件查詢Album方法詳情",tags = {"AlbumController"})
    CommonResponseResult<List<Album>> findList(@ApiParam(name = "Album對象",value = "傳入JSON數據") Album album);

    /**
     * 查詢所有 Album
     *
     * @return 封裝了 【Album 數據集】 的響應結果
     */
    @ApiOperation(value = "查詢所有Album",notes = "查詢所Album有方法詳情",tags = {"AlbumController"})
    CommonResponseResult<List<Album>> findAll();

    /**
     * 根據ID查詢 Album
     *
     * @param id 實體ID
     * @return 封裝了 【Album 數據】 的響應結果
     */
    @ApiOperation(value = "Album根據ID查詢",notes = "根據ID查詢Album方法詳情",tags = {"AlbumController"})
    @ApiImplicitParam(paramType = "path", name = "id", value = "主鍵ID", required = true, dataType = "Long")
    CommonResponseResult<Album> findById(Long id);

    /**
     * 新增 Album
     *
     * @param album 新增實體
     * @return 通用響應結果
     */
    @ApiOperation(value = "Album添加",notes = "添加Album方法詳情",tags = {"AlbumController"})
    ResponseResult add(@ApiParam(name = "Album對象",value = "傳入JSON數據",required = true) Album album);

    /**
     * 修改 Album
     *
     * @param id    實體ID
     * @param album Album 數據
     * @return 通用響應結果
     */
    @ApiOperation(value = "Album根據ID修改",notes = "根據ID修改Album方法詳情",tags = {"AlbumController"})
    @ApiImplicitParam(paramType = "path", name = "id", value = "主鍵ID", required = true, dataType = "Long")
    ResponseResult update(Long id, @ApiParam(name = "Album對象",value = "傳入JSON數據") Album album);

    /**
     * 刪除 Album
     *
     * @param id 實體ID
     * @return 通用響應結果
     */
    @ApiOperation(value = "Album根據ID刪除",notes = "根據ID刪除Album方法詳情",tags = {"AlbumController"})
    @ApiImplicitParam(paramType = "path", name = "id", value = "主鍵ID", required = true, dataType = "Long")
    ResponseResult delete(Long id);

}

編寫實體的注解

@Data
@ApiModel(description = "Album",value = "Album")
@Entity
@Table(name="tb_album")
public class Album implements Serializable {

    /**
     * 編號
     */
    @ApiModelProperty(value = "編號")
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;
    /**
     * 相冊名稱
     */
    @ApiModelProperty(value = "相冊名稱")
    @Column(name = "title")
    private String title;
    /**
     * 相冊封面
     */
    @ApiModelProperty(value = "相冊封面")
    @Column(name = "image")
    private String image;
    /**
     * 圖片列表
     */
    @ApiModelProperty(value = "圖片列表")
    @Column(name = "image_items")
    private String imageItems;
}

測試

打開: http://localhost:8000/swagger-ui/index.html

三、與Spring Cloud Gateway集成

整合思路

1,定義一個SwaggerProvider類用於填充右上角下拉框的數據,格式是(name,oas3Url)

2,定義過濾器,對oas3Url進行修正,讓其能夠獲取文檔

實踐

導入依賴(Gradle)

implementation('io.springfox:springfox-boot-starter:3.0.0')

定義SwaggerProvider類填充右上角下拉框數據

@ConfigurationProperties(prefix = "open-api.swagger")
@EnableConfigurationProperties
@Component
@Primary
public class SwaggerProvider implements SwaggerResourcesProvider {

    @Setter
    @Getter
    private List<String> resources;

    public static final String API_URI = "/v3/api-docs";

    @Override
    public List<SwaggerResource> get() {
        List<SwaggerResource> swaggerResources = new ArrayList<>();
        resources.forEach(s -> {
            //name,oas3Url,group
            String[] split = s.split(",");
            swaggerResources.add(resource(split[0], split[1] + API_URI, split[2]));
        });
        return swaggerResources;
    }

    /**
     * @param name    顯示的名字
     * @param oas3Url 文檔格式:/manage/product/v3/api-docs(?group=...)
     */
    private SwaggerResource resource(
            String name,
            String oas3Url,
            String swaggerGroup) {
        SwaggerResource swaggerResource = new SwaggerResource();
        swaggerResource.setName(name);
        //url: 要看其他微服務是否設置了group 設置了的話
        if (Docket.DEFAULT_GROUP_NAME.equals(swaggerGroup)) {
            swaggerResource.setUrl(oas3Url);
        } else {
            //其他微服務是否設置了group 需要加上"?group=" + 組名
            swaggerResource.setUrl(oas3Url + "?group=" + swaggerGroup);
        }
        System.out.println("name: " + name + " url: " + oas3Url);
        swaggerResource.setSwaggerVersion("3.0.3");
        return swaggerResource;
    }

}

填充的數據來源於配置文件:

open-api:
  swagger:
    # 僅供 springfox 使用
    resources: # name,oas3Url,group
      - manage-product-service-1,/manage/product,defaultBB
      - manage-product-service-2,/manage/product,manage-product
      - file-service,/file,default

上面我給它填充的url是:localhost:端口號/【manage/product】/v3/api-docs(?group= ) 形式的,目的是為了讓它找到微服務,因為我的路由設置是:

spring:
  cloud:
    gateway:
      routes:
        - id: vmall-manage-product-service
          uri: lb://vmall-manage-product
          predicates:
            - Path=/manage/product/**

 但是Springfox獲取文檔的地址格式是:localhost:端口號/v3/api-docs(?group= ),所以我們需要定義一個過濾器,讓它能夠獲取到文檔:

@Component
public class SwaggerHeaderFilter extends AbstractGatewayFilterFactory {

    @Override
    public GatewayFilter apply(Object config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            String path = request.getURI().getPath();
            System.out.println("path:"+path);
            if (!StringUtils.endsWithIgnoreCase(path, SwaggerProvider.API_URI)) {
                return chain.filter(exchange);
            }
            ServerHttpRequest newRequest = request.mutate().path(SwaggerProvider.API_URI).build();
            ServerWebExchange newWebExchange = exchange.mutate().request(newRequest).build();
            return chain.filter(newWebExchange);
        };
    }
}

給路由配上過濾器: 

spring:
  cloud:
    gateway:
      routes:
        - id: vmall-manage-product-service
          uri: lb://vmall-manage-product
          predicates:
            - Path=/manage/product/**
          filters:
            - SwaggerHeaderFilter

 測試:

打開:http://localhost:88/swagger-ui/index.html 

測試調用文檔的方法,請求的是 localhost:88/manage/product/album , 這樣通過網關就能找到對應的微服務,並且正確返回json數據了。

四、總結 

Springfox3.0.0中支持了webflux,所以就不需要再寫swaggerHandler解決請求映射了,相比SpringDoc openApi整合Spring Cloud Gateway 比較簡單,個人比較推薦用來整合Spring Cloud Gateway。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM