跳到正文

通过docsify实现接口文档

优雅的生成接口文档

Posted by lili on January 20, 2023 · 读取中...

    通过docsify实现接口文档

    0、说在前面:

    之前使用了apidoc技术生成的接口文档,但是总有多种不便,如:

    • 框架束缚太严重,改动源码成本太高。
    • 文档的模板较为固定,难以对文档做自定义的保存。
    • 由于数据的规范问题,对个别接口字段的数据读取有误,难以数据保证100%的准确性。

    继而转向使用docsify技术。

    理由如下:

      APIDOC docsify
    文档形式 data.js–>html Markdown–>html,未来可兼容飞书文档
    新增内容显示 固定模板,额外新增字段需要改源码 直接修改.md,所见即所得。
    加载速度 稍慢:生成的json文件转js文件包 很快:生成Markdown之日,就是html完成之时。
    搜索功能 支持目录 支持目录+正文
    数据兼容性 不规范的数据类型,需修改源码匹配规则 支持任何类型
    数据准确性 有个别数据排序不准确 文档支持任何类型
    扩展性 第三方插件多
    版本对比 versiong控制,对比清晰 无法进行对比

    高德地图api

    https://lbs.amap.com/api/webservice/guide/api/search

    1、使用docsify生成接口文档

    sa-doc

    一个基于markdown的接口文档编写工具,这里没有使用原生docsify,采用开源二次开发后的sa-doc,但框架格式和书写语法都是一样的。

    • 基础框架基于:docsify
    • 书写格式参考:apidoc
    • 根据markdown格式编写api接口文档,写时方便
    • 自动将markdown格式转换为表格形式,看时方便

    1.1、通过freemarker生成模板文件

    FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 是一个Java类库。

    1、增加pom依赖

    1
    2
    3
    4
    5
    
    <!-- 引入freemarker模板引擎的依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-freemarker</artifactId>
    </dependency>
    

    2、配置application.properties

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    # 是否开启thymeleaf缓存,本地为false生产建议为true
    spring.freemarker.cache=false
    spring.freemarker.charset=UTF-8
    spring.freemarker.allow-request-override=false
    spring.freemarker.check-template-location=true
        
    #类型
    spring.freemarker.content-type=text/html
    spring.freemarker.expose-request-attributes=true
    spring.freemarker.expose-session-attributes=true
        
    #文件后缀
    spring.freemarker.suffix=.ftl
    #路径
    spring.freemarker.template-loader-path=classpath:/templates/
    

    3、定义模板文件

    apidoc_md.ftl

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    
    ## ${moduleName} | ${pageName}
    
    <#list tables as table>
    
    ---
    
    ### ${table.actionName}
    **请求类型**:  `${table.method}`&emsp;&emsp;**接口类型**:  `${table.interfaceType}`&emsp;&emsp;**版本号**:  `${table.version}`&emsp;**协议号**: `${table.protocolNo}`&emsp;&emsp;**责任人**: `${table.owner}`
    
    **接口描述**: `${table.description}`
    
    **请求Url**:`${table.url}`
    
    **请求参数**
    
    | 变量名   | 备注       |  数据类型  | mock数据  | 是否必须 |
    | -------- | ---------- | ------ | --------- | -------- |
    <#list table.apiParamsList as apiParam>
    | ${apiParam.field} | ${apiParam.description} | ${apiParam.type}  | ${apiParam.mock} |    ${apiParam.must}      |
    </#list>
    
    **响应数据**
    
    <style>
        table th:first-of-type {
            width: 60%;
        }
        table th:nth-of-type(2) {
            width: 15%;
        }
        table th:nth-of-type(3) {
            width: 3%;
        }
        table th:nth-of-type(4) {
            width: 20%;
        }
        table th:nth-of-type(5) {
            width: 2%;
        }
    </style>
    | 变量名                | 备注                                | 数据类型                   | mock数据 | 是否必须 |
    | --------------------- | ----------------------------------- | ---------------------- | -------- | -------- |
    <#list table.apiSuccessList as apiSuccess>
    | ${apiSuccess.field} | ${apiSuccess.description}| ${apiSuccess.type} | ${apiSuccess.mock}| ${apiSuccess.must} |
    </#list>
    </#list>
    

    4、编写路由ApiDocController.java

    重点代码已隐藏,只展示测试类的处理step,其实原理就是按照test.ftl的关键字将值来put到dataMap中,最后通过template.process将dataMap输出到out目录中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    
        @RequestMapping(value = "/shareApiDoc", method = RequestMethod.GET)
        public Map<String, Object> shareApiDoc(@RequestParam(value = "actionId") int actionId) {
    
            // step1 创建freeMarker配置实例
            Configuration configuration = new Configuration();
            Writer out = null;
            try {
                // step2 获取模版路径
                configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));
                // step3 创建数据模型
                Map<String, Object> dataMap = new HashMap<String, Object>();
                //assemble apidoc base info
                dataMap.put("apiVersion", apiVersion);
                dataMap.put("method", requestType);
                dataMap.put("url", actionInfo.getRequestUrl());
                dataMap.put("title", actionInfo.getName());
                dataMap.put("group", page.getName());
                dataMap.put("description", actionInfo.getDescription());
                //get apiParamsList
                List<ApiParam> apiParams = new ArrayList<>();
                dataMap.put("apiParamsList", apiParams);
                //get apiSuccessList
                List<ApiParam> apiSuccess = new ArrayList<>();
                dataMap.put("apiSuccessList", apiSuccess);
                // step4 加载模版文件
                Template template = configuration.getTemplate("test.ftl");
                // step5 生成数据 output to apisrc directory
                File docFile = new File(fileSrc.getPath() + "/" + actionInfo.getName() + nowTime + ".java");
                out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(docFile)));
                template.process(dataMap, out);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (null != out) {
                        out.flush();
                    }
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }
            return null;
        }
    

    1.2、将生成的md文件渲染成网页

    上面的步骤简单说就是通过模版生成了markdown格式的文件,接下来要把文件中的数据渲染成网页。

    • 将生成的markdown文件放在project目录下。
    • 将umeapi_doc目录放置到tomcat上。
    • 通过127.0.0.1/umeApi-doc/index.html#/project/share631-2122-10528来访问在线文档

    后续规划

    多接口文档的分享功能

    整个项目接口的分享功能