猿创征文|小而巧的API文档生成工具之smart-doc

文章目录

  • smart-doc介绍
  • smart-doc特性
  • smart-doc的最佳搭档
  • 谁在使用smart-doc
  • smart-doc的优缺点
  • smart-doc和swagger区别比较
  • smart-doc的使用姿势
    • 姿势一
    • 姿势二
    • 姿势三(公司内部推荐使用)
  • 总结

smart-doc介绍

一个 java restful api 文档生成工具不用像Swagger一样写大量注解,完全基于接口源码分析来生成接口文档,但是需要按照 java的标准注释写。

完全基于接口源码来分析生成接口文档,不采用任何注解侵入到业务代码中。

你只需要按照java-doc标准编写注释, smart-doc就能帮你生成一个简易明了的MarkdownHTML5Postman ollection2.0+OpenAPI 3.0+的文档。

注意:需要完全按照java的标准注释,如果方法注释包含特殊符号或者换行的话,生成的json是会出现格式错误,但是不影响相关的html使用。

smart-doc特性

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

smart-doc的最佳搭档

smart-doc + Torna 组成的文档生成和管理解决方案,使用smart-doc无侵入完成JAVA源代码分析和提取注释生成API文档,自动将文档推送到Torna企业级接口文档管理平台。

猿创征文|小而巧的API文档生成工具之smart-doc_第1张图片

谁在使用smart-doc

猿创征文|小而巧的API文档生成工具之smart-doc_第2张图片

smart-doc的优缺点

简单总结了几个特别明显以及我认为最关键的几个优点如下:

  • 非侵入式接口文档生成
  • 需要按照java文档注释规范对接口及相关对象添加注释
  • 编译文件后需要手动运行插件生成接口文档
  • 配置简单,只需要引入插件,配置文档输出位置即可。相关更加复杂的配置根据需要自行配置。
  • 无需启动项目,生成文档后可直接浏览

缺点
我总结了一下我使用过程中的缺点,在此我仅代表我自己提出的缺点如下

  • 生成的openapi.json数据时,不支持泛型的多层嵌套解析,导致不同接口的responseBody解析为一个。比如接口返回为:ResultVO>,解析成ResultVODefinePage(新版本已解决)

smart-doc和swagger区别比较

功能特性 smart-doc swagger
代码侵入 注解侵入性严重
集成复杂度 简单,只需插件 偏复杂
插件支持 有 gradle 和 maven 插件 无插件
openapi 规范支持 支持 openapi 3.0 完全支持 openapi 的版本
CI 构建集成 可在 ci 构建阶段使用maven 或者 gradle 命令启动插件生成文档 不支持
集中化文档中心集成 已经和 torna 企业级接口文档管理平台对接 不支持
维护持续性 值得信赖,开源后用户基础多,一直持续维护 全球用户多,开源维护值得信赖
接口 debug 2.0.0 版本开始已经支持 debug,页面比 swagger 漂亮太多了。 支持

Smart-doc 从 2.0.0 后几乎实现了 swagger ui 的功能,并且比 swagger ui 更简洁大方,也更符合国内开发者的诉求。当然 smart-doc 的功能也已经超过了 swagger 为 java 开发者提供的功能。当然 smart-doc 本身是只支持扫描代码生成 openapi 3.0 的文档的,也可以将生成的 openapi 3.0 文档导入到其他 ui 中渲染展示。

swagger 生成 离线的文档 需要借助第三方jar包实现,而 smart-doc 直接 运行 test 方法就可以直接导出 md,html,asciidoc 等格式文档。

设计思路不同,smart-doc 是基于 源码分析的,它生成api文档是通过分析JAVA源码主要是通过 注释 和 系统自带注解,来实现文档的 生成,而 swagger 是运行时 自动生成在线文档,并且 生成 测试 接口的 案例。由于他们设计思路 理念 不一样,swagger2 使用过程需要使用它定义的@API 相关注解,这样就污染了源码,代码入侵有点高,而smart -doc 就不一样了,主要是通过 注释 、解析/** */ 来生成API文档的 。这样基本上没有入侵性,很自由!

swagger

  • 侵入式接口文档生成
  • 每个接口及每个实体类都需要添加注解
  • 配置复杂,需要添加依赖然后需要添加相关配置
  • 编译后自动生成接口文档
  • 需要启动后才能查看,如果配置了安全框架还需要开放相关接口

smart-doc的使用姿势

姿势一

使用maven或者gradle插件进行一键生成对应的文档格式或者命令进行生成,在这里我只展示了maven插件的使用姿势。

<plugin>
    <groupId>com.github.shalousungroupId>
    <artifactId>smart-doc-maven-pluginartifactId>
    <version>2.4.9version>
    <configuration>
        
        <configFile>./src/main/resources/smart-doc.jsonconfigFile>
        
        <projectName>测试projectName>
        
        <excludes>
            
            
            <exclude>com.alibaba:fastjsonexclude>
        excludes>
        
        
        <includes>
            
            
            <include>com.alibaba:fastjsoninclude>
            
            <include>com.baomidou:mybatis-plus-extensioninclude>
            
            <include>org.springframework.data:spring-data-commonsinclude>
        includes>
    configuration>
    <executions>
        <execution>
            
            <phase>compilephase>
            <goals>
                
                <goal>htmlgoal>
            goals>
        execution>
    executions>
plugin>

如果配置clean|validate|compile|test|package|verify|install|site|deploy这些,可以在以上指令被触发时执行smart-doc文档生成

使用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

使用IDE一键生成如下:

猿创征文|小而巧的API文档生成工具之smart-doc_第3张图片

优点:便捷,快速上手

缺点:每个服务各自指定smart-doc的配置文件smart-doc.json

姿势二

导入相关smart-doc依赖


<dependency>
    <groupId>com.github.shalousungroupId>
    <artifactId>smart-docartifactId>
    <version>2.5.1version>
dependency>

手动为每个项目引入以上jar包,可以使用smart-doc.json配置文件也可以使用smart-doc自带的ApiConfig配置类进行手动配置。

使用单元测试测试API文档生成如下:

@Test
public void testBuilderControllersApi() {
    ApiConfig config = new ApiConfig();
    config.setServerUrl("http://localhost:8080");
    //当把AllInOne设置为true时,Smart-doc将会把所有接口生成到一个Markdown、HHTML或者AsciiDoc中
    config.setAllInOne(true);

    //HTML5文档,建议直接放到src/main/resources/static/doc下,Smart-doc提供一个配置常量HTML_DOC_OUT_PATH
    //源码---String HTML_DOC_OUT_PATH = "src/main/resources/static/doc";
    config.setOutPath("src/main/resources/static/doc");

    // 设置接口包扫描路径过滤,如果不配置则Smart-doc默认扫描所有的接口类
    // 配置多个报名有英文逗号隔开
    config.setPackageFilters("com.***.Controller.*");

    //设置错误错列表,遍历自己的错误码设置给Smart-doc即可
    List<ApiErrorCode> errorCodeList = new ArrayList<>();
    for (HttpCodeEnum codeEnum : HttpCodeEnum.values()) {
        ApiErrorCode errorCode = new ApiErrorCode();
        errorCode.setValue(codeEnum.getCode()).setDesc(codeEnum.getMessage());
        errorCodeList.add(errorCode);
    }

    //不需要显示错误码,则可以不用设置错误码。
    config.setErrorCodes(errorCodeList);
    //生成Markdown文件
    HtmlApiDocBuilder.buildApiDoc(config);
}

姿势三(公司内部推荐使用)

Q:为什么说公司内部建议使用呢?
:每个公司都会有自己的maven仓库(几乎),可以搞一些定制化的工具包,比如:日志、认证、链路、授权等。可以在工具包中加入smart-doc包进行简单开发。

可以这么做:
将smart-doc集成到工具包中,在工具包进行打包,提供给使用方,然后定制开发进行配置化管理

每个Java业务服务引入公共jar包,然后进行配置,自定义配置如下:

# 是否开启html生成,默认为false
smart-doc.html-enable=true
# html生成路径,默认为当前服务子目录doc下
smart-doc.out-path=/doc/
# 接口返回对象配置
smart-doc.response-class-name=com.sparkxmedia.xplatform.sd.api.common.result.ResultVO
# 自定义请求头
smart-doc.request-header.username=zane
smart-doc.request-header.user_id=1
smart-doc.request-header.authorization=test
# controller层包
smart-doc.package-filters=com.sparkxmedia.xplatform.sd.api.ai.controller.*,com.sparkxmedia.xplatform.sd.api.controller.*
# 如果使用swagger-ui替代smart-doc的html,则需配置获取openapi.json路径
springdoc.swagger-ui.url=/sd-api/doc/openapi.json

其核心代码如下:

package com.cuizb.tools.starter.config.doc;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ResourceUtils;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author: Java技术债务
 * @Date: 2021/6/6 20:03
 * Describe: 跨域解决,映射生成的静态资源
 */
@Slf4j
@Configuration
@EnableConfigurationProperties({ApiDocProperties.class})
public class WebMvcConfig implements WebMvcConfigurer {
    @Autowired
    private ApiDocProperties apiDocProperties;

    /**
     * 解决跨域问题
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedHeaders("*")
                .allowedMethods("*")
                .allowedOriginPatterns("/**")
                .maxAge(3600);
    }

    @SneakyThrows
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 当前项目根路径
        String rootPath = ResourceUtils.getURL("").getPath();
        // 文档保存绝对路径
        rootPath = rootPath.substring(0, rootPath.length() - 1) + apiDocProperties.getOutPath();
        // 映射到当前项目根路径+用户自定义路径(当前仅支持当前项目下路径)
        String resourcesPath;
        if ("dev".equals(apiDocProperties.getProfileActive()) || "local".equals(apiDocProperties.getProfileActive())) {
            resourcesPath = "file:///" + rootPath;
        } else {
            resourcesPath = "file:///" + apiDocProperties.getOutPath();
        }

        log.info(">>>>>>>>>>>>>" + resourcesPath);
        //配置静态资源映射
        registry
                .addResourceHandler("/doc/static/**")
                .addResourceLocations(resourcesPath);
    }

}
package com.cuizb.tools.starter.config.doc;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * @author Java技术债务
 * @date 2022-08-17 15:08
 * Be in awe of every code modification
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Configuration
@ConfigurationProperties(prefix = "smart-doc")
public class ApiDocProperties {

    @Value("${server.port}")
    private int port;

    @Value("${app.id}")
    private String appId;

    @Value("${server.servlet.context-path:}")
    private String pathFilter;

    @Value("${spring.profiles.active:dev}")
    private String profileActive;

    private boolean htmlEnable;

    private String outPath;

    private String responseClassName;

    private Map<String, String> requestHeader = new HashMap<>();

    private String packageFilters;
}

/**
 * @author Java技术债务
 * @date 2022-08-16 18:17
 * Be in awe of every code modification
 */
@Slf4j
@EnableConfigurationProperties({ApiDocProperties.class})
@Controller
//@RequestMapping("${spring.application.name}/doc")
@Profile({"dev", "local", "qa", "test", "sit", "uat"})
@RequestMapping("/doc")
public class DocController {
    @Autowired
    private ApiDocProperties apiDocProperties;

    private ApiDocConfig apiDocConfig;

    public DocController() {

    }

    @GetMapping("/openapi.json")
    @ResponseBody
    public String openapi() {
        initApiDocConfig();
        ApiConfig config = apiDocConfig.getApiConfig();

        return OpenApiBuilder.buildOpenApi(config).trim().replace(" ", "");
    }
     @GetMapping("/build")
    public String buildHtml() {
        initApiDocConfig();
        ... ...
    }
}

代码解释:

  • WebMvcConfig解决跨域以及文件映射,由开发人员决定是否使用smart-doc生成的API接口文档页面,因为有的已经使用了其他产品,可以将smart-doc生成的json同步到现有的产品,当然如果你只使用smart-doc的话,不需要配置文件映射。
  • ApiDocProperties自定义配置,开发人员只关心自己当前服务的smart-doc相关配置即可
  • DocController工具包中的uri进行资源访问,可以自定义html,openapi.json等路径。也可以自定义开发,生成json文件或者json字符串等。

当前为了适用本公司,简单的自定义了一些开发,以下是简单的配置了一些路径资源:

  • 获取openapi.json地址:http://localhost:port[/server-servlet-context-path]/doc/openapi.json
  • 构建html文件地址:http://localhost:port[/server-servlet-context-path]/doc/build
  • html接口文档地址:http://localhost:port[/server-servlet-context-path]/doc/static/index.html

如果你想使用这种的话,你可以继续研究与开发。。。

总结

可以入手使用,关键是零侵入,还支持dubbo方式(虽然我未体验使用此方式)

谢谢阅读,如果有不一样的见解,请评论说出你的观点以及见解。。。觉得不错的话,介意点个赞吗?我知道你不介意,谢谢哈。。。

一些工具特性介绍等引用smart-doc官方文档:https://smart-doc-group.github.io/#/zh-cn/start/quickstart

你可能感兴趣的:(SpringBoot,随笔,资源分享,postman,API文档,spring,spring,boot)