资讯专栏INFORMATION COLUMN

Spring Boot [如何优雅的编写文档]

曹金海 / 1229人阅读

摘要:导读在团队协作的时候许多时候需要用到接口文档,我们通常通过手工编写大量重复格式的文档,让我想起了程序员最讨厌的两件事没有文档,编写文档。对应的资料可自行谷歌。关于和官网是这样描述的。我们可以理解为为基于构建的自动生成文档。

导读:

在团队协作的时候许多时候需要用到接口文档,我们通常通过手工编写大量重复格式的文档,让我想起了程序员最讨厌的两件事:没有文档,编写文档。哈哈,如果使用过swagger的朋友应该都很了解它带给我们的便利,如果你还没有使用swagger的话,正好打算编写RESTful API文档,这里有一篇文章Spring Boot中使用Swagger2构建强大的RESTful API文档可以帮助你在较短的时间内构建出一个线上文档,有些时候我们需要生成离线文档有该怎么做呢?带着这个问题我们一起去出发。

关于swagger:

Swagger - 前后端分离后的契约

通过Swagger进行API设计,与Tony Tam的一次对话

一个简短的总结,更好的生成RESTful API文档,提供相应的测试功能,效果图如下:

编写离线文档:

swagger为我们提供了生成在线文档的功能,然而有些时候客户需要的是离线文档的api,有没有什么较好的办法可以通过swagger帮助我们生成离线文档呢?

这就是今天的主角:Springfox和Spring Rest Docs帮我们做的事情
1.预备知识:
建议了解swagger、Asciidoc、asciidoctor-maven-plugin和SpringBoot Testing。对应的资料可自行谷歌。
2.关于Springfox和Spring Rest Docs:
官网是这样描述的Springfox:Automated JSON API documentation for API"s built with Spring。我们可以理解为为 基于Spring构建的API自动生成文档。

引入pom依赖:

其实我们的思路就是把swagger在线文档转成staticdocs形式的文档,引入相关的一些依赖 Spring Rest Docs的依赖spring-restdocs-mockmvc,离线文档的依赖springfox-staticdocs,因为要在单元测试的时候生成文档,所以再加测试相关的spring-boot-starter-test。


    org.springframework.boot
    spring-boot-starter-data-jpa



    com.h2database
    h2
    runtime


    org.springframework.boot
    spring-boot-starter-web


    org.springframework.boot
    spring-boot-starter-test


    io.springfox
    springfox-swagger2
    2.6.1


    io.springfox
    springfox-swagger-ui
    2.6.1


    org.springframework.restdocs
    spring-restdocs-mockmvc
    1.1.2.RELEASE
    test


    io.springfox
    springfox-staticdocs
    2.6.1


    com.alibaba
    fastjson
    1.2.8
使用Maven插件:

我们使用asciidoctor-maven-plugin插件将Asciidoc格式转成HTML5格式
了解更多: 使用介绍

 
    org.asciidoctor
    asciidoctor-maven-plugin
    
        
        
        ${asciidoctor.html.output.directory}
        index.adoc
        
            book
            left
            3
            ${generated.asciidoc.directory}
        
    
    
        
            output-html
            test
            
                process-asciidoc
            
            
                html
                
                    ${project.build.directory}/generated-snippets
                
            
        
    

编写测试类生成离线文档:
import cn.sunxyz.domain.UserInfo;
import com.alibaba.fastjson.JSON;
import io.github.robwin.markup.builder.MarkupLanguage;
import io.github.robwin.swagger2markup.GroupBy;
import io.github.robwin.swagger2markup.Swagger2MarkupConverter;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
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.http.MediaType;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import springfox.documentation.staticdocs.SwaggerResultHandler;

import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@AutoConfigureMockMvc
@AutoConfigureRestDocs(outputDir = "target/generated-snippets")
@RunWith(SpringRunner.class)
@SpringBootTest
public class DocumentationBuild {

    private String snippetDir = "target/asciidoc/generated-snippets";
    private String outputDir = "target/asciidoc";

    @Autowired
    private MockMvc mockMvc;

    @After
    public void Test() throws Exception {
        // 得到swagger.json,写入outputDir目录中
        mockMvc.perform(get("/v2/api-docs").accept(MediaType.APPLICATION_JSON))
                .andDo(SwaggerResultHandler.outputDirectory(outputDir).build())
                .andExpect(status().isOk())
                .andReturn();

        // 读取上一步生成的swagger.json转成asciiDoc,写入到outputDir
        // 这个outputDir必须和插件里面标签配置一致
        Swagger2MarkupConverter.from(outputDir + "/swagger.json")
                .withPathsGroupedBy(GroupBy.TAGS)// 按tag排序
                .withMarkupLanguage(MarkupLanguage.ASCIIDOC)// 格式
                .withExamples(snippetDir)
                .build()
                .intoFolder(outputDir);// 输出
    }

    @Test
    public void TestApi() throws Exception {
        mockMvc.perform(get("/api/user/1")
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andDo(MockMvcRestDocumentation.document("查询用户", preprocessResponse(prettyPrint())));

        UserInfo userInfo = new UserInfo();
        userInfo.setName("lisi");
        userInfo.setAge(23);
        userInfo.setAddress("山东济南");
        userInfo.setSex("男");

        mockMvc.perform(post("/api/user").contentType(MediaType.APPLICATION_JSON)
                .content(JSON.toJSONString(userInfo))
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().is2xxSuccessful())
                .andDo(MockMvcRestDocumentation.document("新增用户", preprocessResponse(prettyPrint())));
    }


}

由于前面已经配置了maven的插件,只需要执行测试就可以生成相应的文档, 效果图如下:

补充:

Swagger配置:

@Configuration
@EnableSwagger2
public class SwaggerConfiguration {

    @Bean
    public Docket configSpringfoxDocket_all(ApiInfo apiInfo) {
        return new Docket(DocumentationType.SWAGGER_2)
                .produces(Sets.newHashSet("application/json"))
                .consumes(Sets.newHashSet("application/json"))
                .protocols(Sets.newHashSet("http", "https"))
                .apiInfo(apiInfo)
                .forCodeGeneration(true)
                .select().paths(regex("/api.*"))
                .build();
    }

    @Bean
    public Docket createUserInfoRestApi(ApiInfo apiInfo) {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("user")
                .produces(Sets.newHashSet("application/json"))
                .consumes(Sets.newHashSet("application/json"))
                .protocols(Sets.newHashSet("http", "https"))
                .apiInfo(apiInfo)
                .select()
                .apis(RequestHandlerSelectors.basePackage("cn.sunxyz.controller"))
                .paths(regex("/api/user.*"))
                .build();
    }

    @Bean
    public ApiInfo apiInfo() {
        return new ApiInfoBuilder().title("Springfox REST API")
                .description("Descriptions.")
                .termsOfServiceUrl("http://springfox.io")
                .license("Apache License Version 2.0")
                .licenseUrl("https://github.com/springfox/springfox/blob/master/LICENSE")
                .version("2.0")
                .build();
    }

}

相关源码已托管github

参考资料:

Spring REST Docs

SpringBoot项目生成RESTfull API的文档

Introduction to Spring REST Docs

asciidoctor-maven-plugin

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70000.html

相关文章

  • Spring Boot 中 crud如何优雅实现-附代码

    摘要:以下内容基于如果你使用的也是相同的技术栈可以继续往下阅读,如果不是可以当作参考。编写的四种方式裸写最简单最粗暴也是使用最多的一种方式,在写的多了之后可以用生成工具生成。 导读 在目前接触过的项目中大多数的项目都会涉及到: crud相关的操作, 哪如何优雅的编写crud操作呢?带着这个问题,我们发现项目中大量的操作多是 创建实体 、删除实例、 修改实体、 查询单个实体、 分页查询多个实体...

    wing324 评论0 收藏0
  • 如何优雅关闭 Spring Boot 应用

    摘要:除了,还有十余种,有的是特定操作,比如转储内存日志有的是信息展示,比如显示应用健康状态。 showImg(http://ww1.sinaimg.cn/large/006tNc79gy1g5qb2coyfoj30u00k0tan.jpg); 前言 随着线上应用逐步采用 SpringBoot 构建,SpringBoot应用实例越来多,当线上某个应用需要升级部署时,常常简单粗暴地使用 kil...

    xiyang 评论0 收藏0
  • Spring Boot 参考指南(开发你第一个Spring Boot应用程序)

    摘要:开发你的第一个应用程序本节描述如何开发一个简单的应用程序来突出了的一些关键特性,我们使用来构建这个项目,因为大多数都支持它。如果你希望分发一个自包含的应用程序,这可能会有问题。 11. 开发你的第一个Spring Boot应用程序 本节描述如何开发一个简单的Hello World! web应用程序来突出了Spring Boot的一些关键特性,我们使用Maven来构建这个项目,因为大多数...

    Cristalven 评论0 收藏0
  • @ConfigurationProperties 注解使用姿势,这一篇就够了

    摘要:在项目中,为满足以上要求,我们将大量的参数配置在或文件中,通过注解,我们可以方便的获取这些参数值使用配置模块假设我们正在搭建一个发送邮件的模块。这使得在不影响其他模块的情况下重构一个模块中的属性变得容易。 在编写项目代码时,我们要求更灵活的配置,更好的模块化整合。在 Spring Boot 项目中,为满足以上要求,我们将大量的参数配置在 application.properties 或...

    SolomonXie 评论0 收藏0
  • @ConfigurationProperties 注解使用姿势,这一篇就够了

    摘要:在项目中,为满足以上要求,我们将大量的参数配置在或文件中,通过注解,我们可以方便的获取这些参数值使用配置模块假设我们正在搭建一个发送邮件的模块。这使得在不影响其他模块的情况下重构一个模块中的属性变得容易。 在编写项目代码时,我们要求更灵活的配置,更好的模块化整合。在 Spring Boot 项目中,为满足以上要求,我们将大量的参数配置在 application.properties 或...

    KoreyLee 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<