SpringBoot2基于Swagger2生成离线Api文档

通过swagger2与swagger-ui可以很方便的生成系统的在线api文档,这方面的博客网上有很多。
但是利用swagger生成离线api文档的博客就不多了。有的无法兼容springboot2,有的配置起来太麻烦,复用性与易用性较差。
为了能够方便的自动生成api离线文档,笔者花了些时间基于网上的博客做了修改,代码经过亲测可用于springboot2项目。


代码样例下载地址

Github: https://github.com/ChaselX/springboot-swagger2-offline-api-doc

Gitee: https://gitee.com/chasel96/springboot-swagger2-offline-api-doc


旧版与新版的区别

个人觉得旧版的配置简单许多,新版的配置按照官方demo的配置来做还是复杂了很多

重要提示1: 本文档有两种版本生成,上面的只能基于2.6.1以下的swagger版本使用,下面的可以用于2.6.1以上版本。笔者在官档上看到了使用最新的swagger来生成离线api文档的方法,并已经在代码样例中实现了。
重要提示2:在生成pdf离线文档时,因为adoc的字符编码问题,部分中文会消失,网上有现成的解决办法,但是由于解决的方式不够灵活,不在文档中展示。生成html离线文档不受影响。


使用2.6.1及以下版本生成Api文档

离线文档生成效果预览

SpringBoot2基于Swagger2生成离线Api文档_第1张图片
生成文档效果预览

最终目标

配置到Springboot项目中以后,在项目打包的时候便会通过单元测试在指定的目录生成被官方称为staticdocs的离线文档

从Maven配置开始

Maven依赖引入

该篇博文引用的依赖都要引入,Spring Rest Docs的依赖spring-restdocs-mockmvc,离线文档的依赖springfox-staticdocs,因为要在单元测试的时候生成文档,所以需要再加测试相关的spring-boot-starter-test。

注意:因为springfox-staticdocs在16年以后就没有发布新依赖包了,swagger2与swagger-ui的依赖包版本必须为2.6.1,否则会因为springfox-staticdocs的swagger-model与swagger2中的model不兼容导致错误。亲测踩坑填坑。


        UTF-8
        UTF-8
        1.8
        ${project.build.directory}/generated-snippets
    

    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            io.springfox
            springfox-swagger2
            2.6.1
        
        
            io.springfox
            springfox-swagger-ui
            2.6.1
        
        
        
            org.springframework.restdocs
            spring-restdocs-mockmvc
            2.0.2.RELEASE
            test
        
        
            io.springfox
            springfox-staticdocs
            2.6.1
            test
        

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

Maven插件

asciidoctor-maven-plugin插件会把Asciidoc格式文件转成HTML5格式输出。

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
            
                org.apache.maven.plugins
                maven-surefire-plugin
                
                    
                        **/*Documentation.java
                    
                
            
            
                org.asciidoctor
                asciidoctor-maven-plugin
                1.5.3
                
                    ${project.basedir}/docs/asciidoc
                    index.adoc
                    
                        book
                        left
                        3
                        
                        
                        
                        
                        ${project.build.directory}/asciidoc
                    
                
                
                
                    
                        output-html
                        test
                        
                            process-asciidoc
                        
                        
                            html5
                            
                        
                    
                
                
                
                    
                    
                        org.jruby
                        jruby-complete
                        1.7.26
                    
                
            
        
    

生成文档的单元测试代码编写

package com.chinamobile.cmic.apidoc;

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.Assert;
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.restdocs.mockmvc.RestDocumentationRequestBuilders;
import org.springframework.restdocs.operation.preprocess.Preprocessors;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.web.context.WebApplicationContext;
import springfox.documentation.staticdocs.SwaggerResultHandler;

/**
 * @author ChaselX
 * @date 2019/1/29 13:02
 */
@AutoConfigureMockMvc
@AutoConfigureRestDocs(outputDir = "target/generated-snippets")
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class Documentation {
    private String snippetDir = "target/generated-snippets";
    private String outputDir = "target/asciidoc";

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext webApplicationContext;

    @After
    public void test() throws Exception {
        // 得到swagger.json,写入outputDir目录中
        mockMvc.perform(RestDocumentationRequestBuilders.get("/v2/api-docs")
                .accept(MediaType.APPLICATION_JSON))
                .andDo(SwaggerResultHandler.outputDirectory(outputDir).build())
                .andExpect(MockMvcResultMatchers.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() {
        try {
            mockMvc.perform(RestDocumentationRequestBuilders.get("/greeting")
                    .accept(MediaType.APPLICATION_JSON))
                    .andExpect(MockMvcResultMatchers.status().isOk())
                    .andDo(MockMvcRestDocumentation.document("greeting",
                            Preprocessors.preprocessResponse(Preprocessors.prettyPrint())))
                    .andReturn();
        } catch (Exception e) {
            e.printStackTrace();
            Assert.fail();
        }
    }
}

这个类包含两个方法,TestApi()是用来生成例子,test()用来生成Asciidoc的文档。生成例子用到了spring-restdocs-mockmvc,每一个API都要进行单元测试才能生成相应的文档片段(snippets),生成的结果如图:

SpringBoot2基于Swagger2生成离线Api文档_第2张图片
Api用例片段

生成完整的Asciidoc文档用到了Swagger2MarkupConverter,第一步先获取在线版本的文档并保存到文件swagger.json中,第二步把swagger.json和之前的例子snippets整合并保存为Asciidoc格式的完整文档。生成结果如图:

SpringBoot2基于Swagger2生成离线Api文档_第3张图片
Asciidoc格式的文档

Swagger配置类

通过配置类定义一些文档相关的信息

package com.chinamobile.cmic.apidoc.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * @author ChaselX
 * @date 2019/1/30 11:22
 */
@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.chinamobile.cmic.apidoc"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder().title("API Document")
                .description("API Document for Spring Boot 2 Project")
                .contact(new Contact("ChaselX", "", ""))
                .version("1.0")
                .build();
    }
}

index.adoc

路径:项目名/docs/asciidoc/index.adoc

include::{generated}/overview.adoc[]
include::{generated}/definitions.adoc[]
include::{generated}/paths.adoc[]

生成HTML5的文档

利用前面配置的maven插件,只需要执行打包就可以生成相应的文档,如图:

SpringBoot2基于Swagger2生成离线Api文档_第4张图片
生成的HTML5文档

参考资料

  1. https://www.jianshu.com/p/af7a6f29bf4f
  2. https://blog.csdn.net/fly910905/article/details/79131755

使用2.6.1及以上版本生成Api文档

从Maven配置开始

Maven依赖引入

该篇博文引用的依赖都要引入,Spring Rest Docs的依赖spring-restdocs-mockmvc,离线文档的依赖springfox-staticdocs,因为要在单元测试的时候生成文档,所以需要再加测试相关的spring-boot-starter-test。

   
        UTF-8
        UTF-8
        1.8

        1.2.0
        ${project.basedir}/src/docs/asciidoc
        ${project.build.directory}/swagger
        ${project.build.directory}/asciidoc/snippets
        ${project.build.directory}/asciidoc/generated
        ${project.build.directory}/asciidoc/html
        ${project.build.directory}/asciidoc/pdf
        ${swagger.output.dir}/swagger.json
        2.9.2
    

    
        
            jcentral
            bintray
            http://jcenter.bintray.com
            
                false
            
        
        
            jcenter-snapshots
            jcenter
            http://oss.jfrog.org/artifactory/oss-snapshot-local/
        
    

    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            net.logstash.logback
            logstash-logback-encoder
            5.1
        
        
        
            io.springfox
            springfox-swagger2
            ${springfox.version}
        
        
            io.springfox
            springfox-swagger-ui
            ${springfox.version}
        
        
        
            org.springframework.restdocs
            spring-restdocs-mockmvc
            
        
        
            io.github.swagger2markup
            swagger2markup-spring-restdocs-ext
            ${swagger2markup.version}
            test
        
        
            io.springfox
            springfox-staticdocs
            2.6.1
            
        

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

Maven插件

asciidoctor-maven-plugin插件会把Asciidoc格式文件转成HTML5格式输出。

    
        
            jcenter-snapshots
            jcenter
            http://oss.jfrog.org/artifactory/oss-snapshot-local/
        
        
            jcenter-releases
            jcenter
            http://jcenter.bintray.com
            
                false
            
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
            
                org.apache.maven.plugins
                maven-compiler-plugin
                3.3
                
                    ${java.version}
                    ${java.version}
                    ${java.version}
                    UTF-8
                    
                    false
                
            

            
                org.apache.maven.plugins
                maven-surefire-plugin
                
                    
                        ${swagger.output.dir}
                        ${swagger.snippetOutput.dir}
                    
                
            

            
            
                io.github.swagger2markup
                swagger2markup-maven-plugin
                ${swagger2markup.version}
                
                    
                        io.github.swagger2markup
                        swagger2markup-import-files-ext
                        ${swagger2markup.version}
                    
                    
                        io.github.swagger2markup
                        swagger2markup-spring-restdocs-ext
                        ${swagger2markup.version}
                    
                
                
                    ${swagger.input}
                    ${generated.asciidoc.directory}
                    
                        ASCIIDOC
                        TAGS

                        ${project.basedir}/src/docs/asciidoc/extensions/overview
                        ${project.basedir}/src/docs/asciidoc/extensions/definitions
                        ${project.basedir}/src/docs/asciidoc/extensions/paths
                        ${project.basedir}src/docs/asciidoc/extensions/security/

                        ${swagger.snippetOutput.dir}
                        true
                    
                
                
                    
                        test
                        
                            convertSwagger2markup
                        
                    
                
            

            
            
                org.asciidoctor
                asciidoctor-maven-plugin
                1.5.6
                
                
                    
                        org.asciidoctor
                        asciidoctorj-pdf
                        1.5.0-alpha.16
                    
                    
                        org.jruby
                        jruby-complete
                        1.7.21
                    
                
                
                
                    ${asciidoctor.input.directory}
                    index.adoc
                    
                        book
                        left
                        3
                        
                        
                        
                        
                        ${generated.asciidoc.directory}
                    
                
                
                
                    
                        output-html
                        test
                        
                            process-asciidoc
                        
                        
                            html5
                            ${asciidoctor.html.output.directory}
                        
                    

                    
                        output-pdf
                        test
                        
                            process-asciidoc
                        
                        
                            pdf
                            ${asciidoctor.pdf.output.directory}
                        
                    

                
            

            
            
                org.apache.maven.plugins
                maven-jar-plugin
                3.1.0
                
                    
                        
                            true
                            lib/
                            
                            
                            
                            com.chinamobile.cmic.apidoc.ApiDocApplication
                        
                    
                
            

            
            
                maven-dependency-plugin
                
                    
                        package
                        
                            copy-dependencies
                        
                        
                            ${project.build.directory}/lib
                        
                    
                
            

            
            
                maven-resources-plugin
                3.1.0
                
                    
                        copy-resources
                        prepare-package
                        
                            copy-resources
                        
                        
                            ${project.build.outputDirectory}/static/docs
                            
                                
                                    ${asciidoctor.html.output.directory}
                                
                                
                                    ${asciidoctor.pdf.output.directory}
                                
                            
                        
                    
                
            
        
    

生成文档的单元测试代码编写

package com.chinamobile.cmic.apidoc;

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.mock.web.MockHttpServletResponse;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;

import java.io.BufferedWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

/**
 * @author ChaselX
 * @date 2019/1/29 13:02
 */
@WebAppConfiguration
@RunWith(SpringRunner.class)
@AutoConfigureRestDocs(outputDir = "build/asciidoc/snippets")
@SpringBootTest
@AutoConfigureMockMvc
public class Swagger2MarkupTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testApi() throws Exception {
        mockMvc.perform(get("/greeting")
                .accept(MediaType.APPLICATION_JSON))
                .andDo(document("greetingGet",
                        Preprocessors.preprocessResponse(Preprocessors.prettyPrint())))
                .andExpect(status().isOk());
    }

    @Test
    public void createSpringfoxSwaggerJson() throws Exception {

        String outputDir = System.getProperty("io.springfox.staticdocs.outputDir");
        MvcResult mvcResult = this.mockMvc.perform(get("/v2/api-docs")
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andReturn();

        MockHttpServletResponse response = mvcResult.getResponse();
        String swaggerJson = response.getContentAsString();
        Files.createDirectories(Paths.get(outputDir));
        try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(outputDir, "swagger.json"), StandardCharsets.UTF_8)) {
            writer.write(swaggerJson);
        }
    }
}

这个类包含两个方法,TestApi()是用来生成例子,createSpringfoxSwaggerJson()用来生成Asciidoc的文档。生成例子用到了spring-restdocs-mockmvc,每一个API都要进行单元测试才能生成相应的文档片段(snippets),生成的结果如图:

SpringBoot2基于Swagger2生成离线Api文档_第5张图片
Api用例片段

生成完整的Asciidoc文档用到了Swagger2MarkupConverter,第一步先获取在线版本的文档并保存到文件swagger.json中,第二步把swagger.json和之前的例子snippets整合并保存为Asciidoc格式的完整文档。生成结果如图:

SpringBoot2基于Swagger2生成离线Api文档_第6张图片
生成结果

Swagger配置类

通过配置类定义一些文档相关的信息

package com.chinamobile.cmic.apidoc.config;

import com.google.common.base.Predicates;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import static springfox.documentation.builders.PathSelectors.ant;

/**
 * @author ChaselX
 * @date 2019/1/30 11:22
 */
@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket restApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .paths(Predicates.and(ant("/**"), Predicates.not(ant("/error"))))
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("API Document")
                .description("API Document for Spring Boot 2 Project")
                .contact(new Contact("ChaselX", "", ""))
                .version("1.0")
                .build();
    }
}

LogstashEncoder

在resources目录下创建一个名为logback.xml的配置文件,使用LogstashEncoder作为Default Log Encoder



    
    

    

    
    
    

    

    
        
    

    
        
    


index.adoc

路径:项目名src/docs/asciidoc/index.adoc

include::{generated}/overview.adoc[]
include::{generated}/paths.adoc[]
include::{generated}/security.adoc[]
include::{generated}/definitions.adoc[]

生成HTML5、PDF的文档

利用前面配置的maven插件,只需要执行打包就可以生成相应的文档,如图:

SpringBoot2基于Swagger2生成离线Api文档_第7张图片
生成的HTML5文档
SpringBoot2基于Swagger2生成离线Api文档_第8张图片
生成的pdf文档

你可能感兴趣的:(SpringBoot2基于Swagger2生成离线Api文档)