Swagger 是一个简单但功能强大的 API 表达工具,它开源在 Github 中。

swagger2markup

swagger2markup用来将我们手写的或自动生成的 swagger.yaml 或 swagger.json 转换成漂亮的 AsciiDoc 或 Markdown 格式文件。 然后再通过 asciidoctor-maven-plugin 将其转换为 HTML、PDF 格式文档看。

具体操作或者缺少的文件,可以通过 spring-swagger2markup-demo 下载。

引入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!--swagger2 依赖 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.github.swagger2markup</groupId>
<artifactId>swagger2markup</artifactId>
<version>1.3.3</version>
<scope>test</scope>
</dependency>

增加 UserDo 实体对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Data
@ApiModel(value = "user 对象 ", description = " 用户对象 user")
public class UserDo {

@ApiModelProperty(value = " 必须是 2~5 个中文汉字 ", required = true)
private String username;
private String password;

/**
* 不加 example 时,会报:java.lang.NumberFormatException: For input string: ""
* 原因是 example 默认是空字符串。在转换时,无法把空字符串转换成 int 类型。
*/
@ApiModelProperty(value = " 年龄要求:18 < age < 60", example = "18")
private int age;

}

增加 HelloController 测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/**
* Created with IntelliJ IDEA.
* DateTime: 2020/5/15 11:10
*
* @author muycode
*/
@RestController
@RequestMapping("/hello")
@Api(value = "/hello", tags = "Test 控制层 ")
public class HelloController {

@GetMapping("/sayHello1")
@ApiOperation(value = " 测试无参 ", notes = " 可以无参调用 ")
@ApiResponses(value = {
@ApiResponse(code = 1001, message = " 通用异常 "),
@ApiResponse(code = 1002, message = " 没有找到要查询的数据 ")
})
public String sayHello1(){
return "sayHello1";
}

@GetMapping("/sayHello2")
@ApiOperation(value = " 测试 String 类型参数 ", notes = " 当 rid 不为 null 时,查询该实体。为 null 时,返回 null")
@ApiResponses(value = {
@ApiResponse(code = 1001, message = " 通用异常 "),
@ApiResponse(code = 1002, message = " 没有找到要查询的数据 "),
@ApiResponse(code = 1003, message = "rid 传递错误 "),
@ApiResponse(code = 0, message = " 根据 rid 返回对应的对象 ")
})
@ApiIgnore // 可以过滤不想要加入的 Controller 和方法
public Object sayHello2(@ApiParam(value = "rid 是必须的 ", required = true) String rid) {
return "sayHello2";
}

@GetMapping("/sayHello3")
@ApiOperation(value = " 测试对象类型参数 ", notes = " 根据传递过来的对象,检查该对象里面的数据 ", response = UserDo.class)
@ApiResponses(value = {
@ApiResponse(code = 1001, message = " 通用异常 "),
@ApiResponse(code = 1002, message = " 没有找到要查询的数据 "),
@ApiResponse(code = 1003, message = "rid 传递错误 "),
@ApiResponse(code = 1004, message = " 对象传递错误 "),
@ApiResponse(code = 0, message = " 根据 rid 返回对应的对象 ")
})
public Object sayHello3(
@ApiParam(value = " 用户的实体对象 ") UserDo userDo) {
return "sayHello3";
}

@ApiOperation(value = " 测试对象、String 类型参数 ", notes = " 根据传递过来的对象和 rid,检查该对象里面的数据是否和 rid 匹配 ", response = UserDo.class)
@ApiResponses(value = {
@ApiResponse(code = 1001, message = " 通用异常 "),
@ApiResponse(code = 1002, message = " 没有找到要查询的数据 "),
@ApiResponse(code = 1003, message = "rid 传递错误 "),
@ApiResponse(code = 0, message = " 根据 rid 返回对应的对象 ")
})
@GetMapping("/sayHello4")
public Object sayHello4(UserDo userDo, String rid) {
return "sayHello4";
}
}

增加 Swagger 配置文件

com.muycode.bsservice.config.swagger

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
* Created with IntelliJ IDEA.
* DateTime: 2020/6/2 10:00
* Swagger 配置
*
* @author muycode
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig {

@Bean
public Docket sysApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.muycode"))
.paths(PathSelectors.any())
.build().globalOperationParameters(parameter());
}

@Bean
public ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title(" 用户中心微服务接口 ")
.description(" 用户中心微服务的所有接口 API")
.termsOfServiceUrl("")
.version("1.0.0")
.build();
}

private List<Parameter> parameter() {
List<Parameter> params = new ArrayList<>();
params.add(new ParameterBuilder().name("Authorization")
.description("Authorization Bearer token")
.modelRef(new ModelRef("string"))
.parameterType("header")
.required(false).build());
return params;
}
}

此时启动服务,通过 http://127.0.0.1:8761/swagger-ui.html 可查看 API 接口文档。

生成静态文件

增加 index.adoc 文件

src/docs/asciidoc/index.adoc

1
2
3
4
include::{generated}/overview.adoc[]
include::{generated}/security.adoc[]
include::{generated}/paths.adoc[]
include::{generated}/definitions.adoc[]

配置 asciidoctor-maven-plugin 插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>11</java.version>

<swagger2markup.version>1.3.1</swagger2markup.version>
<swagger2markup.plugin.version>1.3.3</swagger2markup.plugin.version>
<swagger2markup.extension.version>1.3.1</swagger2markup.extension.version>

<asciidoctorj.version>1.5.5</asciidoctorj.version>
<asciidoctorj.pdf.version>1.5.0-alpha.15</asciidoctorj.pdf.version>
<jruby.version>9.1.8.0</jruby.version>

<swagger.input>${project.basedir}/src/docs/swagger/swagger_petstore.yaml</swagger.input>
<asciidoctor.input.directory>${project.basedir}/src/docs/asciidoc</asciidoctor.input.directory>
<generated.asciidoc.directory>${project.build.directory}/asciidoc</generated.asciidoc.directory>
<asciidoctor.html.output.directory>${project.build.directory}/asciidoc/html</asciidoctor.html.output.directory>
<asciidoctor.pdf.output.directory>${project.build.directory}/asciidoc/pdf</asciidoctor.pdf.output.directory>
</properties>

<pluginRepositories>
<pluginRepository>
<id>jcenter-snapshots</id>
<name>jcenter</name>
<url>http://oss.jfrog.org/artifactory/oss-snapshot-local/</url>
</pluginRepository>
<pluginRepository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>jcenter-releases</id>
<name>jcenter</name>
<url>http://jcenter.bintray.com</url>
</pluginRepository>
</pluginRepositories>

<build>
<plugins>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>1.5.5</version>
<!-- 包括用于生成 PDF 的 Asciidoctor PDF -->
<dependencies>
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj-pdf</artifactId>
<version>${asciidoctorj.pdf.version}</version>
</dependency>
<!-- 注释此部分以使用插件提供的默认 jruby 工件 -->
<dependency>
<groupId>org.jruby</groupId>
<artifactId>jruby-complete</artifactId>
<version>${jruby.version}</version>
</dependency>
<!-- 注释此部分以使用插件提供的默认 AsciidoctorJ 工件 -->
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj</artifactId>
<version>${asciidoctorj.version}</version>
</dependency>
</dependencies>
<!-- 配置通用文档生成设置 -->
<configuration>
<sourceDirectory>${asciidoctor.input.directory}</sourceDirectory>
<sourceDocumentName>index.adoc</sourceDocumentName>
<attributes>
<doctype>book</doctype>
<toc>left</toc>
<toclevels>3</toclevels>
<generated>${generated.asciidoc.directory}</generated>
</attributes>
</configuration>
<!-- 因为每个执行只能处理一个后端,所以运行为每个期望的输出类型单独执行 -->
<executions>
<execution>
<id>output-html</id>
<phase>generate-resources</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>html5</backend>
<outputDirectory>${asciidoctor.html.output.directory}</outputDirectory>
</configuration>
</execution>

<execution>
<id>output-pdf</id>
<phase>generate-resources</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>pdf</backend>
<outputDirectory>${asciidoctor.pdf.output.directory}</outputDirectory>

<!-- 以下配置解决生成 pdf 中文乱码
需要先下载好字体和主题:
https://github.com/chloerei/asciidoctor-pdf-cjk-kai_gen_gothic/releases/tag/v0.1.0-fonts
(RobotoMono 开头和 KaiGenGothicCN 开头的字体文件 8 个和 theme 文件(Source code (zip))
1、把下载的 8 个字体文件复制到 fonts 目录下
2、data\themes\ 下的 cn-theme.yml 复制到 themes 目录 -->
<sourceHighlighter>coderay</sourceHighlighter>
<doctype>book</doctype>
<attributes>
<toc>left</toc>
<toclevels>3</toclevels>
<generated>${generated.asciidoc.directory}</generated>
<pdf-fontsdir>fonts</pdf-fontsdir>
<pdf-stylesdir>themes</pdf-stylesdir>
<pdf-style>cn</pdf-style>
</attributes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

增加 Test 类,用来生成 adoc 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.muycode.test;

import com.muycode.bsservice.BsServiceApplication;
import io.github.swagger2markup.Swagger2MarkupConfig;
import io.github.swagger2markup.Swagger2MarkupConverter;
import io.github.swagger2markup.builder.Swagger2MarkupConfigBuilder;
import io.github.swagger2markup.markup.builder.MarkupLanguage;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
* Created with IntelliJ IDEA.
* DateTime: 2020/6/2 18:16
* 生成 adoc 文件,为后续生成静态文件做准备
* mvn process-resources
*
* @author muycode
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = BsServiceApplication.class)
public class DemoApplicationTests {

/**
* 执行完该测试方法,需要再执行
* mvn process-resources
*
* @throws Exception
*/
@Test
public void generateAsciiDocs() throws Exception {

URL remoteSwaggerFile = new URL("http://127.0.0.1:8761/v2/api-docs");
Path outputDirectory = Paths.get("target/asciidoc");

// 输出 Ascii 格式
Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()
.withMarkupLanguage(MarkupLanguage.ASCIIDOC)
.build();

Swagger2MarkupConverter.from(remoteSwaggerFile)
.withConfig(config)
.build()
.toFolder(outputDirectory);
}
}

生成文件

  • 启动服务
  • 执行 Test 文件
  • 执行 mvn process-resources 会在 target\asciidoc 文件夹生成静态文件。

官网图片


参考文章

Swagger2Markup Documentation

使用 Swagger 生成 RESTful API 文档