Java零注解API文档生成解决方案

339 阅读10分钟

前言

以标准的代码规范、零侵入的方法解决API文档生成的问题,不仅解放了生产力,同时也对现有代码规范提出了更高的检测标准和要求。这就是Smart-Doc带给我们的便捷、高效的解决方案。

背景

在日常的工作中,我们避免不了要维护API文档,不仅是方便项目的维护,同时,也便于同事间高效的协作。起初,我们使用Swagger维护我们的API文档,但是因其较强的侵入性,大量重复的注释不仅降低了开发效率,也始得代码的整洁性荡然无存。后来,我们使用了NEI接口平台,但慢慢的发现接口的时效性、有效性对于团队要求很高,尤其是需要提供给客户的OpenAPI文档。我们迫切的希望可以直接通过代码(注释)生成API文档,不仅保证了其准确性、时效性,又大大降低了其工作强度。

今天,我们看下Smart-Doc带来的API文档生成解决方案是什么样子的。

关于

  • 一个无侵入式的API接口文档生成器,Smart-doc基于JAVA泛型定义推导的理念, 完全基于接口源码来分析生成接口文档,不采用任何注解侵入到业务代码中
  • Smart-doc是一款同时支持JAVA RESTful API和Apache Dubbo RPC接口文档生成的工具
  • 只需要按照Java-doc标准编写注释, Smart-doc就能生成一个简易明了的Markdown、HTML5、Postman Collection2.0+、OpenAPI 3.0+的文档

特性

  • 零注解、零学习成本、只需要写标准JAVA注释。
  • 基于源代码接口定义自动推导,强大的返回结构推导。
  • 支持Spring MVC、Spring Boot、Spring Boot Web Flux(Controller书写方式)、Feign。
  • 支持Callable、Future、CompletableFuture等异步接口返回的推导。
  • 支持JavaBean上的JSR303参数校验规范,包括分组验证。
  • 对JSON请求参数的接口能够自动生成模拟JSON参数。
  • 对一些常用字段定义能够生成有效的模拟值。
  • 支持生成JSON返回值示例。
  • 支持从项目外部加载源代码来生成字段注释(包括标准规范发布的jar包)。
  • 支持生成多种格式文档:Markdown、HTML5、Asciidoctor、Postman Collection、OpenAPI 3.0。 开放文档数据,可自由实现接入文档管理系统。 - 一键生成JSON文件并导入到Postman中去
  • 支持导出错误码和定义在代码中的各种字典码到接口文档。
  • 支持Maven、Gradle插件式轻松集成。
  • 支持Apache Dubbo RPC接口文档生成。
  • debug接口调试html5页面完全支持文件上传,下载(@download tag标记下载方法)测试。

实践

  • 配置文件 - /src/main/resources/smart-doc.json
{
  "outPath": "target/doc",
  "projectName": "YiDun-Text",
  "packageFilters": "com.netease.is.antispam.text.facade.http.controller.*",
  "openUrl": "http://localhost:7700/api",
  "appToken": "6003ecdad2bc45db83f53db8f1c59a07",
  "debugEnvName":"Local",
  "debugEnvUrl":"http://127.0.0.1:8111",
  "tornaDebug": true,
  "replace": true
}
  • Maven插件配置
<plugin>
  <groupId>com.github.shalousun</groupId>
  <artifactId>smart-doc-maven-plugin</artifactId>
  <version>2.6.5</version>
  <configuration>
    <!--Specify the configuration file used to generate the document-->
    <configFile>./src/main/resources/smart-doc.json</configFile>
    <projectName>YIDUN</projectName>
    <!--smart-doc implements automatic analysis of the dependency tree to load the source code of third-party dependencies. If some framework dependency libraries are not loaded, an error is reported, then use excludes to exclude-->
    <excludes>
      <!--The format is: groupId: artifactId; refer to the following-->
      <!--Regular expressions can also be used, such as: com.google:.* -->
      <exclude>com.google.guava:guava</exclude>
    </excludes>
    <!--Since version 1.0.8, the plugin provides includes support-->
    <!--smart-doc can automatically analyze the dependency tree to load all dependent source code. In principle, it will affect the efficiency of document construction, so you can use includes to let the plugin load the components you configure.-->
    <includes>
      <!--The format is: groupId: artifactId; refer to the following-->
      <!--Regular expressions can also be used, such as: com.google:.* -->
      <include>com.alibaba:fastjson</include>
      <!-- If includes is configured, paging using mybatis-plus requires the source package used by include -->
      <include>com.baomidou:mybatis-plus-extension</include>
      <!-- If includes is configured, paging using jpa requires the source package used by include -->
      <include>org.springframework.data:spring-data-commons</include>
    </includes>
  </configuration>
  <executions>
    <execution>
      <!--Comment out phase if you don't need to start smart-doc when compiling-->
      <phase>compile</phase>
      <goals>
        <!--smart-doc provides html, openapi, markdown, adoc and other goals-->
        <goal>html</goal>
      </goals>
    </execution>
  </executions>
</plugin>
<!-- Spring Doc Open API -->
<plugin>
  <groupId>org.springdoc</groupId>
  <artifactId>springdoc-openapi-maven-plugin</artifactId>
  <version>1.4</version>
  <executions>
    <execution>
      <id>integration-test</id>
      <goals>
        <goal>generate</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <apiDocsUrl>http://localhost:8111/v3/api-docs</apiDocsUrl>
    <outputFileName>openapi.json</outputFileName>
    <outputDir>${project.build.directory}</outputDir>
  </configuration>
</plugin>
  • Maven 命令
//生成html
mvn -Dfile.encoding=UTF-8 smart-doc:html
//生成markdown
mvn -Dfile.encoding=UTF-8 smart-doc:markdown
//生成adoc
mvn -Dfile.encoding=UTF-8 smart-doc:adoc
//生成postman json数据
mvn -Dfile.encoding=UTF-8 smart-doc:postman
// 生成 Open Api 3.0+,Since smart-doc-maven-plugin 1.1.5
mvn -Dfile.encoding=UTF-8 smart-doc:openapi
// 生成文档推送到Torna平台
mvn -Dfile.encoding=UTF-8 smart-doc:torna-rest

// Apache Dubbo RPC文档
// Generate html
mvn -Dfile.encoding=UTF-8 smart-doc:rpc-html
// Generate markdown
mvn -Dfile.encoding=UTF-8 smart-doc:rpc-markdown
// Generate adoc
mvn -Dfile.encoding=UTF-8 smart-doc:rpc-adoc

// 生成dubbo接口文档推送到torna
mvn -Dfile.encoding=UTF-8 smart-doc:torna-rpc
  • 增强
  • 原生支持Javadoc tag
  • @param / @deprecated / @apiNote
  • 自定义的注释
tag名称描述
@ignore@ignore tag用于过滤请求参数对象上的某个字段,设置后smart-doc不输出改字段到请求参数列表中。关于响应字段忽略的请看 【忽略响应字段】 如果@ignore加到方法上,则接口方法不会输出到文档。从1.8.4开始@ignore支持添加到Controller上进行忽略不想生成文档的接口类。@ignore也可以用于方法上忽略某个请求参数。
@required如果你没有使用JSR303参数验证规范实现的方式来标注字段,就可以使用@required去标注请求参数对象的字段,标注smart-doc在输出参数列表时会设置为true。【不建议使用,以后会删除】
@mock从smart-doc 1.8.0开始,@mock tag用于在对象基本类型字段设置自定义文档展示值。设置值后smart-doc不再帮你生成随机值。方便可以通过smart-doc直接输出交付文档。
@dubbo从smart-doc 1.8.7开始,@dubbo tag用于在Dubbo的API接口类上添加让smart-doc可以扫描到Dubbo RPC的接口生成文档。
@restApi从smart-doc 1.8.8开始,@restApi tag用于支持smart-doc去扫描Spring Cloud Feign的定义接口生成文档。
@order从smart-doc 1.9.4开始,@order tag用于设置Controller接口或者API入口的自定义排序序号,@order 1就表示设置序号为1。
@ignoreResponseBodyAdvice从smart-doc 1.9.8开始,@ignoreResponseBodyAdvice tag用于忽略ResponseBodyAdvice设置的包装类。
@download从smart-doc 2.0.1开始,@download tag用于标注在Controller的文件下载方法上,生成debug页面时可实现文件下载测试。并且支持下载文件带请求头参数测试。
@page从smart-doc 2.0.2开始,@page tag用于标注在Controller的方法上表示该方法用来渲染返回一个静态页面,生成debug页面时如果发起测试,测试页面会自动在浏览器开启新标签显示页面。
@ignoreParams从smart-doc 2.1.0开始,@ignoreParams tag用于标注在Controller方法上忽略掉不想显示在文档中的参数,例如:@ignoreParams id name,多个参数名用空格隔开
@response从smart-doc 2.2.0开始,@response tag标注在Controller方法上可以允许用这自己定义返回的json example。建议只在返回基础类型时使用,如:Result类型这种泛型是简单原生类型的响应。
@tag@since 2.2.5, @tag用于将Controller方法分类, 可以将不同Contoller下的方法指定到多个分类下, 同时也可以直接指定Controller为一个分类或多个分类,【不要使用,不支持,直接用分组配置代替】
  • 约束 -根据接口的泛型定义在编译器期加载分析项源代码的返回类型和请求参数类型来实现的工具。 如果在代码的接口定义中返回如下几种类型都将无法做处理。
  • 接口中使用Map - 因为无法分析代码中Map的key值,所以smart-doc无法生成好的文档。
@GetMapping(value = "/object")
public Map<String, User> testMapUser() {
    return null;
}
  • 返回JSONObject - 程序员也看不懂得返回
@GetMapping(value = "/user")
public JSONObject object() {
    return null;
}
  • 不规范说明
  • 如果把代码作为公用库被其他项目使用是要发布一个resource jar
  • 泛型规范
  • T: Type(JAVA 类)通用泛型类型,通常作为第一个泛型类型
  • S: 通用泛型类型,如果需要使用多个泛型类型,可以将S作为第二个泛型类型
  • U: 通用泛型类型,如果需要使用多个泛型类型,可以将U作为第三个泛型类型
  • V: 通用泛型类型,如果需要使用多个泛型类型,可以将V作为第四个泛型类型
  • E: 集合元素泛型类型,主要用于定义集合泛型类型
  • K: 映射-键泛型类型,主要用于定义映射泛型类型
  • V: 映射-值泛型类型,主要用于定义映射泛型类型
  • N: Number数值泛型类型,主要用于定义数值类型的泛型类型
  • ?: 表示不确定的JAVA类型
  • 展示
  • 数据字典

原理

  • QDox - 源码解析工具,主要用于动态代码生成、文档工具等。
  • QDox 是一个完整的 java 类、接口、方法定义的提取器,包括了注释、参数、类型、名称。其实核心功能是输入一个 java 类的源码,可以把这个 java 类解析成一个对象,通过这个对象可以获取很方便的获取解析类组成,比如可以获得这个类有哪些方法,这个方法的参数、返回值、类型、注释 tag。

平台

  • Tonar - 接口文档解决方案
  • 文档管理 - 支持接口文档增删改查、导入导出、OpenAPI接入、字典管理、接口调试
  • 权限管理 - 以项目组的形式管理接口,各项目组之间接口互不影响,同时有访客、开发者、管理员三种角色,每种角色有用不同权限
  • 解决文档管理痛点
  • 不满足swagger文档预览页面和调试页面的展现方式
  • 不喜欢swagger这种侵入式注解
  • 希望使用javadoc注释生成文档,并进行接口调试
  • 希望把公司所有项目接口文档进行统一管理
  • 希望把项目中的若干文档提供给第三方调用者查看
  • 希望可以统一管理项目中的字典枚举
  • 支持推送
  • Smart-Doc
  • Swagger 插件 - 将本地项目中的Swagger文档内容推送到Torna平台,使用平台统一管理项目文档
  • SDK
  • 支持SDK

集成

  • Smart-doc + Torna
  • 组成文档生成和管理解决方案,smart-doc无侵入完成Java源代码和注释提取生成API文档,自动将文档推送到Torna企业级接口文档管理平台。
  • 只需要写完Java注释就能把接口信息推送到Torna平台,从而实现接口预览、接口调试。
  • 缺点
  • 与NEI相比,最大的缺点是不支持Mock测试
  • 展示

NEI

  • 手动导入生成的API
  • 自动导入NEI平台
  • 开发Maven插件,将生成的API文档同步到NEI平台

落地

  • 方式
  • 不使用NEI
  • 使用Tonar平台集成Smart-Doc,自动更新API文档
  • 不使用Tonar,对外提供OpenAPI的服务,定期通过插件生成Markdown提供给运营,更新官网的API文档
  • 使用NEI
  • NEI定期导入上述生成的Swagger、Postman文件,同步更新NEI接口,以NEI为标准导出Markdown提供给运营
  • 开发自动更新插件,代码自动同步NEI,导出Markdown文件供运营使用
  • 约束
  • 规范的代码及注释

对比

工具差异
Swaggerswagger主要原理是利用JAVA的注解和反射机制去生成文档。如果项目文档要比较清晰就必须使用大量的注解。 注解和业务代码强绑定,当然最终构建产出的部署包里也就必须包含swagger的依赖了。也因为swagger是利用反射来生成文档,所以可以做到项目启动时更新文档。
Smart-Docsmart-doc主要是基于源代码和JAVADOC标注注释来生成文档,是在开发期或者是项目的编译期执行生成文档, 在最终在打包运行的jar内你是找不到smart-doc的依赖的,因此是完全不侵入项目运行期的, 也就不能像swagger一样项目启动时更新文档。

总结

  • 维护代码=维护API文档
  • 以标准的开发规范来解放生产力
  • 又反过来对现有的工程的规范性提出检验和标准 - 采用源码分析,对代码的标准度要求高于其他工具
  • 更适合代码和API文档同步开发的项目
  • 零注解,无侵入,是每一个程序员的挚爱,也是值得我们思考的一个问题