大致流程:
-
使用spring-rest-doc结合test编写测试用例,可以是继承测试,也可以是只针对controller层。
-
运行test,即可生成对应的描述文档(Snippets)
-
手动编写adoc文件,将生成的snippets文档进行汇总(include)、排版
-
通过asccidocter-maven-plugin将手动编写的文档进行渲染,html等。(也可使用idea 插件生成html)
注意:图片和引用文件的位置一定要正确设置,不然渲染不出内容。
1. 新建springboot项目
推荐使用spring 提供的 生成器,可以避免很多坑,把需要的依赖及版本都配置好了,效果如下图。

2. 准备工作
需求: 一个用户注册接口,包含昵称、账号以及密码,简单即可。
实现: 这里只做controller,模拟返回成功,service以及数据库就忽略。
编辑器: IntelliJ IDEA 2021.1.2 (Community Edition)
JDK: 1.8
OS: windows 10
lombok: 一个插件,可以通过注解生成getter、setter等,不需要深入研究。
3. src/main/java
新建一个UserController、UserVO、UserService,如下:

UerVO: 用户注册参数
package com.wanghengzhi.learn.springrestdoc.module.user.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 用户注册参数
*
* @author wanghengzhi
* @since 2021/8/7 8:55
*/
package com.wanghengzhi.learn.springrestdoc.module.user.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 用户注册参数
*
* @author wanghengzhi
* @since 2021/8/7 8:55
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserVO {
/**
* 昵称
*/
private String nickName;
/**
* 账号
*/
private String account;
/**
* 密码
*/
private String password;
}
UserController:加入一个注册接口
package com.wanghengzhi.learn.springrestdoc.module.user;
import com.wanghengzhi.learn.springrestdoc.module.user.vo.UserVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
/**
* 用户操作接口
*
* @author wanghengzhi
* @since 2021/8/7 8:54
*/
@RestController
@SuppressWarnings("unused")
public class UserController {
public static final String URL_USER_REGISTER = "/user/register";
@Autowired
private UserService userService;
/**
* 用户注册接口
* @param userVO 用户输入参数
* @return 注册结果
*/
@PostMapping(URL_USER_REGISTER)
public ResponseEntity<Object> register(@RequestBody UserVO userVO) {
// 调用 service 进行保存
userService.register(userVO);
return new ResponseEntity<>(HttpStatus.OK);
}
}
UserService: 业务处理类,此例中不需要实现。
package com.wanghengzhi.learn.springrestdoc.module.user;
import com.wanghengzhi.learn.springrestdoc.module.user.vo.UserVO;
import org.springframework.stereotype.Service;
/**
* 用户操作 service 层
*
* @author wanghengzhi
* @since 2021/8/7 9:01
*/
@Service
public class UserService {
@SuppressWarnings("unused")
public void register(UserVO userVO) {
// 省略业务逻辑。
}
}
4. src/main/test

只需要新增一个`UserControllerTest`
4.1 配置 Spring Rest Doc 输出以及处理方式
MyRestDocsConfiguration
:
这里配置文档格式化输出,其他配置,可自行研究。
package com.wanghengzhi.tdd.config;
import org.springframework.boot.test.autoconfigure.restdocs.RestDocsMockMvcConfigurationCustomizer;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer;
import org.springframework.boot.test.context.TestConfiguration;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
/**
* 配置 spring rest doc
* @author wanghengzhi
* @since 2021/8/6 23:02
*/
@TestConfiguration(proxyBeanMethods = false)
public class MyRestDocsConfiguration implements RestDocsMockMvcConfigurationCustomizer {
@Override
public void customize(MockMvcRestDocumentationConfigurer configurer) {
configurer.operationPreprocessors().withRequestDefaults(prettyPrint()).withResponseDefaults(prettyPrint());
}
}
MyResultHandlerConfiguration
: 配置了生成的文件名格式。
package com.wanghengzhi.learn.springrestdoc.config;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler;
/**
* 配置文档处理
* @author wanghengzhi
* @since 2021/8/6 23:03
*/
@TestConfiguration(proxyBeanMethods = false)
public class MyResultHandlerConfiguration {
@Bean
public RestDocumentationResultHandler restDocumentation() {
return MockMvcRestDocumentation.document("{class_name}/{method_name}");
}
}
4.2 编写测试,并生成文档
package com.wanghengzhi.learn.springrestdoc.module.user;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wanghengzhi.learn.springrestdoc.config.MyRestDocsConfiguration;
import com.wanghengzhi.learn.springrestdoc.config.MyResultHandlerConfiguration;
import com.wanghengzhi.learn.springrestdoc.module.user.vo.UserVO;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.restdocs.headers.HeaderDocumentation;
import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler;
import org.springframework.restdocs.payload.JsonFieldType;
import org.springframework.restdocs.payload.PayloadDocumentation;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import static org.junit.jupiter.api.Assertions.*;
/**
* 测试
*
* Annotation {@code @WebMvcTest} :
* 只测是Controller层代码,service层依赖需要使用{@code @MockBean}注入。
* Annotation {@code @AutoConfigureRestDocs}:
* 这里配置了生成snippets位置,默认放在target目录下,由于每次clean会删除。
* 手动编写的*。adoc文档会找不到,会报错。如果多人开发,别人拉取代码,如果不运行test,编辑器会提示错误。
* Annotation {@code @Import}:
* 手动导入自定义的配置文件。包含文档生成规则配置,以及生成一个handler来处理文档。
*
* @author wanghengzhi
* @since 2021.8.7
*/
@WebMvcTest(UserController.class)
@AutoConfigureRestDocs(outputDir = "src/main/asciidoc/snippets")
@Import({MyRestDocsConfiguration.class, MyResultHandlerConfiguration.class})
class UserControllerTest {
@Autowired
private ObjectMapper objectMapper;
@MockBean
private UserService userService;
@Autowired
private MockMvc mockMvc;
/**
* 统一使用这个handler生成文档。
*/
@Autowired
private RestDocumentationResultHandler resultHandler;
@Test
void register() throws Exception {
UserVO userVO = new UserVO();
userVO.setAccount("my_account");
userVO.setNickName("my_nickName");
userVO.setPassword("my_password");
String token = "My Header";
MockHttpServletRequestBuilder request = MockMvcRequestBuilders.post(UserController.URL_USER_REGISTER)
.accept(MediaType.APPLICATION_JSON)
.header(token, "My_Header_value")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(userVO));
ResultActions perform = mockMvc.perform(request);
perform.andReturn().getResponse().setCharacterEncoding("utf-8");
perform.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print())
.andDo(resultHandler.document(
HeaderDocumentation.requestHeaders(
HeaderDocumentation.headerWithName(token).description("自定义header").optional()
),
PayloadDocumentation.requestFields(
PayloadDocumentation.fieldWithPath("nickName").type(JsonFieldType.STRING).description("用户昵称"),
PayloadDocumentation.fieldWithPath("account").type(JsonFieldType.STRING).description("用户账号"),
PayloadDocumentation.fieldWithPath("password").type(JsonFieldType.STRING).description("密码")
),
PayloadDocumentation.responseFields(
PayloadDocumentation.fieldWithPath("ok").type(JsonFieldType.BOOLEAN).description("是否成功"),
PayloadDocumentation.fieldWithPath("message").type(JsonFieldType.STRING).description("信息")
)));
}
}
5. 运行测试,并生成结果

红箭头标识的是,是测试类手动定义生成的,其他都是默认生成的文件。
6 编写测试文档adoc,并生成对应的html文件
-
新建 index.adoc,使用 ascciidoctor语法。
-
根据需求格式进行排版,生成的snippets文件引用。
-
IDea有插件可以进行预览,也可以生成html

6. 补充说明
可以通过配置asciidoc-plugin,在指定maven目标中可以生成html。
备注: 1. <version>1.5.8</version>
: 可以根据喜好选择版本。 2.
<executions>...</executions>
: 执行配置,
可多个,用于不同条件下的执行内容。 3. <execution>...</execution>
:
具体执行某个行为 4. <id>generate-docs</id>
:唯一即可,可自由命名 5.
<phase>prepare-package</phase>
:前置条件:在maven package前执行 6.
<goal>process-asciidoc</goal>
:
目的,可设置多个,这里执行process-asciidoc(处理.adoc文件为html5)。这是asciidoc插件的命令。见下图。

7. 附表
document:
关键字 | 作用 | 类名 |
---|---|---|
HeaderDocumentation |
记录header中的参数 |
org.springframework.restdocs.headers.HeaderDocumentation |
PayloadDocumentation |
记录body中的参数 |
org.springframework.restdocs.payload.PayloadDocumentation |
RequestDocumentation |
org.springframework.restdocs.request.RequestDocumentation |