更多精彩博文,欢迎访问我的个人博客


说明

我个人是一直使用Swagger作为接口文档的说明的。但是由于在一些情况下,接口文档说明需要以文件的形式交付出去,如果再重新写一份文档难免有些麻烦。于是在网上看到了Swagger2Markup + asciidoctor导出PDF的方法,百度一番后感觉网上的文章还是有很多没有描述清楚的地方,遂还是硬着头皮把官方的英文文档大致浏览了一下,按照自己的思路整理出具体的步骤。

本文用到的工具:

  • Gradle - 4.10.3
  • SpringBoot - 2.1.6.RELEASE
  • Swagger - 2.9.2
  • Swagger2Markup - 1.3.3
  • asciidoctor
  • spring-restdocs-mockmvc

准备Swagger数据

SpringBoot中使用Swagger的过程就不再赘述了,下面是本文使用的范例:

@Configuration
@EnableSwagger2
class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.jptangchina.gradle.controller"))
.paths(PathSelectors.any())
.build();
} private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Swagger2Markup Test Api")
.version("1.0")
.build();
}
}
@RestController
@RequestMapping("/user")
@Api(tags = "用户接口")
public class UserController { @ApiOperation("用户登录")
@ResponseBody
@PostMapping("/login")
public Result<Void> login(
@ApiParam(value = "用户名", example = "jptangchina", required = true) @RequestParam String username,
@ApiParam(value = "密码", example = "jptangchina", required = true) @RequestParam String password) {
return Result.ok();
}
}

使用org.asciidoctor.convert生成PDF(个人不推荐使用)

官方教程地址:https://github.com/Swagger2Markup/spring-swagger2markup-demo

仅为了简单的导出PDF而言,本文针对官方案例均有所改动,去掉了部分没有用到的配置。

1. 获取Swagger json文件

Swagger页面本质上也就是对json文件进行解析。这里需要先编写单元测试访问/v2/api-docs接口并将json文件保存到本地。

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
class SwaggerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void generateAsciiDocsToFile() throws Exception {
String outputDir = System.getProperty("io.springfox.staticdocs.outputDir");
MvcResult mvcResult = this.mockMvc.perform(get("/v2/api-docs")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andReturn(); MockHttpServletResponse response = mvcResult.getResponse();
String swaggerJson = response.getContentAsString();
Files.createDirectories(Paths.get(outputDir));
try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(outputDir, "swagger.json"), StandardCharsets.UTF_8)){
writer.write(swaggerJson);
}
} }

System.getProperty("io.springfox.staticdocs.outputDir");来自于build.gradle中的配置

2. 将json文件转换为adoc文件

转换json文件需要使用到io.github.swagger2markup插件的convertSwagger2markup方法。

引入相关依赖:

buildscript {
...
dependencies {
...
classpath 'io.github.swagger2markup:swagger2markup-gradle-plugin:1.3.3'
}
} apply plugin: 'io.github.swagger2markup'

配置convertSwagger2markup:

ext {
asciiDocOutputDir = file("${buildDir}/asciidoc")
swaggerOutputDir = file("${buildDir}/swagger")
} test {
systemProperty 'io.springfox.staticdocs.outputDir', swaggerOutputDir
} convertSwagger2markup {
dependsOn test
swaggerInput "${swaggerOutputDir}/swagger.json"
outputDir asciiDocOutputDir
config = [
'swagger2markup.pathsGroupedBy' : 'TAGS',
]
}

更多config配置可以参考:http://swagger2markup.github.io/swagger2markup/1.3.3/#_swagger2markup_properties

3. 将adoc文件转换为PDF文件

转换PDF文件需要用到org.asciidoctor.convert插件的asciidoctor方法。

引入相关依赖:

buildscript {
...
dependencies {
...
classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.3'
}
}
apply plugin: 'org.asciidoctor.convert'

手动编写index.adoc文件,放置到${asciiDocOutputDir.absolutePath}中:

include::{generated}/overview.adoc[]
include::{generated}/paths.adoc[]
include::{generated}/definitions.adoc[]
include::{generated}/security.adoc[]

{generated}默认值为${build}/asciidoc,参见:https://github.com/Swagger2Markup/swagger2markup-gradle-project-template

配置asciidoctor:

asciidoctor {
dependsOn convertSwagger2markup
// sourceDir中需要包含有之前手动编写的index.adoc文件
sourceDir(asciiDocOutputDir.absolutePath)
sources {
include "index.adoc"
}
backends = ['pdf']
attributes = [
doctype: 'book',
toc: 'left',
toclevels: '3',
numbered: '',
sectlinks: '',
sectanchors: '',
hardbreaks: '',
generated: asciiDocOutputDir
]
}

4. 编写一个自定义task用来执行上述流程:

task genPdf(type: Test, dependsOn: test) {
include '**/*SwaggerTest.class'
exclude '**/*'
dependsOn(asciidoctor)
}

执行genPdf,就可以生成Swagger对应的PDF文件。

5. 小结

使用此方法步骤还是比较繁琐的,总体来讲就是json -> adoc -> pdf,并且使用此种方法目前有几个比较大的问题我仍然没有找到解决方案:

  • 从官方文档中可以看到支持的语言默认有EN, DE, FR, RU。没错,不支持CN,从导出的文档也可以看到,部分中文无法显示,目前我也尚未找到是否有配置可以实现这个功能。网上的文章部分是通过替换源代码包里面的字体文件来实现,但是由于后面有更好的解决方案,这里就不再讨论。
  • 从asciidoctorj-pdf的1.5.0-alpha.16版本以后(目前最新是1.5.0-alpha.18),这种方式生成文件会抛出异常,我个人并没有深究这个异常,有兴趣的读者可以通过修改版本号试一试。
  • 生成的adoc文件一般包含overview.adoc、paths.adoc、definitions.adoc、security.adoc一共4个文件,这也是为什么要手动编写index.adoc进行整合的原因,感觉不太方便。

    综上,我个人并不推荐采用此方式生成PDF。

build.gradle完整文件参考:

buildscript {
ext {
springbootVersion = '2.1.6.RELEASE'
}
repositories {
maven {
url 'http://maven.aliyun.com/nexus/content/groups/public'
}
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springbootVersion}"
classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.3'
classpath 'io.github.swagger2markup:swagger2markup-gradle-plugin:1.3.3'
}
} repositories {
maven {
url 'http://maven.aliyun.com/nexus/content/groups/public'
}
} apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'io.github.swagger2markup'
apply plugin: 'org.asciidoctor.convert' group 'com.jptangchina'
version '1.0-SNAPSHOT' sourceCompatibility = 1.8
targetCompatibility = 1.8 ext {
asciiDocOutputDir = file("${buildDir}/asciidoc")
swaggerOutputDir = file("${buildDir}/swagger")
swaggerVersion = '2.9.2'
} dependencies {
compile 'org.springframework.boot:spring-boot-starter-web'
compile "io.springfox:springfox-swagger2:${swaggerVersion}"
compile "io.springfox:springfox-swagger-ui:${swaggerVersion}"
compile 'io.github.swagger2markup:swagger2markup:1.3.3'
asciidoctor 'org.asciidoctor:asciidoctorj-pdf:1.5.0-alpha.16'
testCompile 'org.springframework.boot:spring-boot-starter-test'
testCompile 'org.springframework.restdocs:spring-restdocs-mockmvc'
} test {
systemProperty 'io.springfox.staticdocs.outputDir', swaggerOutputDir
} convertSwagger2markup {
dependsOn test
swaggerInput "${swaggerOutputDir}/swagger.json"
outputDir asciiDocOutputDir
config = [
'swagger2markup.pathsGroupedBy' : 'TAGS',
]
} asciidoctor {
dependsOn convertSwagger2markup
sourceDir(asciiDocOutputDir.absolutePath)
sources {
include "index.adoc"
}
backends = ['pdf']
attributes = [
doctype: 'book',
toc: 'left',
toclevels: '3',
numbered: '',
sectlinks: '',
sectanchors: '',
hardbreaks: '',
generated: asciiDocOutputDir
]
} task genPdf(type: Test, dependsOn: test) {
include '**/*SwaggerTest.class'
exclude '**/*'
dependsOn(asciidoctor)
}

使用asciidoctor-gradle-plugin生成PDF(推荐)

asciidoctor-gradle-plugin也是官方推荐的使用方式。相对前面的方式,使用起来更加简单,也可以修改配置输出中文。

1. 引入插件

plugins {
id 'org.asciidoctor.jvm.pdf' version '2.2.0'
}

2. 编写测试类生成adoc

与第一中方法不同的是,不需要再将json文件保存到本地了。

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class SwaggerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void generateAsciiDocsToFile() throws Exception {
String outputDir = System.getProperty("io.springfox.staticdocs.outputDir");
MvcResult mvcResult = this.mockMvc.perform(get("/v2/api-docs")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andReturn(); Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()
.withMarkupLanguage(MarkupLanguage.ASCIIDOC)
.withOutputLanguage(Language.ZH)
.withPathsGroupedBy(GroupBy.TAGS)
.withGeneratedExamples()
.withoutInlineSchema()
.build(); MockHttpServletResponse response = mvcResult.getResponse();
String swaggerJson = response.getContentAsString();
Swagger2MarkupConverter.from(swaggerJson)
.withConfig(config)
.build()
.toFile(Paths.get(outputDir + "/swagger"));
}
}

有兴趣的读者可以阅读下toFile方法的源码,里面对第一种方法生成的4个文件进行了整合,这也是不再需要手动编写index.adoc文件的原因。

3. 配置asciidoctorPdf


ext {
asciiDocOutputDir = file("${buildDir}/asciidoc")
// 创建字体与主题的文件夹
pdfFontsDir = file("${buildDir}/fonts")
pdfThemesDir = file("${buildDir}/themes")
swaggerVersion = '2.9.2'
} pdfThemes {
local 'basic', {
styleDir = pdfThemesDir
// styleName会被程序用于匹配${styleName}-theme.yml,如default-styleName-theme.yml
styleName = 'default'
}
}
asciidoctorPdf{
sourceDir(asciiDocOutputDir.absolutePath)
sources {
include "swagger.adoc"
}
fontsDir(pdfFontsDir.absolutePath)
theme("basic")
}

本文字体与主题文件均来自于asciidoctorj-pdf-1.5.0-alpha.18.jar源码包,其路径位于:gems/asciidoctorj-pdf-1.5.0-alpha.18/data

4. 复制并修改default-theme.yml文件配置

为了解决中文无法显示的问题,首先需要自行下载一个支持中文的字体文件。

修改主题文件,将mplus1p-regular-fallback.ttf替换为自己下载的字体文件的名称。

M+ 1p Fallback:
normal: your-font.ttf
bold: your-font.ttf
italic: your-font.ttf
bold_italic: your-font.ttf

由于手动指定了字体文件的路径,所以除了中文以外,还需要将源码中的其他字体文件一并复制到${pdfFontsDir}文件夹。如果不愿意使用官方的字体,也可以考虑将default-theme.yml中其他的字体文件都修改为自己想要的文件。

保持task genPdf不变,再次运行即可生成PDF文件,生成的文件默认路径为${build}/docs/asciidocPdf

小结

asciidoctor-gradle-plugin的方式可以支持配置字体与主题,通过配置不仅规避了中文无法显示的问题,同时使用起来也更加简单。需要注意的是,采用此种方案生成出的文档会在封面写有项目的版本号,此版本号为build.gradle中的version,而非SwaggerConfig类中的version。

官方提供了很多配置,可以自行参考官方文档查看。

build.gradle完整文件参考:

buildscript {
ext {
springbootVersion = '2.1.6.RELEASE'
}
repositories {
maven {
url 'http://maven.aliyun.com/nexus/content/groups/public'
}
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springbootVersion}"
}
} plugins {
id 'org.asciidoctor.jvm.pdf' version '2.2.0'
} repositories {
maven {
url 'http://maven.aliyun.com/nexus/content/groups/public'
}
} apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management' group 'com.jptangchina'
version '1.0-SNAPSHOT' sourceCompatibility = 1.8
targetCompatibility = 1.8 ext {
asciiDocOutputDir = file("${buildDir}/asciidoc")
pdfFontsDir = file("${buildDir}/fonts")
pdfThemesDir = file("${buildDir}/themes")
swaggerVersion = '2.9.2'
} dependencies {
compile 'org.springframework.boot:spring-boot-starter-web'
compile "io.springfox:springfox-swagger2:${swaggerVersion}"
compile "io.springfox:springfox-swagger-ui:${swaggerVersion}"
compile 'io.github.swagger2markup:swagger2markup:1.3.3'
testCompile 'org.springframework.boot:spring-boot-starter-test'
testCompile 'org.springframework.restdocs:spring-restdocs-mockmvc'
} test {
systemProperty 'io.springfox.staticdocs.outputDir', asciiDocOutputDir
} pdfThemes {
local 'basic', {
styleDir = pdfThemesDir
styleName = 'default'
}
}
asciidoctorPdf{
sourceDir(asciiDocOutputDir.absolutePath)
sources {
include "swagger.adoc"
}
fontsDir(pdfFontsDir.absolutePath)
theme("basic")
} task genPdf(type: Test, dependsOn: test) {
include '**/*SwaggerTest.class'
exclude '**/*'
dependsOn(asciidoctorPdf)
}

参考

https://github.com/Swagger2Markup/swagger2markup

https://github.com/Swagger2Markup/spring-swagger2markup-demo

http://swagger2markup.github.io/swagger2markup/1.3.3


更多精彩博文,欢迎访问我的个人博客

Gradle环境下导出Swagger为PDF的更多相关文章

  1. 在linux环境下使用itext生成pdf

    转载请注明出处 https://www.cnblogs.com/majianming/p/9537173.html 项目中需要对订单生成pdf文件,在不断的尝试之后,终于生成了比较满意的pdf文档. ...

  2. 配置不同环境下启用swagger,在生产环境关闭swagger

    前言 Swagger使用起来简单方便,几乎所有的API接口文档都采用swagger了.使用示例:http://www.cnblogs.com/woshimrf/p/swagger.html, 现在开发 ...

  3. 在生产环境下禁用swagger

    学习目标 快速学会使用注解关闭Swagger2,避免接口重复暴露. 使用教程 禁用方法1:使用注解@Profile({"dev","test"}) 表示在开发或 ...

  4. .NET环境下导出Excel表格的两种方式和导入两种类型的Excel表格

    一.导出Excel表格的两种方式,其中两种方式指的是导出XML数据类型的Excel(即保存的时候可以只需要修改扩展名为.xls)和真正的Excel这两种. using System; using Sy ...

  5. Yii2 PHPExcel在linux环境下导出报500错误

    断点调试后发现是因为这句报错 header('Content-Type : application/vnd.ms-excel');删除后正常输出下载

  6. 一次生产环境下MongoDB备份还原数据

    最近开发一个版本的功能当中用到了MongoDB分页,懒于造数据,于是就研究了下从生产环境上导出数据到本地来进行测试. 研究了一下,发现MongoDB的备份还原和MySQL语法还挺类似,下面请看详细介绍 ...

  7. SpringBoot + Vue + ElementUI 实现后台管理系统模板 -- 后端篇(一): 搭建基本环境、整合 Swagger、MyBatisPlus、JSR303 以及国际化操作

    相关 (1) 相关博文地址: SpringBoot + Vue + ElementUI 实现后台管理系统模板 -- 前端篇(一):搭建基本环境:https://www.cnblogs.com/l-y- ...

  8. .net环境下从PDF文档中抽取Text文本的一些方法汇总

    1.PDFBox的IKVM版本:据我所知,目前只有PDFBox的IKVM版本能比较好地从PDF中提取文本,PDFBOX更多信息请访问http://www.pdbox.org,关于其应用实例,可以参考C ...

  9. Mac python3 环境下 完善pdf转jpg脚本

    由于样本图片数据都是保存在pdf里,想拿到样本必须先把图片从pdf中提取出来,算是数据清洗中的一点小小的积累吧. 这里不得不吐槽一下公司存储图片的机制,业务员把jpg格式的照片放到word里,然后用工 ...

随机推荐

  1. aria2安装webui

    安装aria2 yum install aria2 安装完成后可以使用简单命令进行下载 aria2c http://example.org/mylinux.iso aria2c -c -s http: ...

  2. CodeForces 363D 【二分+贪心】

    思路: 一开始是没有办法贪心的,但是答案是可以二分的,因为窝能买k辆车的话,窝就一定能买k-1辆车:而且我最好就是拿手上钱较多的那些人去买价格便宜的车,这样肯定是能买到最多的车,而且花的少,因为对于要 ...

  3. unity 在移动平台中,文件操作路径详解

    今天,这篇文章其实是个老生常谈的问题咯,在网上类似的文章也比比皆是,在此我只是做个详细总结方便大家能够更好.更快的掌握,当然,如有不足的地方 欢迎指正!!! 相信大家在开发过程中,难免会保存一些文件在 ...

  4. 2013 Noip提高组 Day1

    3285 转圈游戏 2013年NOIP全国联赛提高组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解       题目描述 Description ...

  5. Python 实现简单的登录注册界面

    Python 实现简单的登录注册界面 注意:编写代码之前需要导入很重要的包 import tkinter as tk import pickle from tkinter import message ...

  6. MySQL习题1 一对多实例 产品和分类

    /* 需求:建立产品和分类表 1.查询每种分类的产品数量,没有产品的分类也要统计.(cname,quantity) 2.根据分类名称查询分类中的所有产品 */ -- ----------------- ...

  7. beanutils包下载

  8. web.xml中一个filter配置多个url-pattern

    需要在filter标签后添加多个filter-mapping标签,一个url-pattern就对应一个filter-mapping标签,不能直接把多个url-pattern配置到同一个filter-m ...

  9. HDU6298(2018多校第一场)

    Bryce1010模板 http://acm.hdu.edu.cn/showproblem.php?pid=6298 打表找规律: #include<bits/stdc++.h> usin ...

  10. 关于在ARM MDK 中使用STM32F4xx 硬件浮点单元的话题

    http://mp.weixin.qq.com/s/CDyZ8v2kLiyuIBHf7iqEPA