资讯专栏INFORMATION COLUMN

Gradle环境下导出Swagger为PDF

OnlyMyRailgun / 3131人阅读

摘要:没错,不支持,从导出的文档也可以看到,部分中文无法显示,目前我也尚未找到是否有配置可以实现这个功能。相对前面的方式,使用起来更加简单,也可以修改配置输出中文。

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

说明

我个人是一直使用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 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/Swagger2Ma...

仅为了简单的导出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....
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/Swagger2Ma...

配置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

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/74990.html

相关文章

  • 国外程序员整理的Java资源大全

    摘要:日期和时间处理日期和时间的函数库。使用中可观察序列,创建异步基于事件应用程序的函数库。为分布式系统提供延迟和容错处理。发布使用本机格式分发应用程序的工具。将程序资源和打包成和的本机文件。图像处理用来帮助创建评估或操作图形的函数库。 好资源要分享原文 译者 唐尤华 翻译自 github akullpp 构建 这里搜集了用来构建应用程序的工具。 Apache Maven:Mave...

    chengtao1633 评论0 收藏0
  • Spring Boot集成Freemarker和iText生成PDF文档

    摘要:格式文档导出,是信息系统中非常实用的一种功能,用于各种报表和文档的到处。示例中,使用生成要导出的格式文档,通过来实现文件下载。将转换成文档生成的代码比较简单,创建一个对象,然后会在指定的中输入生成的文件。作用相当于在中使用进行配置。 showImg(https://segmentfault.com/img/remote/1460000008547574); PDF格式文档导出,是信息系...

    liujs 评论0 收藏0
  • 【效率专精系列】善用API统一描述语言提升RestAPI开发效率

    摘要:其标准为前身是,提供强大的在线编辑功能,包括语法高亮错误提示自动完成实时预览,并且支持用户以格式撰写导入导出转换文档。 团队内部RestAPI开发采用设计驱动开发的模式,即使用API设计文档解耦前端和后端的开发过程,双方只在联调与测试时耦合。在实际开发和与前端合作的过程中,受限于众多因素的影响,开发效率还有进一步提高的空间。本文的目的是优化工具链支持,减少一部分重复和枯燥的劳动。 现状...

    tianyu 评论0 收藏0
  • 使用spring boot + swagger自动生成HTML、PDF接口文档,并解决中文显示空白

    摘要:首先是从下载了,这个已经能够生成和文档了,但是对中文支持不好,中文大部分会显示为空白。关于这个对中文支持不好,查了很多资料,应该是字体和主题的原因,所以参考了很多资料,结合当前这个,做出了最终的能很好支持中文的,最终地址。 做后端开发,自然离不开接口文档,接口文档不仅方便后端开发人员之间查看,更是前端人员必要的文档,也有可能提供给第三方来调用我们的接口。但是,写接口文档太费时间,而且如...

    fjcgreat 评论0 收藏0
  • 使用API自动生成工具优化前端工作流

    摘要:在工作中,我们的前端工作流一般开始于前后端协商好文档之后,再针对这个文档做模拟数据,然后用做好的进行开发,后端开发完毕之后再改一下数据的切换到正式进行联调如下本文介绍的一个工具或者说方法,来将这个工作流优化一下,也是我平时工作正在用的方法, 在工作中,我们的前端工作流一般开始于前后端协商好Api文档之后,再针对这个Api文档做mock模拟数据,然后用做好的mock进行开发,后端开发完毕...

    GeekQiaQia 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<