JAVA中讓Swagger產出更加符合我們訴求的描述檔案,按需決定顯示或者隱藏指定內容

2022-09-08 12:05:21

大家好,又見面啦。

在前一篇檔案《JAVA中自定義擴充套件Swagger的能力,自動生成引數取值含義說明,提升開發效率》中,我們探討了如何通過自定義註解的方式擴充套件swagger的能力讓Swagger支援自動從指定的列舉類生成介面檔案中的欄位描述的實現思路。

其實swagger作為一個被廣泛使用的線上介面檔案輔助工具,上手會用很容易,但想用好卻還是需要一定功夫的。所以呢,本篇檔案就和大家一起來聊一聊如何用好swagger,讓其真正的成為我們專案交付過程中的神兵利器

更改介面檔案總標題與描述

預設的情況下,Swagger的介面整個檔案的名稱以及描述內容都是通用值,這會讓人拿到檔案之後比較困惑,無法知曉這是哪個專案哪個系統哪個服務提供的介面,也不知道介面是哪個團隊負責,哪位開發人員維護的。

比如下面這樣:

為了體現出介面檔案的專業性,讓人更容易知曉此介面檔案所屬系統對應版本維護團隊等資訊,我們可以在程式碼中根據需要自定義相關的內容。

比如:

@Bean
public Docket createRestApi() {
    ApiInfo apiInfo = new ApiInfoBuilder()
        .title("資源管理系統介面檔案")
        .description("資源管理模組對外供APP/WEB端呼叫的介面詳細檔案描述")
        .version("v1.0.0")
        .contact(new Contact("架構悟道", "https://juejin.cn/user/1028798616709294","[email protected]"))
        .termsOfServiceUrl("https://juejin.cn/user/1028798616709294")
        .license("Apache License")
        .licenseUrl("http://xxx")
        .build();
    return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo).select().build();
}

重新啟動並檢視介面,可以發現介面上相關內容已經變更為我們自定義的內容了,是不是比改動前顯得更加明晰與專業了?

上述swagger中支援自定義的描述性的欄位資訊,梳理如下:

欄位 含義描述
title 介面檔案的檔案標題
description 介面檔案的詳細整體描述說明
version 介面檔案對應的版本資訊
termsOfServiceUrl 此介面檔案的提供團隊對應的團隊url地址
contact 負責此部分介面的聯絡人資訊,包含姓名郵箱主頁url地址等
license 指定介面所遵循的License協定版本
licenseUrl 此介面所遵循的License協定對應的詳細介紹url地址

按需顯示/隱藏相關介面內容

手動編寫介面檔案的時候,我們可以根據實際情況靈活的去控制需要寫入到檔案中的介面內容、以及介面的請求響應體中的欄位資訊 —— 因為並不是系統中提供的所有的介面都需要體現在介面檔案中暴露給呼叫方去知曉的,比如有一些系統狀態監控類的介面,只需要內部使用即可。

對於Swagger而言,生成介面檔案的時候,預設是掃描所有的@Controller中的全部介面方法全部顯示到檔案中,但其也貼心地考慮到了實際應用中的這種按需隱藏或者展示介面內容的訴求,並提供了多種不同的方式來支援。

下面一起來看下。

針對單個介面進行隱藏

在單個介面方法的上方新增 @ApiOperation 註解說明,並指定 hidden = true即可將該介面從swagger介面能上隱藏:

@GetMapping("/test")
@ApiOperation(value = "內部測試介面", hidden = true)
public String test() {
    return "OK";
}

啟動程序,檢視Swagger介面,發現該介面沒有出現在介面上:

隱藏整個Controller類中的介面

如果整個Controller類下面所有的介面都需要隱藏,則可以在Conntroller類上新增上@ApiIgnore註解可以了。

@RestController
@RequestMapping("/test")
@ApiIgnore
public class TestController {
// ... ignore ...
}

改動後重啟程序,再開啟swagger介面,發現TestController整個類的介面都沒有顯示。

這裡補充一句,因為用於描述Controller類的介面含義的註解@Api中也有個hidden屬性,而且看其原始碼註釋說明,如果設定hidden=true,應該也是將該Controller類整體隱藏。但是實際上測試發現並沒有生效,這個實際使用的時候要小心這一點(基於swagger 2.7.0版本試驗,不確定是否為BUG)。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Api {
    /**
     * Hides the operations under this resource.
     *
     * @return true if the api should be hidden from the swagger documentation
     */
    boolean hidden() default false;
}

僅顯示指定package路徑下的介面

我們的專案裡面經常會依賴或者參照一些三方jar包,而這些三方jar中有的時候也會提供一些介面,也會出現在我們的介面檔案中,這樣就會顯得介面檔案中存在很多不確定的內容

比如:

因為這部分邏輯並非業務程式碼中提供的,所以我們沒法按照上面的方式,修改原始碼新增hidden=true的方式來控制其不顯示。這個時候,就需要按照package進行白名單控制的能力了。swagger還支援根據給定的basePackage以及paths進行組合控制,僅顯示給定包下指定路徑下的介面。


@Bean
public Docket createRestApi() {
    ApiInfo apiInfo = new ApiInfoBuilder()
            .title("資源管理系統介面檔案")
            .description("資源管理模組對外供APP/WEB端呼叫的介面詳細檔案描述")
            .version("v1.0.0")
            .build();
    ApiSelectorBuilder selectorBuilder = (new Docket(DocumentationType.SWAGGER_2)).apiInfo(apiInfo).select();
    selectorBuilder.apis(RequestHandlerSelectors.basePackage("com.jiagouwudao.resmanage"));
    selectorBuilder.paths(PathSelectors.any());
    return selectorBuilder.build();
}

這樣就可以保證出現在介面檔案裡面的都是我們自己定義的介面了。重新啟動並重新整理介面,會發現,只有指定package目錄下的Controller介面顯示在swagger介面上了。

隱藏響應中不願暴露的屬性

在專案開發過程中,如果我們的程式碼沒有做強制的VODO隔斷,出於減少編碼量考慮,可能會使用同一個物件進行內部處理以及外部互動。比如:

定義一個OperateLog物件,為資料庫中T_OPERATE_LOG表所對應的實體類,用於記錄每個使用者的操作行為;同時也作為recordOperateLog介面的請求Body體,用於傳遞需要記錄的使用者操作資訊。

在上面的例子中:

  • 作為資料表實體類進行邏輯處理的時候,需要用到唯一主鍵id資訊
  • 作為recordOperateLog介面的請求Body體時,呼叫方是不需要指定這條記錄的ID值的(ID值會在儲存到DB的時候自動由DB生成唯一自增主鍵)

這種場景下,我們就希望提供出去的介面檔案中,在對recordOperateLog介面的請求body體中欄位說明的時候,就不要體現出id欄位,避免讓呼叫方產生疑惑,不知道id呼叫的時候應該如何賦值。我們可以通過在指定欄位上新增@ApiModelProperty註解並指定hidden = true來將其從介面檔案中隱藏掉。

比如:

@Data
@ApiModel("操作記錄資訊")
public class OperateLog {
    @ApiModelProperty(value = "記錄唯一ID,無實際意義", hidden = true)
    private long id;
    @ApiModelProperty("操作型別,取值說明: 1,新增;2,更新;3,刪除;4,查詢")
    private int operateType;
    @ApiModelProperty("操作使用者")
    private String user;
    @ApiModelProperty(value = "操作詳情")
    private String detail;
}

則介面中的介面檔案不會顯示id的有關資訊(注意:僅介面檔案中不體現,不會影響具體請求或者響應中此欄位的實際值)。

關閉生產環境的swagger

考慮到生產環境的安全性,對於一些比較重要的系統,我們一般不太願意將生產環境的介面檔案暴露出來,避免對系統的執行埋下隱患。

SpringBoot專案中,我們會為不同的環境提供不同的組態檔, 然後在啟動的時候使用 --spring.active.profile 來指定載入哪一份設定。

如果需要使Swagger可以被存取,我們可以通過程式碼中新增@EnableSwagger2註解的方式來實現。若限制僅在開發或測試環境上允許swagger存取而生產環境不允許開啟,則只需要讓這個新增了@EnableSwagger2註解的類根據當前的執行環境來決定是否載入就可以了。藉助SpringBoot提供的@Profile註解,我們可以這樣來實現:

@Configuration
@EnableSwagger2
@Profile({"DEV", "TEST"})
public class SwaggerConfig {

}

這樣,就可以讓SwaggerConfig類在profile=PROD的時候不會被載入,也就不會開啟swagger的開關。使用 --spring.active.profile=PROD啟動程序,嘗試存取swagger介面,會發現無法開啟:

給Swagger換個面板

預設的swagger介面所有內容都羅列居中顯示,然後需要一層層的展開去,操作上面不太方便,整體介面風格也不太符合一個「檔案」的樣子。為了提升使用體驗,可以藉助開源的knife4j框架來讓swagger變得更加好用。

使用方式很簡單,在已有的swagger依賴的基礎上,在pom.xml中新增如下參照依賴:

<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-ui</artifactId>
    <version>2.0.4</version>
</dependency>

啟動程序後,存取 doc.html 頁面,比如 http://127.0.0.1:8088/doc.html,可以發現一個更加符合介面檔案體驗的新的介面:

當然,這裡我們使用了knife4j最簡單的一個「換膚」的特性,而作為一款優秀的開源工具,knife4j所提供的能力遠不止這些,有興趣的可以點選此處詳細瞭解一下。

總結

好啦,關於如何補全Swagger介面的描述內容、如何自主決定某些內容的顯示與隱藏等相關的內容,這裡就給大家分享到這裡啦。關於本篇內容你有什麼自己的想法或獨到見解麼?歡迎在評論區一起交流探討下吧。