霸王餐API文档自动化:Spring REST Docs与Asciidoctor多模块聚合
项目结构与目标
"吃喝不愁"App后端采用多模块Maven工程,包含 order-service、user-service、coupon-service 等。每个模块独立提供REST API,需统一生成一份完整、可部署的HTML API文档。目标:
- 测试即文档,杜绝接口与文档不一致;
- 支持多模块测试结果聚合;
- 输出结构化、带示例请求/响应的静态文档。
技术栈:Spring REST Docs + Asciidoctor + Maven插件聚合。

子模块配置(以coupon-service为例)
在 juwatech.cn.coupon 模块中引入依赖:
xml
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-mockmvc</artifactId>
<scope>test</scope>
</dependency>
编写测试用例:
java
package juwatech.cn.coupon;
import org.junit.jupiter.api.BeforeEach;
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.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
import org.springframework.restdocs.payload.JsonFieldType;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.payload.PayloadDocumentation.*;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureRestDocs(outputDir = "target/generated-snippets")
public class CouponApiDocumentation {
@Autowired
private MockMvc mockMvc;
@Test
public void getCouponDetail() throws Exception {
this.mockMvc.perform(get("/api/coupons/{couponId}", "cp_12345")
.header("X-User-ID", "u_789"))
.andExpect(status().isOk())
.andDo(MockMvcRestDocumentation.document("coupon-get-detail",
pathParameters(
parameterWithName("couponId").description("优惠券ID")
),
responseFields(
fieldWithPath("code").type(JsonFieldType.STRING).description("状态码"),
fieldWithPath("data.id").type(JsonFieldType.STRING).description("优惠券ID"),
fieldWithPath("data.title").type(JsonFieldType.STRING).description("标题"),
fieldWithPath("data.validUntil").type(JsonFieldType.STRING).description("有效期至 (ISO8601)")
)
));
}
}
执行 mvn test 后,生成 target/generated-snippets/coupon-get-detail/ 目录,含 http-request.adoc、path-parameters.adoc 等片段。
子模块Asciidoc源文件
在 src/main/asciidoc/coupon-api.adoc 中引用片段:
asciidoc
[[coupon-api]]
== 优惠券接口
=== 获取优惠券详情
include::{snippets}/coupon-get-detail/http-request.adoc[]
include::{snippets}/coupon-get-detail/path-parameters.adoc[]
include::{snippets}/coupon-get-detail/response-fields.adoc[]
include::{snippets}/coupon-get-detail/http-response.adoc[]
聚合模块:docs-aggregator
新建独立Maven模块 docs-aggregator,负责收集所有子模块的snippets和adoc源文件。
pom.xml 配置:
xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack-snippets</id>
<phase>generate-resources</phase>
<goals><goal>unpack</goal></goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>juwatech.cn</groupId>
<artifactId>coupon-service</artifactId>
<version>${project.version}</version>
<type>jar</type>
<includes>**/generated-snippets/**</includes>
<outputDirectory>${project.build.directory}/snippets</outputDirectory>
</artifactItem>
<artifactItem>
<groupId>juwatech.cn</groupId>
<artifactId>order-service</artifactId>
<version>${project.version}</version>
<type>jar</type>
<includes>**/generated-snippets/**</includes>
<outputDirectory>${project.build.directory}/snippets</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
<execution>
<id>unpack-asciidoc</id>
<phase>generate-resources</phase>
<goals><goal>unpack</goal></goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>juwatech.cn</groupId>
<artifactId>coupon-service</artifactId>
<version>${project.version}</version>
<type>jar</type>
<includes>**/*.adoc</includes>
<outputDirectory>${project.build.directory}/asciidoc</outputDirectory>
</artifactItem>
<!-- order-service 同理 -->
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>2.2.4</version>
<executions>
<execution>
<id>generate-docs</id>
<phase>prepare-package</phase>
<goals><goal>process-asciidoc</goal></goals>
<configuration>
<sourceDocumentName>index.adoc</sourceDocumentName>
<backend>html5</backend>
<attributes>
<snippets>${project.build.directory}/snippets</snippets>
</attributes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
主文档 index.adoc
在 docs-aggregator/src/main/asciidoc/index.adoc 中聚合各模块:
asciidoc
= 吃喝不愁霸王餐API文档
:doctype: book
:icons: font
:source-highlighter: highlightjs
:toc: left
include::{projectdir}/target/asciidoc/coupon-api.adoc[]
include::{projectdir}/target/asciidoc/order-api.adoc[]
构建与输出
执行:
bash
mvn clean install -pl coupon-service,order-service
mvn package -pl docs-aggregator
最终生成 docs-aggregator/target/generated-docs/index.html,包含所有服务的完整API文档,支持直接部署至Nginx或对象存储。
注意事项
-
子模块需将
src/main/asciidoc打包进JAR:xml<resources> <resource> <directory>src/main/asciidoc</directory> </resource> </resources> -
测试类必须使用
@AutoConfigureRestDocs并指定outputDir; -
字段描述需精确,避免模糊用语如"相关信息"。
本文著作权归吃喝不愁app开发者团队,转载请注明出处!