swagger导出到pdf、html文档

     阅读:42

最近工作中接到一个任务,就是项目要一份接口文档,之前项目用的文档是swagger的自动生成的,再导入一些好看的UI(也没好看到哪里去,比如springfox-swagger-ui)来使用,其实也是一直这样。但是项目的接口太多了,这要是让我去手写到文档,可能得写到兔年了。于是乎我在想,能不能把swagger的接口导出来,直接完成任务。
起先,我在项目的swagger上面看到有导出这个功能,于是我很高兴得点击了其中 的一个,然后它就转呀转,转了好几个小时都还停,那个时候我就绝望了,所以我就去网上搜索资料,各个方法都去尝试一下,发现其实是可以的,可能是因为我那个项目太大了,接口太多,一直转个不停。后来我还尝试了其他的实现办法,找到了另外两个,遇到了很多的坑,这里一起介绍。

swagger UI离线文档

首先swagger有个比原生好看的UI(swagger基本配置我就不过多介绍,网上一大堆),叫springfox-swagger-ui,这个UI相对于原生的UI好看了很多的,更加符合中国人的审美。下面是springboot整合swagger-bootstrap-ui的介绍。

  1. 导入依赖springfox-swagger-ui
<dependency>
  <groupId>com.github.xiaoymin</groupId>
  <artifactId>swagger-bootstrap-ui</artifactId>
  <version>1.9.6</version>
  <!-- 截止发布,最高版本是1.9.6 -->
</dependency>
  1. 在swagger的配置类上加上注解

导入UI依赖

  1. 静态资源配置

放行静态资源
访问地址:
http:// {ip地址}: {端口号} /doc.html
打开页面后是这样的,提供了拷贝md格式的文本,可以将文本复制到软件 Typora 中去查看
swagger文档页面
拷贝到Typora后
拷贝出来的接口描述

但是我们项目使用的是另外一个UI,叫 knife4j,这个其实是 swagger-bootstrap-ui 的增强版,增加了很多的功能,详情参考官方

  1. 导入依赖
<dependency>
   <groupId>com.github.xiaoymin</groupId>
   <artifactId>knife4j-spring-boot-starter</artifactId>
   <version>2.0.7</version>
   <!-- 截止发布,最高版本是3.0.3-->
</dependency>

说明:3.0.3 版本的knife4j依赖包需要更高版本的swagger依赖包,我用 2.9.2版本的时候报错

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>

报错:

 springfox/documentation/common/ClassPresentInClassPathCondition

升级版本即可

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>3.0.0</version>
</dependency>
  1. 在swagger的配置类上加上注解
    把 swagger-bootstrap-ui 的注解 @EnableSwaggerBootstrapUI 改成 @EnableKnife4j 即可
    添加@EnableKnife4j注解
  2. 静态资源配置
    静态资源配置资源配置和 swagger-bootstrap-ui 一样
    访问的地址一样: http:// {ip地址}: {端口号} /doc.html
    会发现这里增加了导出的功能,比如导出md 、work文档、html等不同类型的接口文档
    swagger UI自带的导出功能
    试着是可以用的,但是下载出来的work格式不敢恭维

导出后的work文档
不过html接口页面还是挺好看的
导出后的html文档

我之所以后面还去尝试其他的办法,是因为开头说过,点击下载后一直在转圈,可能是因为版本不够高,亦或者接口太多。
在这里插入图片描述

所以我在网上参考了其他人的办法,我也遇到了很多的坑

代码实现导出功能

  1. 导入依赖
<dependency>    
    <groupId>io.github.swagger2markup</groupId>   
    <artifactId>swagger2markup</artifactId>    
    <version>1.3.3</version>
</dependency>
  1. 编写代码
import io.github.swagger2markup.GroupBy;
import io.github.swagger2markup.Language;
import io.github.swagger2markup.Swagger2MarkupConfig;
import io.github.swagger2markup.Swagger2MarkupConverter;
import io.github.swagger2markup.builder.Swagger2MarkupConfigBuilder;
import io.github.swagger2markup.markup.builder.MarkupLanguage;

import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Paths;

/**
 * @author weiming wu
 * @date 2022/1/26 11:49
 */
public class SwaggerUtils {

    private static final String url = "http://localhost:8003/v2/api-docs";


    /**
     * 生成AsciiDocs格式文档
     * @throws MalformedURLException
     */
    public static void generateAsciiDocs() throws MalformedURLException {
        Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()
                .withMarkupLanguage(MarkupLanguage.ASCIIDOC)
                .withOutputLanguage(Language.ZH)
                .withPathsGroupedBy(GroupBy.TAGS)
                .withGeneratedExamples()
                .withoutInlineSchema().build();
        Swagger2MarkupConverter.from(new URL(url))
                .withConfig(config)
                .build()
                .toFolder(Paths.get("./docs/asciidoc/generated"));
    }


    /**
     * 生成AsciiDocs格式文档,并汇总成一个文件
     * @throws MalformedURLException
     */
    public static void generateAsciiDocsToFile() throws MalformedURLException {
        Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()
                .withMarkupLanguage(MarkupLanguage.ASCIIDOC)
                .withOutputLanguage(Language.ZH)
                .withPathsGroupedBy(GroupBy.TAGS)
                .withGeneratedExamples()
                .withoutInlineSchema()
                .build();
        Swagger2MarkupConverter.from(new URL(url))
                .withConfig(config)
                .build()
                .toFile(Paths.get("./docs/asciidoc/generated/all"));
    }


    /**
     * 生成Markdown格式文档
     * @throws MalformedURLException
     */
    public static void generateMarkdownDocs() throws MalformedURLException {
        Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()
                .withMarkupLanguage(MarkupLanguage.MARKDOWN)
                .withOutputLanguage(Language.ZH)
                .withPathsGroupedBy(GroupBy.TAGS)
                .withGeneratedExamples()
                .withoutInlineSchema()
                .build();
        Swagger2MarkupConverter.from(new URL(url))
                .withConfig(config)
                .build()
                .toFolder(Paths.get("./docs/markdown/generated"));
    }


    /**
     * 生成Markdown格式文档,并汇总成一个文件
     * @throws MalformedURLException
     */
    public static void generateMarkdownDocsToFile() throws MalformedURLException {
        Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()
                .withMarkupLanguage(MarkupLanguage.MARKDOWN)
                .withOutputLanguage(Language.ZH)
                .withPathsGroupedBy(GroupBy.TAGS)
                .withGeneratedExamples()
                .withoutInlineSchema()
                .build();
        Swagger2MarkupConverter.from(new URL(url))
                .withConfig(config)
                .build()
                .toFile(Paths.get("./docs/markdown/generated/wwm"));
    }


    /**
     * 生成Confluence格式文档
     * @throws MalformedURLException
     */
    public static void generateConfluenceDocs() throws MalformedURLException {
        Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()
                .withMarkupLanguage(MarkupLanguage.CONFLUENCE_MARKUP)
                .withOutputLanguage(Language.ZH)
                .withPathsGroupedBy(GroupBy.TAGS)
                .withGeneratedExamples()
                .withoutInlineSchema()
                .build();
        Swagger2MarkupConverter.from(new URL(url))
                .withConfig(config)
                .build()
                .toFolder(Paths.get("./docs/confluence/generated"));
    }


    /**
     * 生成Confluence格式文档,并汇总成一个文件
     * @throws MalformedURLException
     */
    public static void generateConfluenceDocsToFile() throws MalformedURLException {
        Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()
                .withMarkupLanguage(MarkupLanguage.CONFLUENCE_MARKUP)
                .withOutputLanguage(Language.ZH)
                .withPathsGroupedBy(GroupBy.TAGS)
                .withGeneratedExamples()
                .withoutInlineSchema()
                .build();
        Swagger2MarkupConverter.from(new URL(url))
                .withConfig(config)
                .build()
                .toFile(Paths.get("./docs/confluence/generated/all"));
    }
}

说明:

(1)这个依赖只能生成三种格式的文档 adoc、md 和 txt格式的文件

(2) 这里需要使用到swagger的json格式,代码是通过json数据来生成相应的文档的

(3)如果是使用目录路径,会生成四个文件,分别是controller、 实体类,接口等相关信息;

如果是指定一个文件,可以直接生成一个总文件

(4)注意:代码中用到的url是swagger的json格式的数据,访问接口一般是

http://{ip地址}:{端口}/项目访问根路径/v2/api-docs

生成adoc文件
3. 调用接口执行
调用执行想要的文件格式的接口即可,这里调用方法 generateAsciiDocsToFile 生成的ASSIIDOC文件如下:
生成的ASSIIDOC文件

上面的代码生成的目录结构如下:

src
--docs
----confluence
------generated
--------definitions.txt
--------overview.txt
--------paths.txt
--------security.txt
----markdown
------generated
--------definitions.md
--------overview.md
--------paths.md
--------security.md
  1. 导出 html、pdf、xml 格式
    如果要生成其他的格式,需要使用到插件,这个插件是通过第一步生成的ASSIIDOC文件来生成其他格式的接口文档的
asciidoctor-maven-plugin 

在pom文件中添加插件

<plugin>
    <groupId>org.asciidoctor</groupId>
    <artifactId>asciidoctor-maven-plugin</artifactId>
    <version>1.5.3</version>
    <!-- <version>2.0.0-RC.1</version> -->
    <!-- Include Asciidoctor PDF for pdf generation -->
    <dependencies>
        <dependency>
            <groupId>org.asciidoctor</groupId>
            <artifactId>asciidoctorj-pdf</artifactId>
            <version>1.5.0-alpha.10.1</version>
        </dependency>
        <dependency>
            <groupId>org.jruby</groupId>
            <artifactId>jruby-complete</artifactId>
            <version>1.7.21</version>
        </dependency>
    </dependencies>
    <configuration>  
        <sourceDirectory>./docs/asciidoc/generated</sourceDirectory>
        <outputDirectory>./docs/asciidoc/html</outputDirectory>
        <backend>html</backend>
        <!-- <outputDirectory>./docs/asciidoc/pdf</outputDirectory>
                    <backend>pdf</backend> -->
        <headerFooter>true</headerFooter>
        <doctype>book</doctype>
        <sourceHighlighter>coderay</sourceHighlighter>
        <attributes>
            <!-- 菜单栏在左边 -->
            <toc>left</toc>
            <!-- 多标题排列 -->
            <toclevels>3</toclevels>
            <!-- 自动打数字序号 -->
            <sectnums>true</sectnums>
        </attributes>
    </configuration>
</plugin>

说明:
configuration.sourceDirectory :该标签用于指定利用ASSIIDOC文件(第一步中代码生成的ASSIIDOC文件)生成html的资源目录,即该标签需要与swagger2markup生成的ASSIIDOC文件在同一个目录,一般来说该标签目录设置与swagger2markup插件configuration.outputDir标签内容一致即可

  1. 执行插件
    这里直接执行右边maven菜单中的插件即可:asclidoctor:process-asclidoc

在这里插入图片描述
生成的html如图:

生成的htm接口文档
生成的htm接口文档

生成的pdf:
生成的pdf接口文档
生成的pdf接口文档

插件实现导出功能

  1. pom导入插件
<plugin>
    <groupId>io.github.swagger2markup</groupId>
    <artifactId>swagger2markup-maven-plugin</artifactId>
    <version>1.3.3</version>
    <configuration>
        <swaggerInput>http://localhost:8003/v2/api-docs</swaggerInput>
        <!-- 生成asciidoc格式 -->
        <outputFile>src/docs/asciidoc/generated/all</outputFile>
        <!--                    <outputDir>src/docs/asciidoc/generated</outputDir>-->
        <!-- 生成markdown格式 -->
        <!-- <outputFile>src/docs/markdown/generated/all</outputFile>-->
        <config>
            <!-- 生成asciidoc格式 -->
            <swagger2markup.markupLanguage>ASCIIDOC</swagger2markup.markupLanguage>
            <!-- 生成markdown格式 -->
            <!--                        <swagger2markup.markupLanguage>MARKDOWN</swagger2markup.markupLanguage>-->
            <swagger2markup.outputLanguage>ZH</swagger2markup.outputLanguage>
            <swagger2markup.generatedExamplesEnabled>true</swagger2markup.generatedExamplesEnabled>
            <swagger2markup.inlineSchemaEnabled>false</swagger2markup.inlineSchemaEnabled>
            <swagger2markup.pathsGroupedBy>TAGS</swagger2markup.pathsGroupedBy>
        </config>
    </configuration>
</plugin>

说明:

(1)configuration.swaggerInput :该标签内容需修改为需要导出接口项目的/v2/api-docs 路径
(2)configuration.outputFile :该标签为生成单个文档指定文档生成路径,如生成txt、md等文件,可随意修改;但注意,该标签与outputDir标签二选一;
(3)configuration.outputDir :该标签为生成多个文档指定文档目录,如生成ASCIIDOC文件,该类文件可用于结合asciidoctor插件生成html文件;
(4)configuration.config :该标签内定义的swagger2markup.markupLanguage子标签,只能同时存在一个,如指定生成markdown 即md文件时,就不能指定生成其他类型;
注意:指定生成ASCIIDOC文件类型时,需与configuration.outputDir标签配合使用

  1. 执行插件
    依旧直接执行右边的maven菜单中的插件: swagger2markup:convertSwagger2markup
    不过我执行的时候,一直报下面这个错误:
ch.netzwerg.paleo.ColumnIds$StringColumnId

网上的答案都是一样的,就是
在这里插入图片描述

添加或者替换
<repositories>
    <repository>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
        <id>jcenter-releases</id>
        <name>jcenter</name>
        <url>http://jcenter.bintray.com</url>
    </repository>
</repositories>


再不济就是改成这样

<repositories>
    <repository>
        <id>spring-libs-milestone</id>
        <url>https://repo.spring.io/libs-milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
    <!-- jhipster-needle-maven-repository -->
</repositories>
<pluginRepositories>
    <pluginRepository>
        <id>spring-plugins-release</id>
        <url>https://repo.spring.io/plugins-release</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </pluginRepository>
</pluginRepositories>

参考:https://blog.csdn.net/oceanBin1995/article/details/104833086

但是以上两个方法我都没解决问题,所以这里我其实采用的是第一种方法中的第一步。
说明:这个插件的作用其实相当于第一步中的执行代码,都是为了生成源文件ASSIIDOC

  1. 导出 html、pdf、xml 格式

这个步骤同通过代码导出文档中的第4步一样,这里 不再赘述。

解决pdf文档乱码空白问题

如果导出成功,但是pdf文档出现乱码或者文字空白的情况,解决办法如下:

  1. 打开asciidoctorj-pdf jar包
maven仓库中的asciidoctorj-pdf jar包,使用压缩工具打开:

进入asciidoctorj-pdf-1.5.0-alpha.16.jar\gems\asciidoctor-pdf-1.5.0.alpha.16\data\ 目录
fonts:字体文件目录
themes:配置文件目录

打开asciidoctorj-pdf jar包

  1. 下载字体
字体下载:https://github.com/chloerei/asciidoctor-pdf-cjk-kai_gen_gothic/releases

注:只需下载KaiGenGothicCN-Bold.ttf、KaiGenGothicCN-Bold-Italic.ttf、KaiGenGothicCN-Regular.ttff、KaiGenGothicCN-Regular-Italic.ttf 即可

将字体文件放入fonts目录中

下载字体

  1. 修改配置
进入themes目录,修改default-theme.yml文件
修改以base:font_family属性值对应的字体文件配置:在font:catalog下。
base:
  font_family: Noto Serif

font:
  catalog:
    Noto Serif:
      normal: KaiGenGothicCN-Regular.ttf
      bold: KaiGenGothicCN-Bold.ttf
      italic: KaiGenGothicCN-Regular-Italic.ttf
      bold_italic: KaiGenGothicCN-Bold-Italic.ttf

修改配置

最后吐槽一下:swagger有时候真的很多坑,还有就是上面的那些插件和依赖包最好可以通过 pom 文件下载下来,因为我之前可能因为maven配置文件的问题一下下载不下来,所以去maven官网下载jar后通过 mvn 命令导进 maven 仓库,结果一直没有找到 MarkupLanguage 这个类,后来是我干脆自己创建一个 demo,重新配置一个 maven的setting文件(阿里仓库),才完全下载下来,重新下载前记得把仓库中对应的先删除掉。
在这里插入图片描述
项目我已经上传到 githug 了,地址是:

git@github.com:wwm1997/swagger2markup.git