更多精彩博文,歡迎訪問個人我的博客java
我我的是一直使用Swagger做爲接口文檔的說明的。可是因爲在一些狀況下,接口文檔說明須要以文件的形式交付出去,若是再從新寫一份文檔不免有些麻煩。因而在網上看到了Swagger2Markup + asciidoctor導出PDF的方法,百度一番後感受網上的文章仍是有不少沒有描述清楚的地方,遂仍是硬着頭皮把官方的英文文檔大體瀏覽了一下,按照本身的思路整理出具體的步驟。git
本文用到的工具:github
SpringBoot中使用Swagger的過程就再也不贅述了,下面是本文使用的範例:web
@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();
}
}
複製代碼
官方教程地址:github.com/Swagger2Mar…spring
僅爲了簡單的導出PDF而言,本文針對官方案例均有所改動,去掉了部分沒有用到的配置。json
Swagger頁面本質上也就是對json文件進行解析。這裏須要先編寫單元測試訪問/v2/api-docs
接口並將json文件保存到本地。api
@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中的配置springboot
轉換json文件須要使用到io.github.swagger2markup
插件的convertSwagger2markup
方法。bash
引入相關依賴:mvc
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配置能夠參考:swagger2markup.github.io/swagger2mar…
轉換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,參見:github.com/Swagger2Mar…
配置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
]
}
複製代碼
task genPdf(type: Test, dependsOn: test) {
include '**/*SwaggerTest.class'
exclude '**/*'
dependsOn(asciidoctor)
}
複製代碼
執行genPdf,就能夠生成Swagger對應的PDF文件。
使用此方法步驟仍是比較繁瑣的,整體來說就是json -> adoc -> pdf,而且使用此種方法目前有幾個比較大的問題我仍然沒有找到解決方案:
1.5.0-alpha.16
版本之後(目前最新是1.5.0-alpha.18),這種方式生成文件會拋出異常,我我的並無深究這個異常,有興趣的讀者能夠經過修改版本號試一試。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也是官方推薦的使用方式。相對前面的方式,使用起來更加簡單,也能夠修改配置輸出中文。
plugins {
id 'org.asciidoctor.jvm.pdf' version '2.2.0'
}
複製代碼
與第一中方法不一樣的是,不須要再將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文件的緣由。
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
爲了解決中文沒法顯示的問題,首先須要自行下載一個支持中文的字體文件。
修改主題文件,將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)
}
複製代碼
github.com/Swagger2Mar… github.com/Swagger2Mar… swagger2markup.github.io/swagger2mar…
更多精彩博文,歡迎訪問個人我的博客