1.集成swagger2、swagger2-ui
step1: 添加相关依赖jar包
<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>${springfox.version}</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>${springfox.version}</version> </dependency>step2: 项目代码增加swagger2相关配置,具体参考如下:
package com.xxx.xxx.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import springfox.documentation.annotations.ApiIgnore; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; /** * @author XXX * @project XXX * @package com.xxx.xxx.config * @date 2020/10/19 16:31 */ @Configuration @EnableSwagger2 @ComponentScan("com.xxx.xxx.controller") public class Swagger2Config { @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.xxx.xxx")) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("Demo Swagger2 RESTFul APIs") .description("api root:http://xxx.com.cn/api/xxx/v1") .termsOfServiceUrl("http://xxx.com.cn/") .contact("xxx@xxx.com") .version("1.0") .build(); } }step3: 修改controller代码,示例如下:
package com.xxx.xxx.controller; import com.alibaba.fastjson.JSONObject; import com.xxx.xxx.common.RetMessage; import com.xxx.xxx.pojo.*; import com.xxx.xxx.service.MobileXxxAPIService; import com.xxxx.xxx.utils.CollectionUtils; import io.swagger.annotations.*; import io.swagger.annotations.Example; import io.swagger.annotations.ExampleProperty; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; /** * @author xxx * @project demo * @package com.xxx.xxx.controller * @description xxx数据API接口 * @date 2020/9/16 16:10 */ @Controller @RequestMapping("/mobile/xxx") @Api(value = "xxx 移动端api", description = "xxx 移动端api") public class MobileXxxAPIController { private final Logger logger = LoggerFactory.getLogger ( getClass ( ) ); @Autowired private MobileXxxAPIService mobileXxxAPIService; /** * 当前账户余额 * @param data * @return */ @ApiOperation(value = "当前账户余额", notes = "获取当前账户余额", httpMethod = "POST") @ApiResponses({ @ApiResponse(code = 201, message = "请求已经被实现"), @ApiResponse(code = 400, message = "请求参数有误"), @ApiResponse(code = 401, message = "用户验证失败"), @ApiResponse(code = 403, message = "服务器禁止访问"), @ApiResponse(code = 404, message = "请求资源未找到"), @ApiResponse(code = 500, message = "服务器内部解析出错")}) @RequestMapping(value = "/accountBalance") @ResponseBody public Object getAccountBalance(@RequestBody AccountBalanceRequestBody data) { return CollectionUtils.createMap ( RetMessage.DATA, mobileXxxAPIService.getAccountBalance (data.getOrg_id()), RetMessage.META, CollectionUtils.createMap ( RetMessage.MSG, RetMessage.MSGSUCCESS, RetMessage.CODE, RetMessage.CODESUCESS ) ); } }2.安装插件生成离线html、PDF文档
step1:修改pom.xml,主要增加的配置项如下:
<properties> <swagger2markup.version>1.2.0</swagger2markup.version> <asciidoctor.input.directory>${project.basedir}/src/docs/asciidoc</asciidoctor.input.directory> <swagger.output.dir>${project.build.directory}/swagger</swagger.output.dir> <swagger.snippetOutput.dir>${project.build.directory}/asciidoc/snippets</swagger.snippetOutput.dir> <generated.asciidoc.directory>${project.build.directory}/asciidoc/generated</generated.asciidoc.directory> <asciidoctor.html.output.directory>${project.build.directory}/asciidoc/html</asciidoctor.html.output.directory> <asciidoctor.pdf.output.directory>${project.build.directory}/asciidoc/pdf</asciidoctor.pdf.output.directory> <swagger.input>${swagger.output.dir}/swagger.json</swagger.input> </properties> <dependencies> <!--offline doc--> <dependency> <groupId>org.springframework.restdocs</groupId> <artifactId>spring-restdocs-mockmvc</artifactId> <!--<scope>test</scope>--> </dependency> <dependency> <groupId>io.github.swagger2markup</groupId> <artifactId>swagger2markup-spring-restdocs-ext</artifactId> <version>${swagger2markup.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-staticdocs</artifactId> <version>2.6.1</version> <!--<scope>test</scope>--> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <pluginRepositories> <pluginRepository> <id>jcenter-snapshots</id> <name>jcenter</name> <url>http://oss.jfrog.org/artifactory/oss-snapshot-local/</url> </pluginRepository> <pluginRepository> <id>jcenter-releases</id> <name>jcenter</name> <url>http://jcenter.bintray.com</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <systemPropertyVariables> <io.springfox.staticdocs.outputDir>${swagger.output.dir}</io.springfox.staticdocs.outputDir> <io.springfox.staticdocs.snippetsOutputDir>${swagger.snippetOutput.dir}</io.springfox.staticdocs.snippetsOutputDir> </systemPropertyVariables> </configuration> </plugin> <!-- First, use the swagger2markup plugin to generate asciidoc --> <plugin> <groupId>io.github.swagger2markup</groupId> <artifactId>swagger2markup-maven-plugin</artifactId> <version>${swagger2markup.version}</version> <dependencies> <dependency> <groupId>io.github.swagger2markup</groupId> <artifactId>swagger2markup-import-files-ext</artifactId> <version>${swagger2markup.version}</version> </dependency> <dependency> <groupId>io.github.swagger2markup</groupId> <artifactId>swagger2markup-spring-restdocs-ext</artifactId> <version>${swagger2markup.version}</version> </dependency> </dependencies> <configuration> <swaggerInput>${swagger.input}</swaggerInput> <outputDir>${generated.asciidoc.directory}</outputDir> <config> <swagger2markup.markupLanguage>ASCIIDOC</swagger2markup.markupLanguage> <swagger2markup.pathsGroupedBy>TAGS</swagger2markup.pathsGroupedBy> <swagger2markup.extensions.dynamicOverview.contentPath>${project.basedir}/src/docs/asciidoc/extensions/overview</swagger2markup.extensions.dynamicOverview.contentPath> <swagger2markup.extensions.dynamicDefinitions.contentPath>${project.basedir}/src/docs/asciidoc/extensions/definitions</swagger2markup.extensions.dynamicDefinitions.contentPath> <swagger2markup.extensions.dynamicPaths.contentPath>${project.basedir}/src/docs/asciidoc/extensions/paths</swagger2markup.extensions.dynamicPaths.contentPath> <swagger2markup.extensions.dynamicSecurity.contentPath>${project.basedir}src/docs/asciidoc/extensions/security/</swagger2markup.extensions.dynamicSecurity.contentPath> <swagger2markup.extensions.springRestDocs.snippetBaseUri>${swagger.snippetOutput.dir}</swagger2markup.extensions.springRestDocs.snippetBaseUri> <swagger2markup.extensions.springRestDocs.defaultSnippets>true</swagger2markup.extensions.springRestDocs.defaultSnippets> </config> </configuration> <executions> <execution> <phase>test</phase> <goals> <goal>convertSwagger2markup</goal> </goals> </execution> </executions> </plugin> <!-- Run the generated asciidoc through Asciidoctor to generate other documentation types, such as PDFs or HTML5 --> <plugin> <groupId>org.asciidoctor</groupId> <artifactId>asciidoctor-maven-plugin</artifactId> <version>1.5.6</version> <!-- Include Asciidoctor PDF for pdf generation --> <dependencies> <dependency> <groupId>org.asciidoctor</groupId> <artifactId>asciidoctorj-pdf</artifactId> <version>1.5.0-alpha-zh.16</version> </dependency> <dependency> <groupId>org.jruby</groupId> <artifactId>jruby-complete</artifactId> <version>1.7.21</version> </dependency> </dependencies> <!-- Configure generic document generation settings --> <configuration> <sourceDirectory>${asciidoctor.input.directory}</sourceDirectory> <sourceDocumentName>index.adoc</sourceDocumentName> <attributes> <doctype>book</doctype> <toc>left</toc> <toclevels>3</toclevels> <numbered></numbered> <hardbreaks></hardbreaks> <sectlinks></sectlinks> <sectanchors></sectanchors> <generated>${generated.asciidoc.directory}</generated> </attributes> </configuration> <!-- Since each execution can only handle one backend, run separate executions for each desired output type --> <executions> <execution> <id>output-html</id> <phase>test</phase> <goals> <goal>process-asciidoc</goal> </goals> <configuration> <backend>html5</backend> <outputDirectory>${asciidoctor.html.output.directory}</outputDirectory> </configuration> </execution> <execution> <id>output-pdf</id> <phase>test</phase> <goals> <goal>process-asciidoc</goal> </goals> <configuration> <backend>pdf</backend> <outputDirectory>${asciidoctor.pdf.output.directory}</outputDirectory> <attributes> <pdf-style>cn</pdf-style> </attributes> </configuration> </execution> </executions> </plugin> <!-- specify the main class for the manifest --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.1.0</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> <!--important!!! specify the main class for the manifest!!!--> <!--important!!! specify the main class for the manifest!!!--> <!--important!!! specify the main class for the manifest!!!--> <mainClass>com.mskj.dop.ApplicationMain</mainClass> </manifest> </archive> </configuration> </plugin> <!-- copy dependencies to the lib directory --> <plugin> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/lib</outputDirectory> </configuration> </execution> </executions> </plugin> <!-- copy the generated documents --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.1.0</version> <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>${asciidoctor.html.output.directory}</directory> </resource> <resource> <directory>${asciidoctor.pdf.output.directory}</directory> </resource> </resources> </configuration> </execution> </executions> </plugin> </plugins> </build>step2: 新增测试代码(生成html、PDF文件是在test阶段触发的) 具体的测试代码,参考如下:
package com.xxx.xxx; 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.restdocs.operation.preprocess.Preprocessors; 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.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; /** * @author xxx * @project xxx * @package com.xxx.xxx * @date 2020/10/21 14:03 */ @WebAppConfiguration @RunWith(SpringRunner.class) @AutoConfigureRestDocs(outputDir = "build/asciidoc/snippets") @SpringBootTest @AutoConfigureMockMvc public class Swagger2MarkupTest { @Autowired private MockMvc mockMvc; @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); } } }step3: 项目源码目录下增加index.adoc文件 index.adoc文件内容:
include::{generated}/overview.adoc[] include::{generated}/paths.adoc[] include::{generated}/security.adoc[] include::{generated}/definitions.adoc[]step4: 使用IDE mvn clean test触发文档构建
step5:查看PDF或者HTML文档,具体文档路径:
3.解决PDF中文乱码问题
具体参考【6】中的两种方式,笔者选择方式1 ⚠️下载asciidoctorj-pdf-1.5.0-alpha-zh.16.jar,请从【5】中提到的GitHub项目中下载[1].https://www.baeldung.com/swagger-2-documentation-for-spring-rest-api [2].https://www.javazhiyin.com/57982.html [3].https://github.com/houko/SpringBootUnity [4].https://www.jianshu.com/p/033d650164c4 [5].https://blog.csdn.net/han_chuang/article/details/98748944 [6].https://www.hotbak.net/key/Swagger%E4%BD%BF%E7%94%A8%E4%B8%89%E8%A7%A3%E5%86%B3swagger2markup%E7%94%9F%E6%88%90%E7%9A%84%E7%A6%BB%E7%BA%BFpdf%E5%8D%9A%E5%AE%A2.html