JApiDocs是一個無需額外注解、開箱即用的SpringBoot接口文檔生成工具。
前言
編寫和維護API文檔,對於后端程序員來說,是一件惱人但又不得不做的事情,我們都不喜歡寫文檔,除非項目前后端代碼都是自己寫的,否則API文檔將是前后端協作不可或缺的溝通載體。
最佳實踐是:先把接口設計好,在Mock的方法上寫注釋來生成API文檔,這樣做到前后端根據API文檔並行開發。
為什么引入JApiDocs
相比Swagger要寫一堆注解,Spring Rest Docs需要寫測試用例,才能生成API文檔,JApiDocs只要Controller類和方法的Java注釋寫完即可手動生成多種格式的API文檔。
如下的簡單一個參數的方法,Swagger要寫兩行又臭又長的注解,稍不留神就寫錯。

先睹為快
沒有對比就沒有傷害,看一下我的java代碼,沒有任何多余的注解,只有常規的java規范方法注釋。
/** * 示例生成api文檔方法 * * @param productId 年齡 * @param guo 姓氏 * @return 商品庫存DTO */ @PostMapping("/apiDocDemo") public ProductReduceStockDTO apiDocDemo(@RequestParam Long productId, @RequestParam String guo) { return new ProductReduceStockDTO().setProductId(productId); }
生成后的Java API Doc如圖:

快速上手
第一步
添加依賴
<dependency> <groupId>io.github.yedaxia</groupId> <artifactId>japidocs</artifactId> <version>1.4</version> </dependency>
第二步
配置參數
你可以在任意一個類添加main方法,運行下面的代碼:
DocsConfig config = new DocsConfig(); config.setProjectPath("your springboot project path"); // 項目根目錄 config.setProjectName("ProjectName"); // 項目名稱 config.setApiVersion("V1.0"); // 聲明該API的版本 config.setDocsPath("your api docs path"); // 生成API 文檔所在目錄 config.setAutoGenerate(Boolean.TRUE); // 配置自動生成 Docs.buildHtmlDocs(config); // 執行生成文檔
如果沒有意外,執行完上面的代碼后,你就可以在配置的目錄中看到生成的文檔了。
編碼規范
JApiDocs是通過解析Java源碼來實現的,要使得JApiDocs正確工作,需要你在項目中的Controller
書寫遵循一定的編碼規范。
1. 添加必要的代碼注釋
其中類注釋會對應到一級接口分組,你也可以通過@description
來指定分組名稱;JApiDocs 會通過 @param
來尋找接口參數和進一步解析參數的內容。
package cn.iocoder.springboot.lab52.productservice.controller; import cn.iocoder.springboot.lab52.productservice.dto.ProductReduceStockDTO; import cn.iocoder.springboot.lab52.productservice.service.ProductService; import io.github.yedaxia.apidocs.Docs; import io.github.yedaxia.apidocs.DocsConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; /** * @description 商品相關操作控制器 * @ClassName: ProductController * @author: 郭秀志 jbcode@126.com * @date: 2020/6/23 20:56 * @Copyright: */ @RestController @RequestMapping("/product") public class ProductController { private Logger logger = LoggerFactory.getLogger(ProductController.class); @Autowired private ProductService productService; /** * 減庫存操作 * * @param productReduceStockDTO 商品及庫存的DTO,用於減庫存。 * @param guo 示例參數無意義。 * @return */ @PostMapping("/reduce-stock") public Boolean reduceStock(@RequestBody ProductReduceStockDTO productReduceStockDTO, @RequestParam String guo) { logger.info(guo + "[reduceStock] 收到減少庫存請求, 商品:{}, 價格:{}", productReduceStockDTO.getProductId(), productReduceStockDTO.getAmount()); try { productService.reduceStock(productReduceStockDTO.getProductId(), productReduceStockDTO.getAmount()); // 正常扣除庫存,返回 true return true; } catch (Exception e) { // 失敗扣除庫存,返回 false return false; } } /** * 示例生成api文檔方法 * * @param productId 年齡 * @param guo 姓氏 * @return 商品庫存DTO */ @PostMapping("/apiDocDemo") public ProductReduceStockDTO apiDocDemo(@RequestParam Long productId, @RequestParam String guo) { return new ProductReduceStockDTO().setProductId(productId); } public static void main(String[] args) { DocsConfig config = new DocsConfig(); config.setProjectPath("D:\\dev\\GitRepository\\seata-at-httpclient-demo\\seata-at-httpclient-demo-product-service"); // 項目根目錄 config.setProjectName("商品服務"); // 項目名稱 config.setApiVersion("V1.0"); // 聲明該API的版本 config.setDocsPath("d:\\Japidoc"); // 生成API 文檔所在目錄 config.setAutoGenerate(Boolean.TRUE); // 配置自動生成 Docs.buildHtmlDocs(config); // 執行生成文檔 } }
/** * 商品減少庫存 DTO */ public class ProductReduceStockDTO { /** * 商品編號 */ private Long productId; /** * 數量 */ private Integer amount; 省略getter、setter方法,屬性的注釋將在文檔中被使用.......
如果提交的表單是 application/x-www-form-urlencoded
類型的key/value
格式,你可以在 SpringBoot 端通過在 @param
參數后添加字段解釋或者在相關的JavaBean對象里面添加解釋:
// 直接在java的 @param 注解中
// 在FormBean對象中 public class UserListForm extends PageForm{ private Integer status; //用戶狀態 private String name; //用戶名 }
這種格式對於到文檔中的參數描述將是表格的形式:
參數名 | 類型 | 必須 | 描述 |
---|---|---|---|
status | int | 否 | 用戶狀態 |
name | string | 否 | 用戶名 |
如果提交的表單是 application/json
類型的json
數據格式,對應 SpringBoot 中的 @RequestBody
注解,在文檔中則是 json
格式顯示:
{ "id": "long //用戶ID", "name": "string //用戶名", "phone": "long //電話", "avatar": "string //頭像", "gender": "byte //性別" }
2. 接口聲明返回對象
我們知道,如果Controller
聲明了@RestController
,SpringBoot會把返回的對象直接序列成Json數據格式返回給前端。 JApiDocs也利用了這一特性來解析接口返回的結果,但由於JApiDocs是靜態解析源碼的,因此你要明確指出返回對象的類型信息,JApiDocs支持繼承、泛型、循環嵌套等復雜的類解析。
比如的apiDocDemo
接口:
/** * 示例生成api文檔方法 * * @param productId 年齡 * @param guo 姓氏 * @return 商品庫存DTO */ @PostMapping("/apiDocDemo") public ProductReduceStockDTO apiDocDemo(@RequestParam Long productId, @RequestParam String guo) { return new ProductReduceStockDTO().setProductId(productId); }
ProductReduceStockDTO
表明了該接口返回的數據結構,經過JApiDocs處理后是這樣的:
{ "productId": "long //商品編號", "amount": "int //數量" }
如果你不是通過返回對象的形式,你也可以通過JApiDocs提供的@ApiDoc
注解來聲明返回類型,你可以參考@ApiDoc
章節的相關配置內容。
3. @ApiDoc
JApiDocs 默認只導出聲明了@ApiDoc
的接口,我們前面通過設置 config.setAutoGenerate(Boolean.TRUE)
來解除了這個限制。
如果你不希望把所有的接口都導出,你可以把autoGenerate
設置關閉,在相關Controller
類或者接口方法上通過添加@ApiDoc
來確定哪些接口需要導出。
當@ApiDoc
聲明在接口方法上的時候,它還擁有一些更靈活的設置,下面我們來看一下:
- result: 這個可以直接聲明返回的對象類型,如果你聲明了,將會覆蓋SpringBoot的返回對象
- url: 請求URL,擴展字段,用於支持非SpringBoot項目
- method: 請求方法,擴展字段,用於支持非SpringBoot項目
例子:
@ApiDoc(result = AdminVO.class, url = "/api/v1/admin/login2", method = "post")
4. @Ignore
如果你不想導出對象里面的某個字段,可以給這個字段加上@Ignore
注解,這樣JApiDocs導出文檔的時候就會自動忽略掉了:
例子:
public class UserForm{ @Ignore private Byte gender; //性別 }
導出更多格式
導出markdown
config.addPlugin(new MarkdownDocPlugin());
導出 pdf 或者 word
你可以通過 pandoc 把 markdown 格式轉成 pdf 或者 word 格式。