spring rest docs创建api文档介绍

  • Post author:
  • Post category:其他


日常开发中可能很少会用到

spring rest docs

来创建API文档,因为spring boot容易集成的原因,大家可能还是比较倾向于使用swaggerUI文档框架了,spring rest docs有一个好处是需要写单元测试(这个是很多开发人员不愿意的,包括我 -_-),还有个人觉得从界面和展示效果,我还是比较喜欢spring rest docs。在开发中接口文档是必不可少的,至于选择哪一种,就自由选择了。

下面只要是以一个简单的例子来介绍怎么样去使用spring rest docs来生成文档的。

第一步先保证这些依赖引入,至于可以结合spring boot里面是starter来引入,如1.5.12.RELEASE

   <properties>
        <!--spring restdocs-->
        <spring-restdocs.version>1.2.4.RELEASE</spring-restdocs.version>
        <!--asciidoctor-->
        <asciidoctor-maven-plugin.version>1.5.6</asciidoctor-maven-plugin.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
 
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
 
        <dependency>
            <groupId>org.springframework.restdocs</groupId>
            <artifactId>spring-restdocs-mockmvc</artifactId>
            <version>1.2.4.RELEASE</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.asciidoctor</groupId>
                <artifactId>asciidoctor-maven-plugin</artifactId>
                <version>${asciidoctor-maven-plugin.version}</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>${spring-restdocs.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <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>
   </build>

建一个单元测试类:


import com.google.common.collect.ImmutableMap;
import com.xxx.service.customerservice.CustomerServiceTaskService;
import com.xxx..test.common.BaseTest;
import com.xxx.test.common.Constants;
import org.junit.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.restdocs.payload.JsonFieldType;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
import static org.springframework.restdocs.payload.PayloadDocumentation.*;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;

/**
 * @Date 2019-07-08
 */
public class ControllerTest extends BaseTest {

    @MockBean
    private CustomerServiceTaskService customerServiceTaskService;

    @Test
    public void listAvailableLists() throws Exception {
        List<Map<String, Object>> campaigns = new ArrayList<>();
        Map<String, Object> campaign = new HashMap<>();
        campaign.put("campaignId", 1);
        campaign.put("campaignName", "活动名称");
        campaign.put("remark", "备注信息");
        campaigns.add(campaign);

        when(this.customerServiceTaskService.listCampaigns(Constants.DEFAULT_V))
                .thenReturn(campaigns);

        assertGet("/xxxx/xx/listAvailableLists",
                ImmutableMap.of("vin", Constants.DEFAULT_V),
                document("v2-listAvailableLists",
                        preprocessResponse(prettyPrint()),
                        responseFields(
                                fieldWithPath("code").description("业务码"),
                                fieldWithPath("msg").optional().type(JsonFieldType.STRING).description("业务描述"),
                                subsectionWithPath("data").description("数据")
                        ),
                        responseFields(beneathPath("data").withSubsectionId("data"),
                                fieldWithPath("[].campaignId").description("ID"),
                                fieldWithPath("[].campaignName").description("名称"),
                                fieldWithPath("[].remark").description("备注")
                        ),
                        requestParameters(
                                parameterWithName("key").description("参数")
                        )
                )
        );
    }
}

BaseTest.java

import com.xxx.server.boot.Application;
import com.xxx.test.AbstractMockTest;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
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.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;

/**
 * @author huangdi1309
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = {Application.class})
@AutoConfigureMockMvc
@AutoConfigureRestDocs("target/generated-snippets")
@Ignore
public class BaseTest extends AbstractMockTest {

    @Autowired
    private MockMvc mockMvc;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
    }

    @Override
    protected MockMvc getMockMvc() {
        return this.mockMvc;
    }
}

AbstractMockTest.java

  public void assertGet(String api, Map<String, Object> params, RestDocumentationResultHandler document) throws Exception {
        this.assertGet(api, params, (HttpHeaders)null, HttpStatus.OK.value(), document);
    }
 public void assertGet(String api, Map<String, Object> params, int status, RestDocumentationResultHandler document) throws Exception {
        this.assertGet(api, params, (HttpHeaders)null, status, document);
    }

    public void assertGet(String api, Map<String, Object> params, HttpHeaders headers, int status, RestDocumentationResultHandler document) throws Exception {
        MockHttpServletRequestBuilder builder = RestDocumentationRequestBuilders.get(api, new Object[0]);
        if (params != null) {
            builder.params(this.toMulti(params));
        }

        if (headers != null) {
            builder.headers(headers);
        }

        builder.contentType(MediaType.APPLICATION_JSON_UTF8).accept(new MediaType[]{MediaType.APPLICATION_JSON_UTF8});
        ResultActions actions = this.perform(builder);
        if (document != null) {
            actions.andDo(document);
        }

        actions.andExpect(MockMvcResultMatchers.status().is(status));
    }

在src/main/asciidoc目录下创建index.adoc 内容:

= Management API 文档
:doctype: book
:icons: font
:source-highlighter: highlightjs
:toc: left
:toclevels: 4
:sectlinks:
:numbered:


== API(v2版)
[[v2-listAvailableLists]]
=== 获取xxxxxx接口(/xxx/v2/xxx/listAvailableLists)

operation::v2-listAvailableLists[snippets='request-parameters,http-request,http-response,response-fields,response-fields-data']
[[v2-xxx-listFeedbacks]]

=== 获取事件接口(/xxx/v2/xxx/listFeedbacks)
operation::v2-xxx-listFeedbacks[snippets='request-parameters,http-request,http-response,response-fields,response-fields-data']

[[v2-xxx-listHis]]
=== 获取历史接口(/xxx/v2/xxx/listUpgradeHis)
operation::v2-xxx-listHis[snippets='request-parameters,http-request,http-response,response-fields,response-fields-data']

通过mvnw package命令(也可以通过idea的maven界面操作,我就是这样的)就可以生成文档了。

在这里插入图片描述

在这里插入图片描述

在/target/generated-docs下有个index.html,打开这个html,显示如下:

在这里插入图片描述



版权声明:本文为huangdi1309原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。