团队开发中,文档尤其重要。文档的存大,大幅的下降了团队间的无效沟通时间,使得每位成员便可以按本身的计划开始工做,又能够快速的获取到其它队员的支持。html
优秀的程序员从善于读文档开始,优秀的工程师从善于写文档开始。
在先后台的开发中,接口是使先后台进行关联的关键一环,接口是否合理,清晰直接影响到团队开发的效率和团队间配置的心情(程序员每每都是自恋的坏脾气)。而是否可以提供随时更新的阅读性强的文档,则是先后台开发中的重要一环。java
本文由0开始,记录一次在实际项目中使用Spring REST Docs + travis + github
自动生成API接口的实际操做过程。git
本文环境:java:1.8
+ maven:3.3
+ spring-boot:2.0.3
程序员
咱们一直坚信,官方的原文文档确定是最好的。第一步,咱们来到了spring rest docs
的官方文档,并参考其作如下操做:github
找到pom.xml
加入如下依赖。IDEA会自动为咱们导入依赖的包,其它的IDE,可能须要手动导入。web
<dependency> <groupId>org.springframework.restdocs</groupId> <artifactId>spring-restdocs-mockmvc</artifactId> <version>2.0.1.RELEASE</version> <scope>test</scope> </dependency> <build> <plugins> <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>2.0.1.RELEASE</version> </dependency> </dependencies> </plugin> </plugins> </build>
注意: dependency
须要加入到dependencies
中。若是你的pom.xml
有了build
-> plugins
,则只须要复制plugin
的部分到plugins
中。spring
如下代码的做用以下:json
4.Add spring-restdocs-asciidoctor as a dependency of the Asciidoctor plugin. This will automatically configure the snippets attribute for use in your .adoc files to point to target/generated-snippets. It will also allow you to use the operation block macro.mvc
胡乱翻译以下:app
可能会遇到的小坑:
- 粘贴上述代码时,位置错了。此时,须要按前面给的注意检查,是否出现了嵌套错误。
- 提示
spring-restdocs-asciidoctor:2.0.1.RELEASE
未找到,这是因为咱们本机的maven
库的索引太旧引发来。查看官网咱们得知,这个包的引入时间是Apr 4, 2018
。此时,须要咱们从新下载maven
的目录。即update maven indices
咱们在测试控制器时,会使用MockMVC
来进行模拟数据的发送,这个模拟数据正好成为了咱们须要展示在API接口部分的样例。
这样作的好处很明显:
好比,我如今有个测试的控制器是: DanWeiControllerTest
(历史缘由,请忽略命名)。为了能够统一地对全部的控制器测试进行自动文档的设置,咱们在这再新建一个抽像类ControllerTest
,并使用DanWeiControllerTest
来继续ControllerTest
。
ControllerTest
package com.mengyunzhi.check_apply_online.controller; import org.junit.Before; import org.junit.Rule; 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.restdocs.JUnitRestDocumentation; import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; import org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvcBuilder; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import javax.transaction.Transactional; /** * 单元测试基类 * @author panjie * www.mengyunzhi.com 河北工业大学梦云智开发团队 */ @SpringBootTest @RunWith(SpringRunner.class) @Transactional @AutoConfigureMockMvc public abstract class ControllerTest { protected MockMvc mockMvc; @Autowired protected WebApplicationContext context; @Rule public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation(); @Before public void setUp() { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) .apply(MockMvcRestDocumentation.documentationConfiguration(this.restDocumentation)) .build(); } }
DanWeiControllerTest
进行继承(未加入自动文档)
package com.mengyunzhi.check_apply_online.controller; import org.junit.Test; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; /** * 单位 * @author panjie * www.mengyunzhi.com 河北工业大学梦云智开发团队 */ public class DanWeiControllerTest extends ControllerTest{ @Test public void registerTest() throws Exception { String url = "/DanWei/register"; this.mockMvc.perform(MockMvcRequestBuilders .post(url) .contentType(MediaType.APPLICATION_JSON_UTF8) .content("{}")) .andExpect(MockMvcResultMatchers.status().isOk()); } }
加入自动生成文档代码后:
package com.mengyunzhi.check_apply_online.controller; import org.junit.Test; import org.springframework.http.MediaType; import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; /** * 单位测试 * @author panjie * www.mengyunzhi.com 河北工业大学梦云智开发团队 */ public class DanWeiControllerTest extends ControllerTest{ @Test public void registerTest() throws Exception { String url = "/DanWei/register"; this.mockMvc.perform(MockMvcRequestBuilders .post(url) .contentType(MediaType.APPLICATION_JSON_UTF8) .content("{}")) .andExpect(MockMvcResultMatchers.status().isOk()) .andDo(MockMvcRestDocumentation.document("DanWei_register")); } }
此时,咱们执行本单元测试时,将在target/generated-snippets
中生成以下6个以.adoc
结尾的文件:
这6个文件中,记录了不一样请求方法的请求/返回信息。
咱们的单元测试请求越多,生成这样的文件夹也就越多,下面,咱们共同将这些文件进行格式化,并拼接到一个html文件中。
在src/main/asciidoc/
建立一个任意名称的.adoc
文件,好比,咱们index.adoc
。而后,使用.adoc
的include
语法,将上图中生成的几个测试代码片断包含进来。
src/main/asciidoc/index.adoc
include::{snippets}/DanWei_register/http-request.adoc[] include::{snippets}/DanWei_register/request-body.adoc[] include::{snippets}/DanWei_register/http-response.adoc[] include::{snippets}/DanWei_register/response-body.adoc[]
当咱们进行package
时,就会在target
文件夹中生成generated-docs/index.html
,点击便可查看生成的文档信息。
mvn package
查看html
以下:
至此,咱们便成功的使用spring rest docs
生成了html
的API接口文档。除了基本的功能之外,咱们还能够对传入的字段添加说明等。具体的细节,若是有需求,能够查看Spring
的官方文档。
咱们按照Spring
的官方文档进行了相应的配置;接着在单位测试时,加入了指定生成文档的目录代码,并成功的生成测试的代码片断;而后使用AsciiDoc
语法,在index.adoc
文件中,对测试代码片断进行了拼接;最后,使用mvn package
在进行项目打包的同时,生成了咱们想的html
文件。
不足
但咱们仍然感受这并不够智能化,咱们在生成代码片断后,还须要手动的加入对代码版本的引入;虽然有了代码片断,但对片断中的请求json
数据的解释并不轻松(要参考官方文档),最主要的是,在C层,咱们进行接收时,要么是通常的参数,要么是后台的实体。咱们更但愿可以对参数和实体进行更改时,测试的说明也可以同时更改。
那么如何可以自动的实现代码片断的合并,而且按照参数和实体信息自动生成与后台代码高度吻合的API说明呢?
咱们将在下节中,给出阐述。