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如图:
快速上手
第一步
添加依赖
>
>io.github.yedaxia > >japidocs > >1.4 > >
第二步
配置参数
你可以在任意一个类添加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: 郭秀志 [email protected] * @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 格式。