目录
1、接口文档面对的困境
我工作几年,接口文档用过好几种方式了。从最开始的word文档,到后来的swagger和confluence编写接口文档,再到后来侵入性很小的jApiDoc,最后到现在的smart-doc工具。
对比下他们的优缺点:
方式 | 好处 | 缺点 |
word文档和confluence | 有文档留存(好像也不算好处) | 费时费力、多人编写不便 |
swagger | 1、不用专门写文档 2、通过连接直接访问 3、在线测试,有点像简化的postman | 注释太多,写的想打人 |
jApiDoc | 1、引入jar包,一键生成html接口文档 2、侵入小,添加简单注释就行 | 1、功能单一,只能接口文档 2、作者好久没有维护了 |
smart-doc | 1、引入maven插件,一键生成HTML接口文档 2、作者很活跃,社区也很活跃,反应问题很快就有新版本解决 3、能生成常用的html,markdown、postman接口文档 4、侵入小,添加简单注释就行 5、适配单服务、微服务等多种环境 | 1、需要抽两个小时看下官方文档 |
2、JApiDocs简介
前面我介绍过一种工具,叫做JApiDocs,这个工具我也使用了一段时间,用起来还是不错的,能满足基本要求,文档链接地址
3、前言
被写接口文档难受了好久,使用swagger要加各种稀奇古怪的注释,十分繁琐,突然看到JApiDocs 的介绍,只需要在接口上加上点注释,就能够生成接口文档。突然来了希望,通过看文档自己使用之后,把踩过的坑记录下来
生成的接口文档页面展示:
查询接口
新增接口
删除接口
官方说明文档:
文档内容,说明、使用范文很齐全,特别适合我们使用,我会举个例子,大家如果要使用的话,还是抽一两个小时看看官方文档,会有很大帮助,文档地址如下:
https://gitee.com/smart-doc-team/smart-doc/wikis/smart-doc%20maven%E6%8F%92%E4%BB%B6?sort_id=1791450
4、快速使用
添加插件
<plugin>
<groupId>com.github.shalousun</groupId>
<artifactId>smart-doc-maven-plugin</artifactId>
<version>2.0.8</version>
<configuration>
<!--指定生成文档的使用的配置文件,配置文件放在自己的项目中-->
<configFile>./src/main/resources/smart-doc.json</configFile>
<!--指定项目名称-->
<projectName>测试</projectName>
<!--smart-doc实现自动分析依赖树加载第三方依赖的源码,如果一些框架依赖库加载不到导致报错,这时请使用excludes排除掉-->
<excludes>
<!--格式为:groupId:artifactId;参考如下-->
<exclude>com.alibaba:fastjson</exclude>
</excludes>
<!--自1.0.8版本开始,插件提供includes支持,配置了includes后插件会按照用户配置加载而不是自动加载,因此使用时需要注意-->
<!--smart-doc能自动分析依赖树加载所有依赖源码,原则上会影响文档构建效率,因此你可以使用includes来让插件加载你配置的组件-->
<includes>
<!--格式为:groupId:artifactId;参考如下-->
<include>com.alibaba:fastjson</include>
</includes>
</configuration>
<executions>
<execution>
<!--如果不需要在执行编译时启动smart-doc,则将phase注释掉-->
<phase>compile</phase>
<goals>
<!--smart-doc提供了html、openapi、markdown等goal,可按需配置-->
<goal>html</goal>
</goals>
</execution>
</executions>
</plugin>
在Resources下新增一个接口文档配置文件
看着配置很多,大部分时候我们使用默认配置就行了,并且每个配置作者都给加好了注释,一看就懂了
文档内容如下
{
"serverUrl": "http://127.0.0.1:8072/test", //设置服务器地址,非必须
"isStrict": false, //是否开启严格模式
"allInOne": true, //是否将文档合并到一个文件中,一般推荐为true
"outPath": "src/main/resources/static/doc", //指定文档的输出路径
"coverOld": true, //是否覆盖旧的文件,主要用于mardown文件覆盖
"packageFilters": "",//controller包过滤,多个包用英文逗号隔开
"style":"xt256", //基于highlight.js的代码高亮设置,喜欢配色统一简洁的同学可以不设置
"createDebugPage": true,//@since 2.0.0 smart-doc支持创建可以测试的html页面,仅在AllInOne模式中起作用。
"md5EncryptedHtmlName": false,//只有每个controller生成一个html文件是才使用
"projectName": "这里修改项目名",//配置自己的项目名称
"skipTransientField": true,//目前未实现
"showAuthor":true,//是否显示接口作者名称,默认是true,不想显示可关闭
"requestFieldToUnderline":false, //自动将驼峰入参字段在文档中转为下划线格式,//@since 1.8.7 版本开始
"responseFieldToUnderline":false,//自动将驼峰入参字段在文档中转为下划线格式,//@since 1.8.7 版本开始
"inlineEnum":true,//设置为true会将枚举详情展示到参数表中,默认关闭,//@since 1.8.8版本开始
"recursionLimit":7,//设置允许递归执行的次数用于避免栈溢出,默认是7,正常为3次以内,//@since 1.8.8版本开始
"displayActualType":false,//配置true会在注释栏自动显示泛型的真实类型短类名,@since 1.9.6
"ignoreRequestParams":[ //忽略请求参数对象,把不想生成文档的参数对象屏蔽掉,@since 1.9.2
"org.springframework.ui.ModelMap"
],
"dataDictionaries": [ //配置数据字典,没有需求可以不设置
{
"title": "http状态码字典", //数据字典的名称
"enumClassName": "com.power.common.enums.HttpCodeEnum", //数据字典枚举类名称
"codeField": "code",//数据字典字典码对应的字段名称
"descField": "message"//数据字典对象的描述信息字典
}
],
"errorCodeDictionaries": [{ //错误码列表,没有需求可以不设置
"title": "title",
"enumClassName": "com.power.common.enums.HttpCodeEnum", //错误码枚举类,如果是枚举是在一个类中定义则用$链接类BaseErrorCode$Common
"codeField": "code",//错误码的code码字段名称
"descField": "message"//错误码的描述信息对应的字段名
}],
"revisionLogs": [ //设置文档变更记录,没有需求可以不设置
{
"version": "1.0", //文档版本号
"status": "update", //变更操作状态,一般为:创建、更新等
"author": "author", //文档变更作者
"remarks": "desc" //变更描述
},
{
"version": "1.0", //文档版本号
"status": "update", //变更操作状态,一般为:创建、更新等
"author": "author", //文档变更作者
"remarks": "desc" //变更描述
}
],
"customResponseFields": [ //自定义添加字段和注释,api-doc后期遇到同名字段则直接给相应字段加注释,非必须
{
"name": "code",//覆盖响应码字段
"desc": "响应代码",//覆盖响应码的字段注释
"ownerClassName": "org.springframework.data.domain.Pageable", //指定你要添加注释的类名
"value": "00000"//设置响应码的值
}
],
"requestHeaders": [ //设置请求头,没有需求可以不设置
{
"name": "Authorization",
"type": "string",
"desc": "desc",
"required": false,
"value":"Bearer ebb616e4-b23f-4b60-b9dc-f8393393bd39",
"since": "-"
}
],
"rpcApiDependencies":[{ // 项目开放的dubbo api接口模块依赖,配置后输出到文档方便使用者集成
"artifactId":"SpringBoot2-Dubbo-Api",
"groupId":"com.fj",
"version":"1.0.0"
}],
"rpcConsumerConfig":"src/main/resources/consumer-example.conf",//文档中添加dubbo consumer集成配置,用于方便集成方可以快速集成
"apiObjectReplacements": [{ // 自smart-doc 1.8.5开始你可以使用自定义类覆盖其他类做文档渲染,使用全类名
"className": "org.springframework.data.domain.Pageable",
"replacementClassName": "com.power.doc.model.PageRequestDto" //自定义的PageRequestDto替换Pageable做文档渲染
}]//,
// "apiConstants": [{//从1.8.9开始配置自己的常量类,smart-doc在解析到常量时自动替换为具体的值,如:http://localhost:8080/testConstants/+ApiVersion.VERSION中的ApiVersion.VERSION会被替换
// "constantsClassName": "com.power.doc.constants.RequestParamConstant"
// }],
// "responseBodyAdvice":{ //自smart-doc 1.9.8起,ResponseBodyAdvice统一返回设置,可用ignoreResponseBodyAdvice tag来忽略
// "className":"com.fj.utils.BaseResult" //通用响应体
// }//,
// "sourceCodePaths": [ //设置代码路径,smart-doc默认会自动加载src/main/java, 没有需求可以不设置 1.0.0以后版本此配置不再生效
// {
// "path": "src/main/java",
// "desc": "测试"
// }
// ]
}
在controller上加上对应的注解
只需要表明每个参数的含义,每个方法是干什么的,就能够准确生成接口文档,相比较swagger可是简单多了,然后他有swagger接口测试的替代功能,直接生成能够导入postman的json文件,很方便,后面我会演示。
package com.fj.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fj.entity.User;
import com.fj.service.IUserService;
import com.fj.utils.BaseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 用户接口文档
*
* @author system
* @since 2021-01-15
*/
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
public IUserService userService;
/**
* 分页查询
*
* @param pageNum 页号
* @param pageSize 页面大小
* @param searchValue 搜索值
* @return BaseResult<List < User>>
*/
@GetMapping(value = "/getByPage")
public BaseResult<List<User>> getByPage(@RequestParam Integer pageNum,
@RequestParam Integer pageSize,
String searchValue) {
Page<User> userPageResult = userService.getByPage(pageNum, pageSize, searchValue);
return new BaseResult<>(200, "success", userPageResult.getRecords(), userPageResult.getTotal());
}
/**
* 通过id获取详情
*
* @param id 主键id
* @return BaseResult<User>
*/
@GetMapping("/getById")
public BaseResult<User> getById(@RequestParam Integer id) {
User user = userService.getById(id);
return new BaseResult<>(200, "success", user);
}
/**
* 更新
*
* @param user 实体
* @return BaseResult
*/
@PutMapping("/updateById")
public BaseResult update(@RequestBody User user) {
userService.updateById(user);
return BaseResult.ok();
}
/**
* 新增
*
* @param user 实体
* @return BaseResult
*/
@PostMapping("/add")
public BaseResult add(@RequestBody User user) {
userService.add(user);
return BaseResult.ok();
}
/**
* 通过id删除
*
* @param id 主键id
* @return BaseResult
*/
@DeleteMapping("/deleteById")
public BaseResult deleteById(@RequestParam Integer id) {
userService.removeById(id);
return BaseResult.ok();
}
}
注意点1:查询返回类型加上泛型
/**
* 分页查询
*
* @param pageNum 页号
* @param pageSize 页面大小
* @param searchValue 搜索值
* @return BaseResult<List < User>>
*/
@GetMapping(value = "/getByPage")
public BaseResult<List<User>> getByPage
注意这里的返回类型是list,所以加上了list的泛型
注意点2:返回实体上加上字段含义
大概就是这样子,现在有很多工具可以生成这种把数据库注释加到代码里面的实体,常见的就是mybatis的generator,还有mybatis-plus的生成实体的方法。
@Data
@EqualsAndHashCode(callSuper = false)
public class User extends Model<User> {
/**
* 主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 姓名
*/
private String name;
/**
* 1删除0正常
*/
private Integer isDelete;
}
这里不加注释也不会报错,只是生成的字段没了注释,看着很尴尬,如下图,createTime没加注释,虽然也没啥问题,但是不够规范。
通过插件生成接口文档
双击生成HTML文件,淡然也可以生成adoc文件和markdown文件
在smart-doc.json中我配置的存储路径是在:src/main/resources/static/doc
运行成功之后生成接口文档:
访问debug-all.html,大功告成
5、踩过的坑
1、生成的接口文档没有对实体字段的注释
解决:官方文档明确说明对所有的controller都要介绍描述注解,这是因为后台接口代码返回的是BaseResult,没有加上泛型
解决方法:修改baseResult,修改泛型就ok了
@Data
public class BaseResult<T> {
/**
* 定义jackson对象
*/
private static final ObjectMapper MAPPER = new ObjectMapper();
/**
* 响应业务状态,正常为200
*/
private Integer status;
/**
* 响应消息
*/
private String msg;
/**
* 响应中的数据
*/
private T data;
/**
* 数据总条数
*/
private Long totalCount;
private static BaseResult build(Integer status, String msg, Object data) {
return new BaseResult<>(status, msg, data);
}
public static BaseResult ok(Object data) {
return new BaseResult<>(data);
}
public static BaseResult ok() {
return new BaseResult<>(null);
}
public BaseResult() {
}
/**
* @param status 状态
* @param msg 提示信息
* @return BaseResult
*/
public static BaseResult build(Integer status, String msg) {
return new BaseResult<>(status, msg, null);
}
public BaseResult(Integer status, String msg, T data) {
this.status = status;
this.msg = msg;
this.data = data;
}
public BaseResult(Integer status, String msg, T data, Long totalCount) {
this.status = status;
this.msg = msg;
this.data = data;
this.totalCount = totalCount;
}
public BaseResult(Integer status, String msg) {
this.status = status;
this.msg = msg;
}
public BaseResult(T data) {
this.status = 200;
this.msg = "success";
this.data = data;
}
2、关于参数是否必填坑
必填参数加上@RequestParam注解就行了
/**
* 分页查询
*
* @param pageNum 页号
* @param pageSize 页面大小
* @param searchValue 搜索值
* @return BaseResult<List < User>>
*/
@GetMapping(value = "/getByPage")
public BaseResult<List<User>> getByPage(@RequestParam Integer pageNum,
@RequestParam Integer pageSize,
String searchValue)
生成文档之后是这样的
6、生成postman测试接口文件
生成文件和接口文档是在同一个目录下面
把这个json文件导入到postman
可以看到信息比我们自己写的要完整,还给参数贴心加上了默认值
是不是比swagger用着更爽
强烈推荐大家使用,我们公司通过我的推广,已经用了大半年了,两个字——很爽。