集成 Spring Doc 介面文檔和 knife4j 前面已經集成 MyBatis Plus、Druid 數據源,開發了 5 個介面。在測試這 5 個介面時使用了 HTTP Client 或 PostMan,無論是啥都比較麻煩:得自己寫請求地址 URL、請求參數等,於是多年前就出現了 Swagg... ...
優雅哥 SpringBoot 2.7.2 實戰基礎 - 04 -集成 Spring Doc 介面文檔和 knife4j
前面已經集成 MyBatis Plus、Druid 數據源,開發了 5 個介面。在測試這 5 個介面時使用了 HTTP Client 或 PostMan,無論是啥都比較麻煩:得自己寫請求地址 URL、請求參數等,於是多年前就出現了 Swagger 這個玩意。Swagger 可以自動生成介面文檔,還能很方便的測試各個介面。但不幸的是,MVN Repository 上面 Springfox Swagger2 的版本停止於 2020 年 7月,而寫下這篇文章是 2022 年 8 月,已經兩年過去沒有動靜了,與此同時,springdoc-openapi 悄然出現。
spring doc open api 支持 Open API 3、Swagger-ui等,可以很方便與 Spring Boot 整合,配置和使用與 Springfox Swagger2 類似。
1 集成 Spring Doc
1.1 添加依賴
springdoc-openapi 不是 Spring Framework 官方團隊開發的,而是社區項目,沒有包含在 spring-boot-dependencies
中。故需要先定義版本號:
<properties>
....
<springdoc-openapi-ui.version>1.6.9</springdoc-openapi-ui.version>
</properties>
添加依賴:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>${springdoc-openapi-ui.version}</version>
</dependency>
該依賴裡面使用了 swagger-ui,以HTML形式展示文檔。
1.2 編寫配置類
其實配置類寫不寫都可以,如果不寫配置類,就通過註解定義文檔信息就可以。創建類:com.yygnb.demo.config.SpringDocConfig
package com.yygnb.demo.config;
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringDocConfig {
private String title = "Hero SpringBoot Demo";
private String description = "Hero Demo for usage of Spring Boot";
private String version = "v0.0.1";
private String websiteName = "Hero Website";
private String websiteUrl = "http://www.yygnb.com";
@Bean
public OpenAPI heroOpenAPI() {
return new OpenAPI()
.info(new Info().title(title)
.description(description)
.version(version))
.externalDocs(new ExternalDocumentation().description(websiteName)
.url(websiteUrl));
}
}
上面的配置定義了展示的文檔的信息,與界面上對應關係如下:
在配置文件中除了可以配置文檔的信息,還可以配置文檔分組、Authorization 等,在後面的企業級實戰文章中會具體描寫,將會在網關層 spring cloud gateway 中集成所有微服務的介面。
1.3 配置yml
在 application.yml 配置 springdoc:
# 介面文檔
springdoc:
packages-to-scan: com.yygnb.demo.controller
swagger-ui:
enabled: true
這兩項不配置也可以,packages-to-scan 預設為啟動類所在的路徑;springdoc.swagger-ui.enabled 預設為true,配置後可以在不同的環境中開啟或關閉。
1.4 添加註解
springdoc-openapi 與 springfox-swagger2 提供的註解有很大差別:
swagger 2 | spring doc | 描述 |
---|---|---|
@Api | @Tag | 修飾 controller 類,類的說明 |
@ApiOperation | @Operation | 修飾 controller 中的介面方法,介面的說明 |
@ApiModel | @Schema | 修飾實體類,該實體的說明 |
@ApiModelProperty | @Schema | 修飾實體類的屬性,實體類中屬性的說明 |
@ApiImplicitParams | @Parameters | 介面參數集合 |
@ApiImplicitParam | @Parameter | 介面參數 |
@ApiParam | @Parameter | 介面參數 |
修改實體類 Computer
,添加 springdoc-openapi 註解:
@Schema(title = "電腦")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Computer implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@Schema(title = "尺寸")
private BigDecimal size;
@Schema(title = "操作系統")
private String operation;
@Schema(title = "年份")
private String year;
}
修改控制器 ComputerController,添加註解:
@Tag(name = "電腦相關介面")
@RequiredArgsConstructor
@RestController
@RequestMapping("/computer")
public class ComputerController {
private final IComputerService computerService;
@Operation(summary = "根據id查詢電腦")
@GetMapping("/{id}")
public Computer findById(
@Parameter(name = "id", required = true, description = "電腦id") @PathVariable Long id) {
return this.computerService.getById(id);
}
@Operation(summary = "分頁查詢電腦列表")
@Parameters(value = {
@Parameter(name = "page", description = "頁面,從1開始", example = "2"),
@Parameter(name = "size", description = "每頁大小", example = "10")
})
@GetMapping("/find-page/{page}/{size}")
public Page<Computer> findPage(@PathVariable Integer page, @PathVariable Integer size) {
return this.computerService.page(new Page<>(page, size));
}
@Operation(summary = "新增電腦")
@PostMapping()
public Computer save(@RequestBody Computer computer) {
computer.setId(null);
this.computerService.save(computer);
return computer;
}
@Operation(summary = "根據id修改電腦")
@PutMapping("/{id}")
public Computer update(
@Parameter(name = "id", required = true, description = "電腦id") @PathVariable Long id,
@RequestBody Computer computer) {
computer.setId(id);
this.computerService.updateById(computer);
return computer;
}
@Operation(summary = "根據id刪除電腦")
@DeleteMapping("/{id}")
@Parameter(name = "id", required = true, description = "電腦id")
public void delete(@PathVariable Long id) {
this.computerService.removeById(id);
}
}
1.5 運行測試
啟動服務,在瀏覽器中訪問:
http://localhost:9099/swagger-ui/index.html
2 api-docs
在文檔標題下麵有一個小鏈接:/v3/api-docs
,點擊該鏈接,會在新頁面中顯示一大坨 JSON 數據。
看似很無聊的數據,卻有著重大意義,swagger-ui 就是通過這些數據渲染出頁面的。此外,這些JSON數據在某種程度上可以簡化前端的開發及前後端網路請求的工作量。
hero-admin-ui
優雅哥正在開發的基於 Vue 3 + TypeScript 的開源項目 hero-admin-ui
,其特色就是基於 JSON Schema 的表單和列表。通過 JSON Schema 可以快速渲染出一個列表、表單,甚至是搜索頁和詳情表單頁。如果獨立使用 hero-admin-ui
,需要手動編寫 JSON Schema,但如果後端介面整合了 Swagger 或 Spring Doc,上面 api-docs
返回的 JSON,就包含了 JSON Schema,二者結合可以快速實現搜索頁、表單頁等。目前 hero-admin-ui 已發佈在 npmjs 上,也已經提交到 github上,大家可以搜索關鍵字 hero-admin-ui
查看。在後面的實戰篇中,前端部分將會使用這個組件庫實現前端頁面。
3 自定義配置
在 ”1.2 編寫配置類“ 一節,文檔信息都是寫死在代碼中的,如果多個微服務都要集成 spring doc,可以把前面寫的 SpringDocConfig 提取到公共模塊中,通過maven 依賴引用,在 application.yml 中配置不同的變數。
3.1 添加依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
配置該依賴的目的是在編寫 application.yml 時,自定義的屬性有代碼提示。它會生成配置元數據,無需自己手動編寫。
3.2 定義配置的實體類
創建 com.yygnb.demo.config.DocInfo,將 SpringDocConfig 中寫死的屬性都移到這個配置實體類中:
@Data
@Component
@ConfigurationProperties(prefix = "doc-info")
public class DocInfo {
private String title = "Demo Title";
private String description = "Demo Description";
private String version = "v0.0.1";
private String websiteName = "Demo Website";
private String websiteUrl = "http://www.yygnb.com";
}
註解 @ConfigurationProperties(prefix = "doc-info")
聲明配置屬性,在 application.yml 配置時就可以使用 doc-info。
3.3 重構 SpringDocConfig
在 SpringDocConfig 中引入 DocInfo,並通過構造函數進行註入:
@RequiredArgsConstructor
@Configuration
public class SpringDocConfig {
private final DocInfo docInfo;
@Bean
public OpenAPI springShopOpenAPI() {
return new OpenAPI()
.info(new Info().title(docInfo.getTitle())
.description(docInfo.getDescription())
.version(docInfo.getVersion()))
.externalDocs(new ExternalDocumentation().description(docInfo.getWebsiteName())
.url(docInfo.getWebsiteUrl()));
}
}
補充一個小點:註解 @RequiredArgsConstructor
是 lombok 中提供的,它等價於在類中編寫了方法:
public SpringDocConfig(DocInfo docInfo) {
this.docInfo = docInfo;
}
構造註入時,在構造函數中寫大量的屬性,毫無意義。既然已經使用了 @Data
註解,為啥不用 @RequiredArgsConstructor
呢?
3.4 使用自定義配置
自定義配置已經完成,可以在 application.yml 中使用 DocInfo 對應的配置了:
doc-info:
title: SpringBoot Demo演示
description: 學習 Spring Boot 2.7.2
DocInfo 所有屬性都定義了預設值,在 application.yml 可以覆蓋預設值,如上面的 title
和 description
屬性。重啟服務查看運行效果:
4 集成 knife4j
在之前 springfox-swagger 的時代,很多同學不喜歡 swagger-ui 的界面風格,會集成 knife4j 的 ui。Spring Doc 也可以集成 knife4j。
如果要使用 knife4j ,Spring Doc 的配置中需要添加分組配置,我們這裡添加一個最簡單的分組配置。
com.yygnb.demo.config.SpringDocConfig
@RequiredArgsConstructor
@Configuration
public class SpringDocConfig {
private final DocInfo docInfo;
@Bean
public OpenAPI heroOpenAPI() {
return new OpenAPI()
.info(new Info().title(docInfo.getTitle())
.description(docInfo.getDescription())
.version(docInfo.getVersion()))
.externalDocs(new ExternalDocumentation().description(docInfo.getWebsiteName())
.url(docInfo.getWebsiteUrl()));
}
@Bean
public GroupedOpenApi publicApi() {
return GroupedOpenApi.builder()
.group(docInfo.getTitle())
.pathsToMatch("/**")
.build();
}
}
如果不添加這個 GroupedOpenApi 實例,knife4j ui就顯示不出來。
在 pom.xml 中引入 knife4j
<properties>
...
<knife4j-springdoc-ui.version>3.0.3</knife4j-springdoc-ui.version>
</properties>
<dependencies>
...
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-springdoc-ui</artifactId>
<version>${knife4j-springdoc-ui.version}</version>
</dependency>
</dependencies>
啟動服務,訪問:
http://localhost:9099/doc.html
顯示 knife4j 的ui:
今日優雅哥(工\/youyacoder)學習結束,期待關註留言分享~~