最近因为项目中需要编写接口文档,原来用的swagger结合现有项目问题比较多,且没有直观的目录(不知道swagger是否有左边栏目录这样的形式,没去细查),配合前端和测试使用时,他们抱怨比较多,所以摒弃了swagger之后,找到了spring rest docs, 结合官方文档和网上查到的资料,成功生成了接口文档。样例如下:
spring rest docs的使用其实就是在你现有的spring mvc或spring boot的项目上,配置生成文档的依赖包,然后编写接口单元测试,编写adoc配置文件,最后打包自动生成html接口文档的过程。根据这个步骤一步步操作:
1、配置依赖:
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-mockmvc</artifactId>
<scope>test</scope>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>1.5.3</version>
<executions>
<execution>
<id>generate-docs</id>
<phase>prepare-package</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>html</backend>
<doctype>book</doctype>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-asciidoctor</artifactId>
<version>1.2.1.RELEASE</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>
${project.build.outputDirectory}/static/docs
</outputDirectory>
<resources>
<resource>
<directory>
${project.build.directory}/generated-docs
</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
2、编写接口测试
我们通过mock进行接口测试编写,测试类属性配置及单测前的before方法:
@Rule
public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("target/generated-snippets");//生成的adoc文件导出目录
private MockMvc mockMvc;
@Autowired
private WebApplicationContext context;
@Before
public void setUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration(this.restDocumentation))
// .alwaysDo(document("{method-name}/{step}/"))
.build();
}
单测例子(与普通的mock测试多了红色标注的部分,语法什么的我就不在这里讲解了,要想写出来,肯定要看官方文档:
点击打开链接,如果不想看英文,看这个博客也可以:
点击打开链接,不过,还是强烈推荐看官方文档):
@Test
public void contextLoads() throws Exception {
this.mockMvc.perform(get("/hello?page=2&per_page=100").accept(MediaType.APPLICATION_JSON).header("Authorization", "Basic dXNlcjpzZWNyZXQ="))
.andDo(print()).andExpect(status().isOk())
.andDo(document("hello 接口",//这个identity不同的单测需要不同,否则其他的测试会覆盖现有的,最后文档里只生成一个接口说明
requestHeaders(
headerWithName("Authorization").description(
"Basic auth credentials")),
requestParameters(
parameterWithName("page").description("The page to retrieve"),
parameterWithName("per_page").description("Entries per page")
)));
}
3、编写adoc配置文件
在maven项目标准结构下,src/main下新建asciidoc目录,并建一个.adoc为结尾的文件(到时候打包时,会根据asciidoc目录下的所有.adoc文件生成过个对应文件名的html文档)。例子如下:
== hello 接口
.http-request
include::D:\ideaworkspace\restdoc\target\generated-snippets\hello 接口\http-request.adoc[]
.request-headers 请求头说明
include::D:\ideaworkspace\restdoc\target\generated-snippets\hello 接口\request-headers.adoc[]
.request-parameters 请求参数说明
include::D:\ideaworkspace\restdoc\target\generated-snippets\hello 接口\request-parameters.adoc[]
.http-response
include::D:\ideaworkspace\restdoc\target\generated-snippets\hello 接口\http-response.adoc[]
== hello2 接口
.http-request
include::D:\ideaworkspace\restdoc\target\generated-snippets\hello2 接口\http-request.adoc[]
.http-response
include::D:\ideaworkspace\restdoc\target\generated-snippets\hello2 接口\http-response.adoc[]
4、ok,最后用maven打包项目,跑完之后,就可以在target/generated-docs下看到你的文件了,直接双击打开,就能看到生成的文档。
以上是根据官网文档,就可以导出一个接口文档。但是,并没有左边栏的目录,而且写一个单测就要在.adoc文件里添加include关键字导入新生成的接口内容很麻烦,怎么办呢?
首先,左边栏目录或右边栏目录,或直接在文档最开头添加目录我们只需要在.adoc文件开头添加如下内容:
= 接口文档
v1.0, 2017-09-22
:toc: left
它会自动根据你文件下发的接口配置来定义目录,前面第3点列出的那个配置红色部分就是接口的引用配置。是不是很简单,配置完之后,就能生成和我文档最开头那张图片的样子了。
然后解决每写一个接口测试就要在.adoc文件里添加include的问题:
我们编写.adoc文件生成功能,方法如下(参考了:点击打开链接):
@Test
public void adocBuild() throws IOException {
String appDir = System.getProperty("user.dir");
String adocPath = appDir + "\\src\\main\\asciidoc\\hello.adoc";
StringBuilder content = new StringBuilder();
content.append("include::" + appDir + "\\src\\main\\asciidoc\\preview.adoc[]").append(System.getProperty("line.separator")).append(System.getProperty("line.separator"));
File apidirs = new File(appDir + "\\target\\generated-snippets");
for (File apidir : apidirs.listFiles()) {
String apiName = apidir.getName();
content.append("== " + apiName + System.getProperty("line.separator"));
fileAppend(content, apidir + "\\http-request.adoc", ".http-request");
fileAppend(content, apidir + "\\request-headers.adoc", ".request-headers 请求头说明");
fileAppend(content, apidir + "\\request-parameters.adoc", ".request-parameters 请求参数说明");
fileAppend(content, apidir + "\\request-body.adoc", ".request-body 请求体说明");
fileAppend(content, apidir + "\\http-response.adoc", ".http-response");
fileAppend(content, apidir + "\\response-fields.adoc", ".response-fields 返回值说明");
content.append(System.getProperty("line.separator"));
}
// System.out.println(adocPath);
// System.out.println(content);
File file = new File(adocPath);
writeStringToFile(file, content.toString(), "UTF-8");
}
private void writeStringToFile(File file, String content, String character) throws IOException {
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter osw = new OutputStreamWriter(fos, character);
osw.write(content);
osw.flush();
}
private void fileAppend(StringBuilder content, String include, String title) {
File file = new File(include);
if (file.exists()) {
content.append(title).append(System.getProperty("line.separator"));
content.append("include::").append(include).append("[]").append(System.getProperty("line.separator"));
}
}
很简单,也就是编写方法,创建文件,写入内容。
对啦,告诉你们我是怎么知道加那个目录的,当然是看asciidoctor的语法文档啦,在这里:点击打开链接
嗯,项目源码在此:拿去参考吧,直接就能运行:点击打开链接