首頁 > 軟體

swagger檔案增強工具knife4j使用圖文詳解

2022-08-22 18:01:09

使用原生的swagger作為介面檔案,功能不夠強大,並且預設的ui比較簡陋,不符合大眾審美。所以實際開發中推薦使用knife4j對swagger進行增強。knife4j的地址:https://gitee.com/xiaoym/knife4j

推薦閱讀:Swagger及knife4j的基本使用詳解

基本使用

想要使用knife4j非常簡單,只要在Springboot專案中引入knife4j的依賴即可

<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-boot-starter</artifactId>
    <version>2.0.9</version>
</dependency>

注意:引入knife4j後會自動引入swagger相關依賴

所以無需再手動引入swagger相關依賴,否則會引起版本衝突,在使用knife4j的一些增強功能時會報錯

我們首先搭建springboot環境,建立2個Controller,用swagger相關注解來描述

// Controller1
@RestController
@RequestMapping("controller1")
@Api(tags = "應用1-Controller1")
public class Controller1 {
    @GetMapping("api1/{id}")
    @ApiOperation("api1")
    public void api1(@PathVariable("id") @ApiParam("使用者id") Long id) {

    }

    @PostMapping("api2")
    @ApiOperation("api2")
    public void api2(@RequestBody User user) {

    }
}

// Controller2
@RestController
@RequestMapping("controller2")
@Api(tags = "應用1-Controller2")
public class Controller2 {
    @GetMapping("api1/{id}")
    @ApiOperation("api1")
    public void api1(@PathVariable("id") @ApiParam("使用者id") Long id) {

    }

    @PostMapping("api2")
    @ApiOperation("api2")
    public void api2(@RequestBody User user) {

    }
}

// 實體類
@Data
@ApiModel("使用者實體")
public class User {
    @ApiModelProperty("姓名")
    private String name;
    @ApiModelProperty("年齡")
    private Integer age;
}

然後建立swagger設定類

@Configuration
@EnableSwagger2WebMvc
public class SwaggerConfig {
    // 建立Docket存入容器,Docket代表一個介面檔案
    @Bean
    public Docket webApiConfig(){
        return new Docket(DocumentationType.SWAGGER_2)
                // 建立介面檔案的具體資訊
                .apiInfo(webApiInfo())
                // 建立選擇器,控制哪些介面被加入檔案
                .select()
                // 指定@ApiOperation標註的介面被加入檔案
                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                .build();
    }

    // 建立介面檔案的具體資訊,會顯示在介面檔案頁面中
    private ApiInfo webApiInfo(){
        return new ApiInfoBuilder()
                // 檔案標題
                .title("標題:使用者管理系統介面檔案")
                // 檔案描述
                .description("描述:本檔案描述了使用者管理系統的介面定義")
                // 版本
                .version("1.0")
                // 聯絡人資訊
                .contact(new Contact("baobao", "http://baobao.com", "baobao@qq.com"))
                // 版權
                .license("baobao")
                // 版權地址
                .licenseUrl("http://www.baobao.com")
                .build();
    }
}

此時啟動專案,存取ip:埠/doc.html即可看到knife4j的檔案介面

增強功能

使用knife4j增強功能的前提是要在yaml設定中開啟增強模式

knife4j:
  enable: true

1.新增介面作者

swagger只能給整個檔案新增作者,不能針對某個介面單獨新增作者。knife4j中可以有2種方式給介面新增作者:

  • 在Controller類上標註@ApiSupport(author = "作者名稱"),這樣整個Controller中的所有介面方法將被指定為該作者
  • 在Controller介面方法上標註@ApiOperationSupport(author = "作者名稱"),這樣該介面被指定為該作者

如果@ApiSupport@ApiOperationSupport同時指定了作者,那麼方法級別的@ApiOperationSupport優先順序更高

2.生產環境關閉檔案

目前Springfox-Swagger以及Knife4j提供的資源介面包括如下:

資源說明
/doc.htmlKnife4j提供的檔案存取地址
/v2/api-docs-extKnife4j提供的增強介面地址,自2.0.6版本後刪除
/swagger-resourcesSpringfox-Swagger提供的分組介面
/v2/api-docsSpringfox-Swagger提供的分組範例詳情介面
/swagger-ui.htmlSpringfox-Swagger提供的檔案存取地址
/swagger-resources/configuration/uiSpringfox-Swagger提供
/swagger-resources/configuration/securitySpringfox-Swagger提供

swagger中要實現生產環境關閉檔案資源需要在設定類中進行編碼,判斷環境,比較麻煩。knife4j中只需要在對應環境的設定中新增設定即可

spring:
  profiles: prod # 指定為生產環境
knife4j:
  production: true # 開啟遮蔽檔案資源

此時只要以prod環境執行,就無法存取到介面檔案

注意:如果正常非生產環境下不遮蔽檔案,那麼引入了springsecurtiy或者自定義攔截器的時候,要排除掉上述表格中的檔案資源,否則在非遮蔽狀態下也將無法存取到檔案資源

3.介面排序

介面排序的方式有2種:

針對不同Controller排序:Controller上標註@ApiSupport(order = 序號)

針對同一個Controller中的不同方法排序:同一個Controller不同介面方法上標註@ApiOperationSupport(order = 序號)

4.匯出離線檔案

  • markdown:匯出當前邏輯分組下所有介面的Markdown格式的檔案
  • Html:匯出當前邏輯分組下所有介面的Html格式的檔案
  • Word:匯出當前邏輯分組下所有介面的Word格式的檔案(自2.0.5版本開始)
  • OpenAPI:匯出當前邏輯分組下的原始OpenAPI的規範json結構(自2.0.6版本開始)
  • PDF:未實現

5.過濾請求引數

通常我們在開發介面時,比如一個新增介面和一個修改介面,修改介面需要傳遞主鍵id、而新增介面則不需要傳遞此屬性,但大部分情況,我們只寫一個Model類,此時在新增介面時顯示主鍵id會顯得很多餘。使用自定義增強註解@ApiOperationSupport中的ignoreParameters屬性,可以強制忽略要顯示的引數

5.1 忽略表單引數

我們給User實體新增一個id屬性

然後新增一個新增使用者的介面方法,用表單方式接收引數,但是忽略掉id。在@ApiOperationSupport中的ignoreParameters屬性中填寫忽略的屬性名稱即可

@PostMapping("addUser")
@ApiOperation("新增使用者")
@ApiOperationSupport(ignoreParameters = "id") // 忽略掉User中的id屬性,不顯示在檔案中
public void addUser(User user) {
}

注意:

  • ignoreParameters支援以陣列形式新增多個忽略引數
  • ignoreParameters支援忽略級聯物件的引數,比如User實體類中有個Address型別的屬性addr,那麼如果想要忽略Address的屬性id,那麼只需要設定為ignoreParameters = "addr.id"即可
  • 如果要忽略的引數過多,可以使用includeParameters反向設定

5.2 忽略json引數

如果是以@RequestBody形式接收引數,那麼ignoreParameters中填寫引數名.要忽略的屬性名即可

@PostMapping("addUser2")
@ApiOperation("新增使用者2")
@ApiOperationSupport(ignoreParameters = {"user.id", "user.age"})
public void addUser2(@RequestBody User user) {
}

注意

  • ignoreParameters支援以陣列形式新增多個忽略引數
  • ignoreParameters支援忽略級聯物件的引數,比如User實體類中有個Address型別的屬性addr,那麼如果想要忽略Address的屬性id,那麼只需要設定為ignoreParameters = "user.addr.id"即可
  • 如果要忽略的引數過多,可以使用includeParameters反向設定

6.AfterScript

AfterScript功能是Knife4j自2.0.6版本開始新增的一項特性功能,在每個介面進行偵錯Tab中,開發者可以根據Knife4j提供的全域性變數,在介面呼叫之前編寫一段JavaScript指令碼,當介面呼叫成功後,Knife4j會執行該指令碼

主要應用場景:針對JWT型別的介面,呼叫登入介面後,每個介面請求時帶上Token引數,此時可以通過該指令碼動態賦值全域性token引數,省去複製貼上的麻煩

Knife4j目前主要提供ke(Knife4j Environment)物件來獲取或者操作全域性物件,主要包含的物件:

  • global:全域性操作,可以獲取或者設定目前的全域性引數
  • setHeader(name,value):設定當前邏輯分組下的全域性引數Header請求頭
  • setAllHeader(name,value):設定所有邏輯分組下的全域性引數Header請求頭
  • setParameter(name,value):設定當前邏輯分組下,主要是針對query型別引數進行設定全域性設定。
  • setAllParameter(name,value):設定所有邏輯分組下的全域性引數,主要是query型別
  • response:當前請求介面響應內容
  • headers:伺服器端響應Header物件,注意,此處所有的header的名稱全部進行小寫轉換
  • data:伺服器端響應資料(json/xml/text等等)

我們新增一個登入介面,返回token引數

@PostMapping("login")
@ApiOperation("登入")
public Map<String, Object> login() {
    Map<String, Object> result = new HashMap<>(2);
    result.put("success", true);
    result.put("token", "1364564646");
    return result;
}

然後在knife4j檔案中針對這個登入介面編寫AfterScript,取出返回的token,設定到每一個請求的請求頭中

var success=ke.response.data.success;
if(success===true){
    // 獲取token
    var token=ke.response.data.token;
    // 設定當前邏輯分組下的全域性Header
    ke.global.setHeader("Authorization", "Bearer " + token);
}

這樣的效果是,請求login介面成功返回token後,後續偵錯其他所有介面時會自動給請求頭中新增token引數,無需手動新增

7.全域性引數

Knife4j提供基於UI臨時設定全域性引數功能,例如後臺全域性token引數等.提供該功能主要是方便開發者進行偵錯

目前全域性引數功能主要提供兩種引數型別:query(表單)、header(請求頭)

如果後端Swagger有設定全域性引數,該功能可以無視

微服務檔案聚合

在微服務架構下,如果給每個微服務都設定檔案,那麼每個微服務的介面檔案都有自己獨立的存取地址,這樣要一個個開啟每個微服務的檔案非常麻煩。一般我們會採用聚合的辦法,將所有微服務的介面整合到一個檔案中

傳統的整合方法需要在gateway中進行大量設定,十分繁瑣。自2.0.8版本開始,Knife4j 提供了knife4j-aggregation-spring-boot-starter元件,該元件是一個基於Spring Boot系統的starter,他提供了以下幾種能力:

  • 最輕量級、最簡單、最方便的聚合OpenApi規範的中介軟體
  • 讓所有的基於Spring Boot的Web體系擁有了輕鬆聚合OpenApi的能力
  • 提供4種模式供開發者選擇
  • 基於本地靜態JSON檔案的方式聚合OpenAPI
  • 基於雲端HTTP介面的方式聚合
  • 基於Eureka註冊中心的方式聚合
  • 基於Nacos註冊中心的方式聚合
  • 基於該starter釋出了Docker映象,跨平臺與語言讓開發者基於此Docker映象輕鬆進行聚合OpenAPI規範
  • 完美相容所有Spring Boot版本,沒有相容性問題
  • 開發者可以徹底放棄基於Zuul、Spring Cloud Gateway等複雜的聚合方式
  • 相容OpenAPI2規範以及OpenAPI3規範

目前Knife4jAggregation主要提供了四種方式進行OpenAPI檔案的聚合,主要包括:

基於OpenAPI的靜態JSON檔案方式,Disk模式
基於HTTP介面的方式獲取OpenAPI,Cloud模式
基於Eureka註冊中心獲取OpenAPI,Eureka模式
基於Nacos註冊中心獲取OpenAPI,Nacos模式

Disk、Cloud、Eureka、Nacos這四種模式只能使用其中1種,不能混合一起使用(即只能設定這4中模式中的一種屬性,然後將其enable屬性設定為true,其他三種的enable則必須設定為false)

利用knife4j進行檔案聚合的步驟非常簡單:

1.建立一個SpringBoot專案,用於聚合檔案,引入下列依賴

 <dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-aggregation-spring-boot-starter</artifactId>
    <version>2.0.9</version>
</dependency>

2.設定需要聚合的檔案的地址

3.存取該聚合檔案的地址,即可存取到被聚合的所有介面檔案

1.Cloud模式

cloud模式原理是,在聚合檔案工程設定每個微服務的http介面資源地址,這樣聚合檔案工程啟動的時候可以存取到每個微服務的http介面檔案資源地址,從而聚合每個微服務的介面檔案

這種方式可以用在沒有註冊中心,每個SpringBoot微服務單獨啟動的場景由於聚合檔案工程需要能存取到每個微服務的http介面檔案資源地址才能做聚合,所以在聚合檔案工程啟動之前要先啟動需要被聚合的每個微服務,並且每個微服務自己要做好swagger檔案的相關設定

為了測試聚合檔案,我們首先複製出一個SpringBoot工程knife4j-app2作為第2個微服務,其主要設定與knife4j-app1一樣,只是部分地方作了名稱修改。然後再建立一個聚合檔案工程knife4j-agg-doc

在聚合檔案工程knife4j-agg-doc中引入依賴

 <dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-aggregation-spring-boot-starter</artifactId>
    <version>2.0.9</version>
</dependency>

cloud模式中,yaml的設定範例如下:

knife4j:
  enableAggregation: true
  cloud:
    enable: true
    routes:
      - name: 使用者體系
        uri: 192.168.0.152:8999
        location: /v2/api-docs?group=2.X版本
        swaggerVersion: 2.0
        servicePath: /abbb/ffe
        routeAuth:
          enable: true
          username: test3
          password: 66666
    routeAuth:
      enable: true
      username: test
      password: 12313
  • knife4j.cloud.enable:將該屬性設定為true,則代表啟用Cloud模式
  • knife4j.cloud.routeAuth:該屬性是一個公共Basic驗證屬性(可選),如果開發者提供的OpenAPI規範的HTTP介面需要以Basic驗證進行鑑權存取,那麼可以設定該屬性,如果設定該屬性,則該模式下所有設定的Routes節點介面都會以Basic驗證資訊存取介面
  • knife4j.cloud.routeAuth.enable:是否啟用Basic驗證
  • knife4j.cloud.routeAuth.usernae:Basic使用者名稱
  • knife4j.cloud.routeAuth.password:Basic密碼
  • knife4j.cloud.routes:需要聚合的服務集合(必選),可以設定多個
  • knife4j.cloud.routes.name:服務名稱(顯示名稱,最終在Ui的左上角下拉框進行顯示)
  • knife4j.cloud.routes.uri:該服務的介面URI資源,如果是HTTPS,則需要完整設定
  • knife4j.cloud.routes.location::具體資源介面地址,最終Knife4j是通過uri+location的組合路徑進行存取
  • knife4j.cloud.routes.swaggerVersion:版本號,預設是2.0,可選設定
  • knife4j.cloud.routes.servicePath:該屬性是最終在Ui中展示的介面字首屬性,提供該屬性的目的也是因為通常開發者在以Gateway等方式聚合時,需要一個字首路徑來進行轉發,而最終這個字首路徑會在每個介面中進行追加
  • knife4j.cloud.routes.routeAuth:如果該Route節點的介面開啟了Basic,並且和公共設定的Basic不一樣,需要單獨設定
  • knife4j.cloud.routes.routeAuth.enable:是否啟用Basic驗證
  • knife4j.cloud.routes.routeAuth.usernae:Basic使用者名稱
  • knife4j.cloud.routes.routeAuth.password:Basic密碼

我們在knife4j-agg-doc的yaml中做如下設定

server:
  port: 8010

knife4j:
  enableAggregation: true  # 開啟聚合
  cloud:
    enable: true  # 開啟cloud模式
    routes: 
      - name: 應用1    # 微服務在聚合檔案中的名稱
        uri: localhost:8000  # 微服務的http地址
        location: /v2/api-docs # 微服務檔案資源路徑
        servicePath: /api/app1 # 給每個介面新增路徑字首,作用是拼接出經過nginx和gateway處理前的實際介面url
      - name: 應用2
        uri: localhost:8001
        location: /v2/api-docs?group=default
        servicePath: /api/app2

然後先啟動knife4j-app1knife4j-app2,再啟動knife4j-agg-doc,存取knife4j-agg-doc的地址http://localhost:8010/doc.html即可看到聚合後的檔案

  • 可以發現,不同的微服務是以不同分組的形式出現在聚合檔案中,所以實際上設定檔案聚合是聚合某個微服務中的某個分組
  • 在設定routes.location的時候,可以指定分組引數group,預設不指定代表group=default。這也意味著,我們不止可以細化到每個微服務,還可以細化到一個微服務的不同分組。如果每個微服務的swagger檔案中設定了多個分組,可以聚合每一個分組,這樣聚合檔案中可以區分選擇某一個微服務下具體分組的檔案
  • 實際開發中一般情況下不建議在一個微服務中再進行分組,否則不好管理。每個微服務都用預設分組,直接以微服務為單位聚合檔案即可清晰區分開每個微服務的介面

2.Nacos模式

Nacos模式原理是,在聚合檔案工程設定每個微服務的Nacos註冊中心地址和服務名稱,這樣聚合檔案工程啟動的時候可以從Nacos存取到每個微服務的http介面檔案資源地址,從而聚合每個微服務的介面檔案

  • 這種方式適合以Nacos作為微服務註冊中心的場景
  • 由於聚合檔案工程需要能存取到Nacos獲取每個微服務的資訊才能做聚合,所以在聚合檔案工程啟動之前要先啟動Nacos和需要被聚合的每個微服務,並且每個微服務要成功註冊到Nacos中
  • 每個微服務自己要做好swagger檔案的相關設定

為了測試Nacos模式,首先在每個微服務中引入nacos相關依賴和設定,並啟動Nacos和微服務,將它們註冊到Nacos中

Nacos模式的可選設定如下

knife4j:
  enableAggregation: true
  nacos:
    enable: true
    serviceUrl: http://192.168.0.112:8804/nacos/
    routeAuth:
      enable: true
      username: test
      password: 12313
    routes:
      - name: 訂單服務
        serviceName: service-order
        groupName: test
        namespaceId: test
        clusters: test
        location: /v2/api-docs?group=default
        swaggerVersion: 2.0
        servicePath: /order
        routeAuth:
          enable: true
          username: test
          password: 12313
  • knife4j.nacos.enable:將該屬性設定為true,則代表啟用nacos模式
  • knife4j.nacos.serviceUrl:nacos註冊中心的地址
  • knife4j.nacos.routeAuth:該屬性是一個公共Basic驗證屬性(可選),如果開發者提供的OpenAPI規範的服務需要以Basic驗證進行鑑權存取,那麼可以設定該屬性,如果設定該屬性,則該模式下所有設定的Routes節點介面都會以Basic驗證資訊存取介面
  • knife4j.nacos.routeAuth.enable:是否啟用Basic驗證
  • knife4j.nacos.routeAuth.usernae:Basic使用者名稱
  • knife4j.nacos.routeAuth.password:Basic密碼
  • knife4j.nacos.routes:需要聚合的服務集合(必選),可以設定多個
  • knife4j.nacos.routes.name:服務名稱(顯示名稱,最終在Ui的左上角下拉框進行顯示),如果該屬性不設定,最終Ui會顯示serviceName
  • knife4j.nacos.routes.serviceName:nacos註冊中心的服務名稱
  • knife4j.nacos.routes.groupName:Nacos分組名稱,非必須,開發者根據自己的實際情況進行設定
  • knife4j.nacos.routes.namespaceId:名稱空間id,非必須,開發者根據自己的實際情況進行設定
  • knife4j.nacos.routes.clusters:叢集名稱,多個叢集用逗號分隔,非必須,開發者根據自己的實際情況進行設定
  • knife4j.nacos.routes.uri:該服務的介面URI資源,如果是HTTPS,則需要完整設定
  • knife4j.nacos.routes.location::具體資源介面地址,最終Knife4j是通過註冊服務uri+location的組合路徑進行存取
  • knife4j.nacos.routes.swaggerVersion:版本號,預設是2.0,可選設定
  • knife4j.nacos.routes.servicePath:該屬性是最終在Ui中展示的介面字首屬性,提供該屬性的目的也是因為通常開發者在以Gateway等方式聚合時,需要一個字首路徑來進行轉發,而最終這個字首路徑會在每個介面中進行追加
  • knife4j.nacos.routes.routeAuth:如果該Route節點的介面開啟了Basic,並且和公共設定的Basic不一樣,需要單獨設定
  • knife4j.nacos.routes.routeAuth.enable:是否啟用Basic驗證
  • knife4j.nacos.routes.routeAuth.usernae:Basic使用者名稱
  • knife4j.nacos.routes.routeAuth.password:Basic密碼

我們在聚合檔案工程knife4j-agg-doc的yaml中做如下設定

server:
  port: 8010

knife4j:
  enableAggregation: true
  nacos:
    enable: true  # 開啟Nacos模式
    serviceUrl: http://localhost:8848/nacos # Nacos註冊中心地址
    routes:
      - name: 應用1  # 微服務在聚合檔案中的名稱
        serviceName: APP1  # 微服務在Nacos註冊中心的名稱
        location: /v2/api-docs # 微服務檔案資源路徑
        servicePath: /api/app1 # 給每個介面新增路徑字首,作用是拼接出經過nginx和gateway處理前的實際介面url
      - name: 應用2
        serviceName: APP2
        location: /v2/api-docs
        servicePath: /api/app2

啟動聚合檔案工程,存取http://localhost:8010/doc.html檢視聚合檔案

到此這篇關於swagger檔案增強工具knife4j使用詳解的文章就介紹到這了,更多相關swagger檔案增強工具knife4j內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com