Swagger 在工程師或測試方面幫助很大,但有些人員非工程背景,拿到 Jar 檔也不會執行,也就看不到 API 規格,所以還是需要一份文件,這時候我們既然都定義好 Swagger 了,直接用來輸出就最方便
流程來說是 測試程式產出 adoc 檔 -> plugins org.asciidoctor.convert 轉換成 html 等其他格式
buildscript {
ext {
springBootVersion = '1.5.2.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
plugins {
id 'org.asciidoctor.convert' version '1.5.2'
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
jar {
baseName = 'ps-account'
version = '0.0.1-SNAPSHOT'
dependsOn asciidoctor
}
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-data-rest')
compile('org.springframework.boot:spring-boot-starter-mail')
compile('org.springframework.boot:spring-boot-starter-security')
compile('org.springframework.boot:spring-boot-starter-web')
compile 'org.springframework.security.oauth:spring-security-oauth2:2.0.12.RELEASE'
compile 'org.springframework.security:spring-security-jwt:1.0.7.RELEASE'
compile 'org.modelmapper:modelmapper:0.7.7'
compile 'org.apache.commons:commons-lang3:3.5'
compile 'mysql:mysql-connector-java:6.0.5'
compile 'io.springfox:springfox-swagger2:2.6.1'
compile 'io.springfox:springfox-swagger-ui:2.6.1'
compile 'io.springfox:springfox-data-rest:2.6.1'
compileOnly('org.projectlombok:lombok')
testCompile 'io.springfox:springfox-staticdocs:2.6.1'
testCompile 'org.springframework.restdocs:spring-restdocs-mockmvc:1.1.2.RELEASE'
testRuntime('com.h2database:h2')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
asciidoctor {
dependsOn test
sourceDir 'src/docs/asciidoc'
attributes 'snippets': file("build/asciidoc"),
'doctype': 'book',
'icons': 'font',
'source-highlighter': 'highlightjs',
'toc': 'left',
'toclevels': 2,
'sectlinks': true
outputDir = file('build/asciidoc/generated')
// backends 'html5', 'pdf', 'epub3', 'docbook' , 'revealjs'
// sourceDir = file('src/docs/asciidoc')
// outputDir = file('build/asciidoc/generated')
}
- 首先加入 plugins { id 'org.asciidoctor.convert' version '1.5.2' }
- 再來加入
- testCompile 'io.springfox:springfox-staticdocs:2.6.1'
- testCompile 'org.springframework.restdocs:spring-restdocs-mockmvc:1.1.2.RELEASE'
- 定義 asciidoctor 區塊,也就是轉換成 html 的樣式
- jar 區塊加上 dependsOn asciidoctor 這樣一來我們在打包時就可以順便轉出一份文檔
如果需要其他格式,可以再加上 backends 'html5', 'pdf', 'epub3', 'docbook' , 'revealjs'
這樣一來就可以了...but 理論上是這樣,不過除了 html 以外其他我試不出來,應該是配置有些不同吧
目前沒用到就不研究了
sourceDir 'src/docs/asciidoc' 這部分呢是指來源資料夾
但是 Swagger 預設會輸出三份 adoc ,這樣就會變成三份分開的文件
所以需要手動編排一下像下面
編排的內容如下,簡單用就是把產出的文件包進來
= {project-name} Getting Started Guide
:revnumber: {project-version}
include::introduction.adoc[]
include::generated/overview.adoc[]
include::generated/paths.adoc[]
include::generated/definitions.adoc[]
[[resources]]
= Resources
// \include::resources/some-resource.adoc[] 註解
{project-name} is a RESTful web service for manager user account & permission.
最後準備產出 adoc 的測試程式
package com.ps;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.github.robwin.markup.builder.MarkupLanguage;
import io.github.robwin.swagger2markup.GroupBy;
import io.github.robwin.swagger2markup.Swagger2MarkupConverter;
import org.apache.commons.lang3.Validate;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultHandler;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
/**
* Created by samchu on 2017/3/28.
*/
@AutoConfigureMockMvc
@RunWith(SpringRunner.class)
@SpringBootTest
public class Swagger2MarkupTest {
@Autowired
private MockMvc mockMvc;
@Before
public void setUp() {
}
// 輸出成 adoc 格式
@Test
public void convertSwaggerToAsciiDoc() throws Exception {
this.mockMvc.perform(get("/v2/api-docs")
.accept(MediaType.APPLICATION_JSON))
// 原本的寫法
//.andDo(Swagger2MarkupResultHandler.outputDirectory("src/docs/asciidoc/generated").build())
// 稍微客製化只留下api開頭的path
.andDo(new PsSwagger2MarkupHandler("src/docs/asciidoc/generated"))
.andExpect(status().isOk());
}
// 輸出成 Markdown 格式
// @Test
// public void convertSwaggerToMarkdown() throws Exception {
// this.mockMvc.perform(get("/v2/api-docs")
// .accept(MediaType.APPLICATION_JSON))
// .andDo(Swagger2MarkupResultHandler.outputDirectory("docs/markdown/generated")
// .withMarkupLanguage(MarkupLanguage.MARKDOWN).build())
// .andExpect(status().isOk());
// }
// 一般寫測試兼輸出的方式
// @Test
// public void testIndex() throws Exception {
// this.mockMvc.perform(get("/api/test").accept(MediaType.APPLICATION_JSON))
// .andExpect(status().isOk())
// .andDo(document("test", preprocessResponse(prettyPrint())));
// }
class PsSwagger2MarkupHandler implements ResultHandler {
private String outputDir;
private final MarkupLanguage markupLanguage = MarkupLanguage.ASCIIDOC;
private String examplesFolderPath;
private final GroupBy pathsGroupedBy = GroupBy.AS_IS;
private final String encoding = "UTF-8";
private String passStr = "listRepositories,getCollectionResource,getItemResource,getCollectionResourceCompact,listSearches,errorHtml,listAllFormsOfMetadata,schema";
public PsSwagger2MarkupHandler(String outputDir) {
Validate.notEmpty(outputDir, "outputDir must not be empty!");
this.outputDir = outputDir;
}
@Override
public void handle(MvcResult result) throws Exception {
MockHttpServletResponse response = result.getResponse();
response.setCharacterEncoding(encoding);
String swaggerJson = response.getContentAsString();
// 去除掉 Spring Data Rest 提供的基礎路徑
List<String> passSummary = Arrays.asList(passStr.split(","));
ObjectMapper mapper = new ObjectMapper();
ObjectNode newPaths = mapper.createObjectNode();
JsonNode jsonRoot = mapper.readTree(swaggerJson);
JsonNode jsonPaths = jsonRoot.get("paths");
Iterator<String> keyit = jsonPaths.fieldNames();
while (keyit.hasNext()) {
String key = keyit.next();
JsonNode jsonPath = jsonPaths.get(key);
String summary = jsonPath.findPath("summary").asText();
if (!passSummary.contains(summary)) {
newPaths.set(key, jsonPath);
}
}
((ObjectNode) jsonRoot).set("paths", newPaths);
swaggerJson = jsonRoot.toString();
// 這邊輸出成 adoc
Swagger2MarkupConverter.fromString(swaggerJson).withMarkupLanguage(markupLanguage)
.withPathsGroupedBy(this.pathsGroupedBy)
.withExamples(examplesFolderPath).build().intoFolder(outputDir);
}
}
}
這樣大致就完成,執行 gradle test 會產出 adoc ,執行 jar 會轉成文檔的格式
如果是 html 會是在這裡 build\asciidoc\generated\html5 像這樣
就可以打包提供給相關人員囉
參考資料
asciidoctor/asciidoctor-gradle-plugin: A Gradle plugin that uses Asciidoctor via JRuby to process AsciiDoc source files within the project.
jhipster Static API documentation
BeeWorks - Bootiful CMS part 3 - Microservice with Test-Driven Documentation