最近工作中接到一个任务,就是项目要一份接口文档,之前项目用的文档是swagger的自动生成的,再导入一些好看的UI(也没好看到哪里去,比如springfox-swagger-ui)来使用,其实也是一直这样。但是项目的接口太多了,这要是让我去手写到文档,可能得写到兔年了。于是乎我在想,能不能把swagger的接口导出来,直接完成任务。
起先,我在项目的swagger上面看到有导出这个功能,于是我很高兴得点击了其中 的一个,然后它就转呀转,转了好几个小时都还停,那个时候我就绝望了,所以我就去网上搜索资料,各个方法都去尝试一下,发现其实是可以的,可能是因为我那个项目太大了,接口太多,一直转个不停。后来我还尝试了其他的实现办法,找到了另外两个,遇到了很多的坑,这里一起介绍。
swagger UI离线文档
首先swagger有个比原生好看的UI(swagger基本配置我就不过多介绍,网上一大堆),叫springfox-swagger-ui,这个UI相对于原生的UI好看了很多的,更加符合中国人的审美。下面是springboot整合swagger-bootstrap-ui的介绍。
- 导入依赖springfox-swagger-ui
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.6</version>
<!-- 截止发布,最高版本是1.9.6 -->
</dependency>
- 在swagger的配置类上加上注解
- 静态资源配置
访问地址:
http:// {ip地址}: {端口号} /doc.html
打开页面后是这样的,提供了拷贝md格式的文本,可以将文本复制到软件 Typora 中去查看
拷贝到Typora后
但是我们项目使用的是另外一个UI,叫 knife4j,这个其实是 swagger-bootstrap-ui 的增强版,增加了很多的功能,详情参考官方
- 导入依赖
<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>
- 在swagger的配置类上加上注解
把 swagger-bootstrap-ui 的注解 @EnableSwaggerBootstrapUI 改成 @EnableKnife4j 即可
- 静态资源配置
静态资源配置资源配置和 swagger-bootstrap-ui 一样
访问的地址一样: http:// {ip地址}: {端口号} /doc.html
会发现这里增加了导出的功能,比如导出md 、work文档、html等不同类型的接口文档
试着是可以用的,但是下载出来的work格式不敢恭维
不过html接口页面还是挺好看的
我之所以后面还去尝试其他的办法,是因为开头说过,点击下载后一直在转圈,可能是因为版本不够高,亦或者接口太多。
所以我在网上参考了其他人的办法,我也遇到了很多的坑
代码实现导出功能
- 导入依赖
<dependency>
<groupId>io.github.swagger2markup</groupId>
<artifactId>swagger2markup</artifactId>
<version>1.3.3</version>
</dependency>
- 编写代码
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
3. 调用接口执行
调用执行想要的文件格式的接口即可,这里调用方法 generateAsciiDocsToFile 生成的ASSIIDOC文件如下:
上面的代码生成的目录结构如下:
src
--docs
----confluence
------generated
--------definitions.txt
--------overview.txt
--------paths.txt
--------security.txt
----markdown
------generated
--------definitions.md
--------overview.md
--------paths.md
--------security.md
- 导出 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标签内容一致即可
- 执行插件
这里直接执行右边maven菜单中的插件即可:asclidoctor:process-asclidoc
生成的html如图:
生成的pdf:
插件实现导出功能
- 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标签配合使用
- 执行插件
依旧直接执行右边的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
- 导出 html、pdf、xml 格式
这个步骤同通过代码导出文档中的第4步一样,这里 不再赘述。
解决pdf文档乱码空白问题
如果导出成功,但是pdf文档出现乱码或者文字空白的情况,解决办法如下:
- 打开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:配置文件目录
- 下载字体
字体下载: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目录中
- 修改配置
进入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