Full Code of JMCuixy/SwaggerToWord for AI

master 0da571201671 cached
30 files
136.1 KB
31.8k tokens
144 symbols
1 requests
Download .txt
Repository: JMCuixy/SwaggerToWord
Branch: master
Commit: 0da571201671
Files: 30
Total size: 136.1 KB

Directory structure:
gitextract_o1xkyn5v/

├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
└── src/
    └── main/
        ├── java/
        │   └── org/
        │       └── word/
        │           ├── Application.java
        │           ├── config/
        │           │   ├── JavaConfig.java
        │           │   └── SwaggerDocumentationConfig.java
        │           ├── controller/
        │           │   ├── IndexController.java
        │           │   ├── OpenApiWordController.java
        │           │   └── WordController.java
        │           ├── model/
        │           │   ├── ModelAttr.java
        │           │   ├── Request.java
        │           │   ├── Response.java
        │           │   └── Table.java
        │           ├── service/
        │           │   ├── OpenApiWordService.java
        │           │   ├── WordService.java
        │           │   └── impl/
        │           │       ├── OpenApiWordServiceImpl.java
        │           │       └── WordServiceImpl.java
        │           └── utils/
        │               ├── JsonUtils.java
        │               ├── MenuUtils.java
        │               ├── ModelAttrUtils.java
        │               ├── RequestUtils.java
        │               └── ResponseUtils.java
        └── resources/
            ├── application.yml
            ├── logback.xml
            └── templates/
                ├── index.html
                ├── word-en_US.html
                ├── word-fr_FR.html
                ├── word-zh_CN.html
                └── word.html

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.idea
/*.iml
target/


================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
### 使用步骤(Google Chrome)
1. 启动工程,访问地址: http://127.0.0.1:8080/swagger-ui.html
2. swagger2Word 提供了多种方式生成 word 文档,可以通过 swagger json 的资源地址,例如:https://petstore.swagger.io/v2/swagger.json ;可以通过上传 json 文件;甚至可以直接输入 json 字符串。  
![Image text](https://github.com/JMCuixy/swagger2word/blob/master/swagger2word.jpg)
3. 生成的 WORD 示例:  
![Image text](https://github.com/JMCuixy/swagger2word/blob/master/demo_word.jpg)

<br>
<br>
<br>
<p>--------------版本迭代历程,感谢各位小伙伴的支持--------------</p>

#### 版本: SwaggerToWord 1.0 (2018-01-18)
1. 一个Swagger API 文档转 Word 文档的工具项目 
2. 项目想法和说明可以参考:[http://www.cnblogs.com/jmcui/p/8298823.html](http://www.cnblogs.com/jmcui/p/8298823.html)

#### 版本:SwaggerToWord 1.1 (2018-02-11)
1. 替换 HttpClient 工具类以适配更多的Restful服务。
2. 把 json 示例文件替换成官方的示例文件。
3. 更改写死的模板。让生成的 word 的内容都从 Swagger api 中来。

#### 版本:SwaggerToWord 1.2 (2018-06-21)
1. 引入了 Spring 的 RestTemplate 取代 HttpClients 以支持更多的 Restful 请求。
2. 命名规范以及增加异常处理,对于无法处理的HTTP请求返回空字符串。
3. 修改之前导入data.josn的方式,变成 restTemplate.getForObject("SwaggerJson的url地址",Map.class) 的动态获取方式。

#### 版本:SwaggerToWord 1.3 (2019-06-12)
1. Spring 框架向 SpringBoot 升级。
2. thymeleaf 取代 jsp模板。

#### 版本:SwaggerToWord 1.4 (2019-08-02)
1. 取消 HttpClient 的请求方式去获得返回值,改由从 Swagger Json 文件中直接读取  
2. 针对 application/json 请求方式的入参做渲染     
3. 对于文字过多导致 HTML table 变形做适配   
4. 真诚感谢 [fpzhan](https://github.com/fpzhan)  的代码贡献。

##### 版本: SwaggerToWord 1.4.1 (2019-09-25)
1. 修复当请求参数为@RequestBody 时,参数类型显示不正确问题。
2. 新增直接从请求路径中获取 Swagger JSON,多项目下API文档生成。
3. 解决中文乱码问题。
4. 真诚感谢 [NealLemon](https://github.com/NealLemon) 的代码贡献。


##### 版本: SwaggerToWord 1.4.2 (2019-10-11)
1. 增加一键下载doc文件文件的方式。
2. 真诚感谢 [benwudan](https://github.com/benwudan) 的想法和代码贡献。

#### 版本:SwaggerToWord 1.5 (2019-12-18)
1. 代码梳理和页面美化。
4. 真诚感谢 [kevin4j](https://github.com/kevin4j)  的代码贡献。


================================================
FILE: pom.xml
================================================
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.word</groupId>
    <artifactId>Swagger2Word</artifactId>

    <packaging>jar</packaging>
    <version>1.5.0-SNAPSHOT</version>
    <name>swagger2word</name>


    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
    </parent>

    <properties>
        <skipTests>true</skipTests>
        <java.version>1.8</java.version>
        <springfox-version>2.6.1</springfox-version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- thymeleaf -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </dependency>
        <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>
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
        </dependency>
    </dependencies>
    <build>
        <finalName>Swagger2Word</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>utf-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <delimiters>
                        <delimiter>${*}</delimiter>
                        <delimiter>@</delimiter>
                    </delimiters>
                    <useDefaultDelimiters>false</useDefaultDelimiters>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.0.1.RELEASE</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <!--可以把依赖的包都打包到生成的Jar包中-->
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                        <!--可以生成不含依赖包的不可执行Jar包-->
                        <configuration>
                            <classifier>exec</classifier>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
		  	<plugin>
		  		<groupId>org.springframework.boot</groupId>
		 		<artifactId>spring-boot-maven-plugin</artifactId>
		  	</plugin>
        </plugins>
    </build>
</project>


================================================
FILE: src/main/java/org/word/Application.java
================================================
package org.word;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * @author cuixiuyin
 * @description
 * @date: 2018/12/19 21:32
 */
@SpringBootApplication
@EnableSwagger2
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}


================================================
FILE: src/main/java/org/word/config/JavaConfig.java
================================================
package org.word.config;

import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;

/**
 * Created by XiuYin.Cui on 2018/6/21.
 */
@Configuration
public class JavaConfig {

    @Bean
    public RestTemplate restTemplate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
        SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
                .loadTrustMaterial(null, acceptingTrustStrategy)
                .build();
        SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLSocketFactory(csf)
                .build();
        HttpComponentsClientHttpRequestFactory requestFactory =
                new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(httpClient);

        //60s
        requestFactory.setConnectTimeout(60 * 1000);
        requestFactory.setReadTimeout(60 * 1000);
        RestTemplate restTemplate = new RestTemplate(requestFactory);
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        return restTemplate;
    }
}


================================================
FILE: src/main/java/org/word/config/SwaggerDocumentationConfig.java
================================================
package org.word.config;

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

import java.util.Collections;
import java.util.List;

/*
 * added by dongxl6
 * enable swagger-ui
 */
@Configuration
public class SwaggerDocumentationConfig {

    ApiInfo apiInfo() {
        return new ApiInfoBuilder()
            .title("Swagger to Word")
            .description("a tool for converting swagger json to word")
            .license("Apache 2.0")
            .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
            .termsOfServiceUrl("")
            .version("0.0.1")
            .contact(new Contact("","", "15980292662@163.com"))
            .build();
    }

    @Bean
    public Docket customImplementation(){
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                    .apis(RequestHandlerSelectors.basePackage("org.word.controller"))
                    .build()
                .directModelSubstitute(org.joda.time.LocalDate.class, java.sql.Date.class)
                .directModelSubstitute(org.joda.time.DateTime.class, java.util.Date.class)
                .apiInfo(apiInfo());
    }

}


================================================
FILE: src/main/java/org/word/controller/IndexController.java
================================================
package org.word.controller;


import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;

/**
 * @author xiuyin.cui
 * @Description
 * @date 2019/3/22 10:52
 */
@Controller
public class IndexController {
    @ApiIgnore
    @RequestMapping(value = "/")
    public String index(HttpServletRequest request) {
        return "redirect:swagger-ui.html";
    }
}


================================================
FILE: src/main/java/org/word/controller/OpenApiWordController.java
================================================
package org.word.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.word.service.OpenApiWordService;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Map;

@Controller
@Api(tags = "OpenAPI")
public class OpenApiWordController {

    @Value("${swagger.url}")
    private String swaggerUrl;

    @Autowired
    private OpenApiWordService openApiWordService;
    @Autowired
    private SpringTemplateEngine springTemplateEngine;

    private String fileName;

    /**
     * 将 swagger json文件转换成 word文档并下载
     *
     * @param model
     * @param jsonFile 需要转换成 word 文档的swagger json文件
     * @param response
     * @return
     * @throws Exception
     */
    @ApiOperation(value = "将 swagger json文件转换成 word文档并下载", notes = "", tags = {"Word"})
    @ApiResponses(value = {@ApiResponse(code = 200, message = "请求成功。")})
    @RequestMapping(value = "/OpenApiFileToWord", method = {RequestMethod.POST})
    public void getWord(Model model, @ApiParam("swagger json file") @Valid @RequestPart("jsonFile") MultipartFile jsonFile, HttpServletResponse response) throws Exception {
        generateModelData(model, jsonFile);
        writeContentToResponse(model, response);
    }

    private void generateModelData(Model model, MultipartFile jsonFile) throws IOException {
        Map<String, Object> result = openApiWordService.tableList(jsonFile);
        fileName = jsonFile.getOriginalFilename();

        if (fileName != null) {
            fileName = fileName.replaceAll(".json", "");
        } else {
            fileName = "toWord";
        }

        model.addAttribute("url", "http://");
        model.addAttribute("download", 0);
        model.addAllAttributes(result);
    }

    private void generateModelData(Model model, String url, Integer download) {
        url = StringUtils.defaultIfBlank(url, swaggerUrl);
        Map<String, Object> result = openApiWordService.tableList(url);
        model.addAttribute("url", url);
        model.addAttribute("download", download);
        model.addAllAttributes(result);
    }

    private void writeContentToResponse(Model model, HttpServletResponse response) {
        Context context = new Context();
        context.setVariables(model.asMap());
        String content = springTemplateEngine.process("word", context);
        response.setContentType("application/octet-stream;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        try (BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream())) {
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".doc", "utf-8"));
            byte[] bytes = content.getBytes();
            bos.write(bytes, 0, bytes.length);
            bos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

================================================
FILE: src/main/java/org/word/controller/WordController.java
================================================
package org.word.controller;

import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.word.service.WordService;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.*;
import java.net.URLEncoder;
import java.util.Locale;
import java.util.Map;

/**
 * Created by XiuYin.Cui on 2018/1/11.
 */
@Controller
@Api(tags = "the toWord API")
@Slf4j
public class WordController {

    @Value("${swagger.url}")
    private String swaggerUrl;

    @Autowired
    private WordService tableService;
    @Autowired
    private SpringTemplateEngine springTemplateEngine;

    private String fileName = "toWord";

    /**
     * 将 swagger 文档转换成 html 文档,可通过在网页上右键另存为 xxx.doc 的方式转换为 word 文档
     *
     * @param model
     * @param url   需要转换成 word 文档的资源地址
     * @return
     */
    @Deprecated
    @ApiOperation(value = "将 swagger 文档转换成 html 文档,可通过在网页上右键另存为 xxx.doc 的方式转换为 word 文档", response = String.class, tags = {"Word"})
    @ApiResponses(value = {@ApiResponse(code = 200, message = "请求成功。", response = String.class)})
    @RequestMapping(value = "/toWord", method = {RequestMethod.GET})
    public String getWord(Model model,
                          @ApiParam(value = "资源地址", required = false) @RequestParam(value = "url", required = false) String url,
                          @ApiParam(value = "是否下载", required = false) @RequestParam(value = "download", required = false, defaultValue = "1") Integer download) {
        generateModelData(model, url, download);

        // Is there a localized template available ?
        Locale currentLocale = Locale.getDefault();
        String localizedTemplate = "word-" + currentLocale.getLanguage() + "_" + currentLocale.getCountry();
        String fileName = "/templates/" + localizedTemplate + ".html";

        if (getClass().getResourceAsStream(fileName) != null) {
            log.info(fileName + " resource found");
            return localizedTemplate;
        } else {
            log.info(fileName + " resource not found, using default");
        }
        return "word";
    }

    private void generateModelData(Model model, String url, Integer download) {
        url = StringUtils.defaultIfBlank(url, swaggerUrl);
        Map<String, Object> result = tableService.tableList(url);
        model.addAttribute("url", url);
        model.addAttribute("download", download);
        model.addAllAttributes(result);
    }

    /**
     * 将 swagger 文档一键下载为 doc 文档
     *
     * @param model
     * @param url      需要转换成 word 文档的资源地址
     * @param response
     */
    @ApiOperation(value = "将 swagger 文档一键下载为 doc 文档", notes = "", tags = {"Word"})
    @ApiResponses(value = {@ApiResponse(code = 200, message = "请求成功。")})
    @RequestMapping(value = "/downloadWord", method = {RequestMethod.GET})
    public void word(Model model, @ApiParam(value = "资源地址", required = false) @RequestParam(required = false) String url, HttpServletResponse response) {
        generateModelData(model, url, 0);
        writeContentToResponse(model, response);
    }

    private void writeContentToResponse(Model model, HttpServletResponse response) {
        Context context = new Context();
        context.setVariables(model.asMap());
        String content = springTemplateEngine.process("word", context);
        response.setContentType("application/octet-stream;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        try (BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream())) {
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".doc", "utf-8"));
            byte[] bytes = content.getBytes();
            bos.write(bytes, 0, bytes.length);
            bos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 将 swagger json文件转换成 word文档并下载
     *
     * @param model
     * @param jsonFile 需要转换成 word 文档的swagger json文件
     * @param response
     * @return
     */
    @ApiOperation(value = "将 swagger json文件转换成 word文档并下载", notes = "", tags = {"Word"})
    @ApiResponses(value = {@ApiResponse(code = 200, message = "请求成功。")})
    @RequestMapping(value = "/fileToWord", method = {RequestMethod.POST})
    public void getWord(Model model, @ApiParam("swagger json file") @Valid @RequestPart("jsonFile") MultipartFile jsonFile, HttpServletResponse response) {
        generateModelData(model, jsonFile);
        writeContentToResponse(model, response);
    }

    /**
     * 将 swagger json字符串转换成 word文档并下载
     *
     * @param model
     * @param jsonStr  需要转换成 word 文档的swagger json字符串
     * @param response
     * @return
     */
    @ApiOperation(value = "将 swagger json字符串转换成 word文档并下载", notes = "", tags = {"Word"})
    @ApiResponses(value = {@ApiResponse(code = 200, message = "请求成功。")})
    @RequestMapping(value = "/strToWord", method = {RequestMethod.POST})
    public void getWord(Model model, @ApiParam("swagger json string") @Valid @RequestParam("jsonStr") String jsonStr, HttpServletResponse response) {
        generateModelData(model, jsonStr);
        writeContentToResponse(model, response);
    }

    private void generateModelData(Model model, String jsonStr) {
        Map<String, Object> result = tableService.tableListFromString(jsonStr);
        model.addAttribute("url", "http://");
        model.addAttribute("download", 0);
        model.addAllAttributes(result);
    }

    private void generateModelData(Model model, MultipartFile jsonFile) {
        Map<String, Object> result = tableService.tableList(jsonFile);
        fileName = jsonFile.getOriginalFilename();

        if (fileName != null) {
            fileName = fileName.replaceAll(".json", "");
        } else {
            fileName = "toWord";
        }

        model.addAttribute("url", "http://");
        model.addAttribute("download", 0);
        model.addAllAttributes(result);
    }
}


================================================
FILE: src/main/java/org/word/model/ModelAttr.java
================================================
package org.word.model;

import lombok.Data;
import org.apache.commons.lang3.StringUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * 返回属性
 *
 * @author kevin
 */
@Data
public class ModelAttr implements Serializable {

    public String getClassName() {
		return className;
	}

	public void setClassName(String className) {
		this.className = className;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public Boolean getRequire() {
		return require;
	}

	public void setRequire(Boolean require) {
		this.require = require;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public List<ModelAttr> getProperties() {
		return properties;
	}

	public void setProperties(List<ModelAttr> properties) {
		this.properties = properties;
	}

	public boolean isCompleted() {
		return isCompleted;
	}

	public void setCompleted(boolean isCompleted) {
		this.isCompleted = isCompleted;
	}

	public static long getSerialversionuid() {
		return serialVersionUID;
	}

	private static final long serialVersionUID = -4074067438450613643L;

    /**
     * 类名
     */
    private String className = StringUtils.EMPTY;
    /**
     * 属性名
     */
    private String name = StringUtils.EMPTY;
    /**
     * 类型
     */
    private String type = StringUtils.EMPTY;
    /**
     * 是否必填
     */
    private Boolean require = false;
    /**
     * 属性描述
     */
    private String description;
    /**
     * 嵌套属性列表
     */
    private List<ModelAttr> properties = new ArrayList<>();

    /**
     * 是否加载完成,避免循环引用
     */
    private boolean isCompleted = false;
}


================================================
FILE: src/main/java/org/word/model/Request.java
================================================
package org.word.model;

import java.io.Serializable;

import lombok.Data;

/**
 * Created by XiuYin.Cui on 2018/1/11.
 */
@Data
public class Request implements Serializable{

    public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public String getParamType() {
		return paramType;
	}

	public void setParamType(String paramType) {
		this.paramType = paramType;
	}

	public Boolean getRequire() {
		return require;
	}

	public void setRequire(Boolean require) {
		this.require = require;
	}

	public String getRemark() {
		return remark;
	}

	public void setRemark(String remark) {
		this.remark = remark;
	}

	public ModelAttr getModelAttr() {
		return modelAttr;
	}

	public void setModelAttr(ModelAttr modelAttr) {
		this.modelAttr = modelAttr;
	}

	/**
     * 参数名
     */
    private String name;

    /**
     * 数据类型
     */
    private String type;

    /**
     * 参数类型
     */
    private String paramType;

    /**
     * 是否必填
     */
    private Boolean require;

    /**
     * 说明
     */
    private String remark;

    /**
     * 复杂对象引用
     */
    private ModelAttr modelAttr;
}


================================================
FILE: src/main/java/org/word/model/Response.java
================================================
package org.word.model;

import java.io.Serializable;

import lombok.Data;

/**
 * Created by XiuYin.Cui on 2018/1/11.
 */
@Data
public class Response implements Serializable{

    public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getRemark() {
		return remark;
	}

	public void setRemark(String remark) {
		this.remark = remark;
	}

	/**
     * 返回参数
     */
    private String description;

    /**
     * 参数名
     */
    private String name;

    /**
     * 备注
     */
    private String remark;
}


================================================
FILE: src/main/java/org/word/model/Table.java
================================================
package org.word.model;

import lombok.Data;

import java.util.List;

/**
 * Created by XiuYin.Cui on 2018/1/11.
 */
@Data
public class Table {

    public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getTag() {
		return tag;
	}

	public void setTag(String tag) {
		this.tag = tag;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String getRequestForm() {
		return requestForm;
	}

	public void setRequestForm(String requestForm) {
		this.requestForm = requestForm;
	}

	public String getResponseForm() {
		return responseForm;
	}

	public void setResponseForm(String responseForm) {
		this.responseForm = responseForm;
	}

	public String getRequestType() {
		return requestType;
	}

	public void setRequestType(String requestType) {
		this.requestType = requestType;
	}

	public List<Request> getRequestList() {
		return requestList;
	}

	public void setRequestList(List<Request> requestList) {
		this.requestList = requestList;
	}

	public List<Response> getResponseList() {
		return responseList;
	}

	public void setResponseList(List<Response> responseList) {
		this.responseList = responseList;
	}

	public String getRequestParam() {
		return requestParam;
	}

	public void setRequestParam(String requestParam) {
		this.requestParam = requestParam;
	}

	public String getResponseParam() {
		return responseParam;
	}

	public void setResponseParam(String responseParam) {
		this.responseParam = responseParam;
	}

	public ModelAttr getModelAttr() {
		return modelAttr;
	}

	public void setModelAttr(ModelAttr modelAttr) {
		this.modelAttr = modelAttr;
	}

	/**
     * 大标题
     */
    private String title;
    /**
     * 小标题
     */
    private String tag;
    /**
     * url
     */
    private String url;

    /**
     * 描述
     */
    private String description;

    /**
     * 请求参数格式
     */
    private String requestForm;

    /**
     * 响应参数格式
     */
    private String responseForm;

    /**
     * 请求方式
     */
    private String requestType;

    /**
     * 请求体
     */
    private List<Request> requestList;

    /**
     * 返回体
     */
    private List<Response> responseList;

    /**
     * 请求参数
     */
    private String requestParam;

    /**
     * 返回参数
     */
    private String responseParam;

    /**
     * 返回属性列表
     */
    private ModelAttr modelAttr = new ModelAttr();
}


================================================
FILE: src/main/java/org/word/service/OpenApiWordService.java
================================================
package org.word.service;

import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Map;

/**
 * Created by XiuYin.Cui on 2018/1/12.
 */
public interface OpenApiWordService {

    Map<String,Object> tableList(String swaggerUrl);

    Map<String, Object> tableListFromString(String jsonStr) throws IOException;

    Map<String, Object> tableList(MultipartFile jsonFile) throws IOException;
}

================================================
FILE: src/main/java/org/word/service/WordService.java
================================================
package org.word.service;

import org.springframework.web.multipart.MultipartFile;

import java.util.Map;

/**
 * Created by XiuYin.Cui on 2018/1/12.
 */
public interface WordService {

    Map<String,Object> tableList(String swaggerUrl);

    Map<String, Object> tableListFromString(String jsonStr);

    Map<String, Object> tableList(MultipartFile jsonFile);
}


================================================
FILE: src/main/java/org/word/service/impl/OpenApiWordServiceImpl.java
================================================
package org.word.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.word.model.ModelAttr;
import org.word.model.Request;
import org.word.model.Response;
import org.word.model.Table;
import org.word.service.OpenApiWordService;
import org.word.utils.JsonUtils;
import org.word.utils.RequestUtils;
import org.word.utils.ResponseUtils;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;

/**
 * @Author XiuYin.Cui
 * @Date 2018/1/12
 **/
@SuppressWarnings({"unchecked", "rawtypes"})
@Slf4j
@Service
public class OpenApiWordServiceImpl implements OpenApiWordService {

    @Autowired
    private RestTemplate restTemplate;

    @Override
    public Map<String, Object> tableList(String swaggerUrl) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            String jsonStr = restTemplate.getForObject(swaggerUrl, String.class);
            resultMap = tableListFromString(jsonStr);
            // log.debug(JsonUtils.writeJsonStr(resultMap));
        } catch (Exception e) {
            log.error("parse error", e);
        }
        return resultMap;
    }

    @Override
    public Map<String, Object> tableListFromString(String jsonStr) throws IOException {
        Map<String, Object> resultMap = new HashMap<>();
        List<Table> result = new ArrayList<>();
        try {
            Map<String, Object> map = getResultFromString(result, jsonStr);
            Map<String, List<Table>> tableMap = result.stream().parallel().collect(Collectors.groupingBy(Table::getTitle));
            resultMap.put("tableMap", new TreeMap<>(tableMap));
            resultMap.put("info", map.get("info"));

            // log.debug(JsonUtils.writeJsonStr(resultMap));
        } catch (Exception e) {
            log.error("parse error", e);
        	throw e;
        }
        return resultMap;
    }

	@Override
    public Map<String, Object> tableList(MultipartFile jsonFile) throws IOException {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            String jsonStr = new String(jsonFile.getBytes());
            resultMap = tableListFromString(jsonStr);
            // log.debug(JsonUtils.writeJsonStr(resultMap));
        } catch (Exception e) {
            log.error("parse error", e);
        	throw e;
        }
        return resultMap;
    }

    private Map<String, Object> getResultFromString(List<Table> result, String jsonStr) throws IOException {
        // convert JSON string to Map
        Map<String, Object> map = JsonUtils.readValue(jsonStr, HashMap.class);

        //解析model
        Map<String, ModelAttr> definitinMap = parseComponents(map);

        //解析paths
        Map<String, Map<String, Object>> paths = (Map<String, Map<String, Object>>) map.get("paths");

        //获取全局请求参数格式作为默认请求参数格式
        List<String> defaultConsumes = (List) map.get("consumes");

        //获取全局响应参数格式作为默认响应参数格式
        List<String> defaultProduces = (List) map.get("produces");

        if (paths != null) {

            Iterator<Entry<String, Map<String, Object>>> it = paths.entrySet().iterator();
            while (it.hasNext()) {
                Entry<String, Map<String, Object>> path = it.next();

                // 0. 获取该路由下所有请求方式的公共参数
                Map<String, Object> methods = (Map<String, Object>) path.getValue();
                List<LinkedHashMap> commonParameters = (ArrayList) methods.get("parameters");

                Iterator<Entry<String, Object>> it2 = path.getValue().entrySet().iterator();
                // 1.请求路径
                String url = path.getKey();
                String requestType = null;
                while (it2.hasNext()) {
                	try {
                		Entry<String, Object> request = it2.next();

                		// 2.请求方式,类似为 get,post,delete,put 这样
                		requestType = request.getKey();

                		if ("parameters".equals(requestType)) {
                			continue;
                		}

                		Map<String, Object> content = (Map<String, Object>) request.getValue();

                		// 4. 大标题(类说明)
                		String title = String.valueOf(((List) content.get("tags")).get(0));

                		// 5.小标题 (方法说明)
                		String tag = String.valueOf(content.get("operationId"));

                		// 6.接口描述
                		Object descObj = content.get("description");
                		String description = descObj == null ? "" : descObj.toString();

                		// 7. 请求体
                		List<LinkedHashMap> parameters = (ArrayList) content.get("parameters");

                		if (!CollectionUtils.isEmpty(parameters)) {
                			if (commonParameters != null) {
                				parameters.addAll(commonParameters);
                			}
                		} else {
                			if (commonParameters != null) {
                				parameters = commonParameters;
                			}
                		}

                		// 8.返回体
                		Map<String, Object> responses = (LinkedHashMap) content.get("responses");

                		// 9.请求参数格式,类似于 multipart/form-data
                		List<String> requestParamsFormates = getRequestParamsFormate(content);
                		String requestForm = StringUtils.join(requestParamsFormates, ",");

                		// 取出来状态是200时的返回值
                		Map<String, Object> obj = (Map<String, Object>) responses.get("200");
                		Map<String, Object> requestBody = (Map<String, Object>) content.get("requestBody");

                		// 10.返回参数格式,类似于 application/json
                		List<String> responseParamsFormates = getResponseParamsFormate(obj);
                		String responseForm = StringUtils.join(responseParamsFormates, ",");

                		//封装Table
                		Table table = new Table();

                		table.setTitle(title);
                		table.setUrl(url);
                		table.setTag(tag);
                		table.setDescription(description);
                		table.setRequestForm(requestForm);
                		table.setResponseForm(responseForm);
                		table.setRequestType(requestType);
                		table.setRequestList(processRequestList(parameters, requestBody, definitinMap));

                		table.setResponseList(processResponseCodeList(responses, definitinMap));
                		if (obj != null && obj.get("content") != null) {
                			table.setModelAttr(processResponseModelAttrs(obj, definitinMap));
                		}

                		//示例
                		table.setRequestParam(processRequestParam(table.getRequestList()));
                		table.setResponseParam(processResponseParam1(obj, definitinMap));

                		result.add(table);
                	} catch (Exception e) {
                		StringWriter sw = new StringWriter();
                		PrintWriter pw = new PrintWriter(sw);
                		e.printStackTrace(pw);
                		throw new JsonProcessingException(url + "接口格式不正确: " + requestType + "请求 " + e.getMessage()) {};
                	}
                }
            }
        }
        return map;
    }

    /**
     * 请求参数格式, 类似于 multipart/form-data
     */
    private List<String> getRequestParamsFormate(Map<String, Object> obj) {
        Map<String, Object> requestBody = (LinkedHashMap) obj.get("requestBody");
        List<String> requestTypes = new ArrayList();
        if (requestBody != null) {
            Map<String, Map> content = (LinkedHashMap) requestBody.get("content");
            Set keys = content.keySet();
            return new ArrayList<String>(keys);
        }
        return requestTypes;
    }

    /**
     * 返回参数格式,类似于 application/json
     * @throws Exception
     */
    private List<String> getResponseParamsFormate(Map<String, Object> responseObj) {
        Map<String, Map> content = (LinkedHashMap) responseObj.get("content");
        List<String> responseTypes = new ArrayList();
        if (content != null) {
            Set keys = content.keySet();
            return new ArrayList<String>(keys);
        }
        return responseTypes;
    }

    /**
     * 处理请求参数列表
     *
     * @param parameters
     * @param definitinMap
     * @return
     * @throws JsonProcessingException
     */
    private List<Request> processRequestList(List<LinkedHashMap> parameters, Map<String, Object> requestBody, Map<String, ModelAttr> definitinMap) throws JsonProcessingException {
        List<Request> requestList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(parameters)) {
            for (Map<String, Object> param : parameters) {
                Object in = param.get("in");
                Request request = new Request();
                request.setName(String.valueOf(param.get("name")));

                Map<String, String> schema1 = (Map) param.get("schema");

                request.setType(schema1 == null ? " " : schema1.get("type").toString());
                // request.setType(param.get("type") == null ? "object" : param.get("type").toString());
                if (param.get("format") != null) {
                    request.setType(request.getType() + "(" + param.get("format") + ")");
                }
                request.setParamType(String.valueOf(in));
                // 考虑对象参数类型
                if (in != null && "body".equals(in)) {
                    Map<String, Object> schema = (Map) param.get("schema");
                    Object ref = schema.get("$ref");
                    // 数组情况另外处理
                    if (schema.get("type") != null && "array".equals(schema.get("type"))) {
                        ref = ((Map) schema.get("items")).get("$ref");
                        request.setType("array");
                    }
                    if (ref != null) {
                        request.setType(request.getType() + ":" + ref.toString().replaceAll("#/definitions/", ""));
                        request.setModelAttr(definitinMap.get(ref));
                    }
                }
                // 是否必填
                request.setRequire(false);
                if (param.get("required") != null) {
                    request.setRequire((Boolean) param.get("required"));
                }
                // 参数说明
                request.setRemark(String.valueOf(param.get("description")));
                requestList.add(request);
            }
        }

        if (requestBody != null) {
            Map<String, Map> content = (LinkedHashMap) requestBody.get("content");

            try {
            	RequestUtils.validateRequestKey(content);
            } catch(Exception e) {
            	throw new JsonProcessingException("requestybody 字段 " + e.getMessage()) {};
            }

            Iterator<Map.Entry<String, Map>> applications = content.entrySet().iterator();
            while (applications.hasNext()) {
                Map.Entry<String, Map> application = applications.next();

                if (application.getValue() != null) {
                    Request request = new Request();

                    Map<String, Object> schema = (Map<String, Object>) application.getValue().get("schema");
                    request.setName(" ");
                    request.setType(schema == null ? " " : schema.get("type").toString());
                    request.setParamType("body");

                    Object ref = schema.get("$ref");

                    if (schema.get("type") != null && "array".equals(schema.get("type"))) {
                        ref = ((Map) schema.get("items")).get("$ref");
                        request.setType("array");
                    }
                    if (ref != null) {
                        // request.setType(request.getType() + ":" + ref.toString().replaceAll("#/definitions/", ""));
                        request.setType("object");
                        request.setModelAttr(definitinMap.get(ref));
                    }
                    if (schema.get("properties") != null) {
                        ArrayList<String> requiredArr = new ArrayList<String>();
                        if (schema.get("required") != null) {
                            requiredArr = (ArrayList<String>) schema.get("required");
                        }
                        request.setModelAttr(getRequestSchemaModelAttr(schema, requiredArr));
                    }

                    // 是否必填
                    request.setRequire(true);

                    // 参数说明
                    requestList.add(request);
                }
            }
        }
        return requestList;
    }


    /**
     * 处理返回码列表
     *
     * @param responses 全部状态码返回对象
     * @return
     */
    private List<Response> processResponseCodeList(Map<String, Object> responses,  Map<String, ModelAttr> definitinMap ) throws JsonProcessingException  {
        List<Response> responseList = new ArrayList<>();
        Iterator<Map.Entry<String, Object>> resIt = responses.entrySet().iterator();
        while (resIt.hasNext()) {
            Map.Entry<String, Object> entry = resIt.next();
            Response response = new Response();
            // 状态码 200 201 401 403 404 这样
            response.setName(entry.getKey());
            LinkedHashMap<String, Object> statusCodeInfo = (LinkedHashMap) entry.getValue();
            response.setDescription(String.valueOf(statusCodeInfo.get("description")));

            Map<String, Map> content = (Map) statusCodeInfo.get("content");

            if (content != null) {
            	try {
            		ResponseUtils.validateResponseKey(content);
            	} catch(Exception e) {
            		throw new JsonProcessingException("response字段 " + entry.getKey() + "字段 " + e.getMessage()) {};
            	}
                // responses内容application多个遍历处理
                Iterator<Map.Entry<String, Map>> applications = content.entrySet().iterator();

                while (applications.hasNext()) {
                    Map.Entry<String, Map> application = applications.next();

                    if (application.getValue() != null) {
                        Object schema = application.getValue().get("schema");
                        if (schema != null) {
                            Object originalRef = ((LinkedHashMap) schema).get("originalRef");
                            response.setRemark(originalRef == null ? "" : originalRef.toString());
                        }
                        responseList.add(response);
                    }
                }
            } else {
                String ref = String.valueOf(statusCodeInfo.get("$ref"));

                if (ref != "") {
                    ModelAttr modelAttr = definitinMap.get(ref);
                    response.setDescription(modelAttr.getDescription());
                }

                responseList.add(response);
            }
        }
        return responseList;
    }

    /**
     * 处理返回属性列表
     *
     * @param responseObj
     * @param definitinMap
     * @return
     */
    private ModelAttr processResponseModelAttrs(Map<String, Object> responseObj, Map<String, ModelAttr> definitinMap) {
        Map<String, Map> content = (Map) responseObj.get("content");
        //其他类型
        ModelAttr modelAttr = new ModelAttr();

        Iterator<Map.Entry<String, Map>> applications = content.entrySet().iterator();

        while (applications.hasNext()) {
            Map.Entry<String, Map> application = applications.next();

            if (application.getValue() != null) {

                Map<String, Object> schema = (Map<String, Object>) application.getValue().get("schema");
                String type = (String) schema.get("type");
                String ref = null;
                //数组
                if ("array".equals(type)) {
                    Map<String, Object> items = (Map<String, Object>) schema.get("items");
                    if (items != null && items.get("$ref") != null) {
                        ref = (String) items.get("$ref");
                    }
                }
                //对象
                if (schema.get("$ref") != null) {
                    ref = (String) schema.get("$ref");
                }

                //其他类型
                modelAttr.setType(StringUtils.defaultIfBlank(type, StringUtils.EMPTY));

                if (StringUtils.isNotBlank(ref) && definitinMap.get(ref) != null) {
                    modelAttr = definitinMap.get(ref);
                }

                // 未使用ref方式 使用properties方式
                if (schema.get("properties") != null) {
                    modelAttr = getSchemaModelAttr(schema);
                }
            }
        }
        return modelAttr;
    }

    /**
     * 解析components
     *
     * @param map
     * @return
     */
    private Map<String, ModelAttr> parseComponents(Map<String, Object> map) {
        Map<String, Object> definitions = (Map<String, Object>) map.get("components");
        Map<String, ModelAttr> definitinMap = new HashMap<>(256);
        if (definitions != null) {
            Iterator<String> modelNameIt = definitions.keySet().iterator();
            /**
             "components": {
             "requestBodies": {},
             "schemas": {}
             }
             */
            while (modelNameIt.hasNext()) {
                String modeName = modelNameIt.next();
                /**
                 "schemas": {
                 "cat":{},
                 "dog":{},
                 }
                 */
                Map<String, Map<String, Object>> modeContent = (Map<String, Map<String, Object>>) definitions.get(modeName);

                if (modeContent != null) {
                    Iterator<String> modeContentIt = modeContent.keySet().iterator();

                    while (modeContentIt.hasNext()) {
                        String componentsGrandChildName = modeContentIt.next();

                        getAndPutModelAttr(modeContent, definitinMap, modeName, componentsGrandChildName);
                    }
                }
            }
        }
        return definitinMap;
    }

    /**
     * 递归生成ModelAttr
     * 对$ref类型设置具体属性
     */
    private ModelAttr getAndPutModelAttr(Map<String, Map<String, Object>> swaggerMap, Map<String, ModelAttr> resMap, String parentName, String modeName) {
        ModelAttr modeAttr;
        if ((modeAttr = resMap.get("#/components/" + parentName + "/" + modeName)) == null) {
            modeAttr = new ModelAttr();
            resMap.put("#/components/" + parentName + "/" + modeName, modeAttr);
        } else if (resMap.get("#/components/" + parentName + "/" + modeName) != null) {
            return resMap.get("#/components/" + parentName + "/" + modeName);
        }
        Map<String, Object> modeProperties = (Map<String, Object>) swaggerMap.get(modeName).get("properties");
        List<ModelAttr> attrList = new ArrayList<>();
        // 获取required字段,遍历properties添加是否必填属性
        ArrayList modeRequired = (ArrayList) swaggerMap.get(modeName).get("required");

        if (modeProperties != null) {
            Iterator<Entry<String, Object>> mIt = modeProperties.entrySet().iterator();

            //解析属性
            while (mIt.hasNext()) {
                Entry<String, Object> mEntry = mIt.next();
                Map<String, Object> attrInfoMap = (Map<String, Object>) mEntry.getValue();
                ModelAttr child = new ModelAttr();
                child.setName(mEntry.getKey());
                child.setType((String) attrInfoMap.get("type"));
                if (attrInfoMap.get("format") != null) {
                    child.setType(child.getType() + "(" + attrInfoMap.get("format") + ")");
                }
                child.setType(StringUtils.defaultIfBlank(child.getType(), "object"));

                Object ref = attrInfoMap.get("$ref");
                Object items = attrInfoMap.get("items");
                if (ref != null || (items != null && (ref = ((Map) items).get("$ref")) != null)) {
                    String refName = ref.toString();
                    //截取 #/components/ 后面的
                    String clsName = refName.substring(21);
                    ModelAttr refModel = getAndPutModelAttr(swaggerMap, resMap, parentName, clsName);
                    if (refModel != null) {
                        child.setProperties(refModel.getProperties());
                    }
                    child.setType(child.getType() + ":" + clsName);
                }
                child.setDescription((String) attrInfoMap.get("description"));

                child.setRequire(false);
                if (modeRequired != null && modeRequired.contains(mEntry.getKey())) {
                    child.setRequire(true);
                }

                attrList.add(child);
            }
        }

        Object title = swaggerMap.get(modeName).get("title");
        Object description = swaggerMap.get(modeName).get("description");
        modeAttr.setClassName(title == null ? "" : title.toString());
        modeAttr.setDescription(description == null ? "" : description.toString());
        modeAttr.setProperties(attrList);
        return modeAttr;
    }

    /**
     * 递归生成ModelAttr
     * 处理schema对象
     * 处理requestBody直接返回属性值情况
     */
    private ModelAttr getRequestSchemaModelAttr(Map<String, Object> schemaMap, ArrayList requiredArr) {
        ModelAttr modeAttr = new ModelAttr();
        Map<String, Object> modeProperties = (Map<String, Object>) schemaMap.get("properties");

        if ("array".equals(schemaMap.get("type"))) {
            Map items = (Map<String, Object>) schemaMap.get("items");

            if (items != null) {
                modeProperties = (Map<String, Object>) items.get("properties");
            }
        }

        if (modeProperties == null) {
            return null;
        }
        Iterator<Entry<String, Object>> mIt = modeProperties.entrySet().iterator();

        List<ModelAttr> attrList = new ArrayList<>();
        //解析属性
        while (mIt.hasNext()) {
            Entry<String, Object> mEntry = mIt.next();
            Map<String, Object> attrInfoMap = (Map<String, Object>) mEntry.getValue();
            ModelAttr child = new ModelAttr();
            child.setName(mEntry.getKey());
            child.setType((String) attrInfoMap.get("type"));
            if (attrInfoMap.get("format") != null) {
                child.setType(child.getType() + "(" + attrInfoMap.get("format") + ")");
            }
            child.setType(StringUtils.defaultIfBlank(child.getType(), "object"));

            Object properties = attrInfoMap.get("properties");
            Object ref = attrInfoMap.get("$ref");
            Object items = attrInfoMap.get("items");
            if (properties != null || (items != null)) {
                ArrayList<String> childRequiredArr = new ArrayList<String>();
                if (attrInfoMap.get("required") != null) {
                    childRequiredArr = (ArrayList<String>) attrInfoMap.get("required");
                }
                ModelAttr refModel = getRequestSchemaModelAttr(attrInfoMap, childRequiredArr);
                if (refModel != null) {
                    child.setProperties(refModel.getProperties());
                }
                child.setType((String) attrInfoMap.get("type"));
            }
            child.setRequire(true);
            if (!requiredArr.contains(mEntry.getKey())) {
                child.setRequire(false);
            }
            child.setDescription((String) attrInfoMap.get("description"));
            attrList.add(child);
        }
        modeAttr.setClassName("");
        modeAttr.setDescription("");
        modeAttr.setProperties(attrList);
        return modeAttr;
    }

    /**
     * 递归生成ModelAttr
     * 处理schema对象
     * 处理responseData直接返回属性值情况
     */
    private ModelAttr getSchemaModelAttr(Map<String, Object> schemaMap) {
        ModelAttr modeAttr = new ModelAttr();
        Map<String, Object> modeProperties = (Map<String, Object>) schemaMap.get("properties");

        if ("array".equals(schemaMap.get("type"))) {
            Map items = (Map<String, Object>) schemaMap.get("items");

            if (items != null) {
                modeProperties = (Map<String, Object>) items.get("properties");
            }
        }

        if (modeProperties == null) {
            return null;
        }
        Iterator<Entry<String, Object>> mIt = modeProperties.entrySet().iterator();

        List<ModelAttr> attrList = new ArrayList<>();
        //解析属性
        while (mIt.hasNext()) {
            Entry<String, Object> mEntry = mIt.next();
            Map<String, Object> attrInfoMap = (Map<String, Object>) mEntry.getValue();
            ModelAttr child = new ModelAttr();
            child.setName(mEntry.getKey());

            child.setType((String) attrInfoMap.get("type"));
            if (attrInfoMap.get("format") != null) {
                child.setType(child.getType() + "(" + attrInfoMap.get("format") + ")");
            }
            child.setType(StringUtils.defaultIfBlank(child.getType(), "object"));

            Object properties = attrInfoMap.get("properties");
            Object ref = attrInfoMap.get("$ref");
            Object items = attrInfoMap.get("items");
            if (properties != null || (items != null)) {
                ModelAttr refModel = getSchemaModelAttr(attrInfoMap);
                if (refModel != null) {
                    child.setProperties(refModel.getProperties());
                }
                child.setType((String) attrInfoMap.get("type"));
            }
            child.setDescription((String) attrInfoMap.get("description"));
            attrList.add(child);
        }
        modeAttr.setClassName("");
        modeAttr.setDescription("");
        modeAttr.setProperties(attrList);
        return modeAttr;
    }

    /**
     * 处理返回值
     *
     * @param responseObj
     * @return
     */
    private String processResponseParam(Map<String, Object> responseObj, Map<String, ModelAttr> definitinMap) throws JsonProcessingException {
        Map<String, Map> content = (Map) responseObj.get("content");
        if (content != null) {
            Iterator<Map.Entry<String, Map>> applications = content.entrySet().iterator();
            while (applications.hasNext()) {
                Map.Entry<String, Map> application = applications.next();

                if (application.getValue() != null) {
                    Map<String, Object> applicationContent = (Map<String, Object>) application.getValue();
                    if (applicationContent != null) {
                        Map<String, Object> schema = (Map<String, Object>) applicationContent.get("schema");
                        String type = (String) schema.get("type");
                        String ref = null;
                        // 数组
                        if ("array".equals(type)) {
                            Map<String, Object> items = (Map<String, Object>) schema.get("items");
                            if (items != null && items.get("$ref") != null) {
                                ref = (String) items.get("$ref");
                            }
                        }
                        // 对象ref
                        if (schema.get("$ref") != null) {
                            ref = (String) schema.get("$ref");
                        }
                        if (StringUtils.isNotEmpty(ref)) {
                            ModelAttr modelAttr = definitinMap.get(ref);
                            if (modelAttr != null && !CollectionUtils.isEmpty(modelAttr.getProperties())) {
                                Map<String, Object> responseMap = new HashMap<>(8);
                                for (ModelAttr subModelAttr : modelAttr.getProperties()) {
                                    responseMap.put(subModelAttr.getName(), getValue(subModelAttr.getType(), subModelAttr));
                                }
                                return JsonUtils.writeJsonStr(responseMap);
                            }
                        }
                        if (schema.get("properties") != null) {
                            ModelAttr modelAttr = getSchemaModelAttr(schema);
                            if (modelAttr != null) {
                                Map<String, Object> responseMap = new HashMap<>(8);
                                for (ModelAttr subModelAttr : modelAttr.getProperties()) {
                                    responseMap.put(subModelAttr.getName(), getValue(subModelAttr.getType(), subModelAttr));
                                }
                                return JsonUtils.writeJsonStr(responseMap);
                            }
                        }
                    }
                }
            }
        }
        return StringUtils.EMPTY;
    }

    private String processResponseParam1(Map<String, Object> responseObj, Map<String, ModelAttr> definitinMap) throws JsonProcessingException {
        Map<String, Map> content = (Map) responseObj.get("content");
        // if (responseObj != null && content.get("application/json") != null) {
        if (content != null) {
            Iterator<Map.Entry<String, Map>> applications = content.entrySet().iterator();
            while (applications.hasNext()) {
                Map.Entry<String, Map> application = applications.next();

                if (application.getValue() != null) {
                    Map<String, Map<String, Map>> applicationContent = (Map<String, Map<String, Map>>) application.getValue();
                    if (applicationContent != null) {
                        Map<String, Map> examples = (Map<String, Map>) applicationContent.get("examples");

                        if (examples != null) {
                            Map<String, Object> responseData = examples.get("response");

                            if (responseData != null) {
                                Object value = responseData.get("value");
                                return JsonUtils.writeJsonStr(value);
                            }
                        } else {
                            return "";
                        }

                    }
                }
            }
        }
        return StringUtils.EMPTY;
    }

    /**
     * 封装请求体
     *
     * @param list
     * @return
     */
    private String processRequestParam(List<Request> list) throws IOException {
        Map<String, Object> headerMap = new LinkedHashMap<>();
        Map<String, Object> queryMap = new LinkedHashMap<>();
        Map<String, Object> jsonMap = new LinkedHashMap<>();
        if (list != null && list.size() > 0) {
            for (Request request : list) {
                String name = request.getName();
                String paramType = request.getParamType();
                Object value = getValue(request.getType(), request.getModelAttr());
                switch (paramType) {
                    case "header":
                        headerMap.put(name, value);
                        break;
                    case "query":
                        queryMap.put(name, value);
                        break;
                    case "path":
                        queryMap.put(name, value);
                        break;
                    case "body":
                        //TODO 根据content-type序列化成不同格式,目前只用了json
                        jsonMap.put(name, value);
                        break;
                    default:
                        break;

                }
            }
        }
        String res = "";
        if (!queryMap.isEmpty()) {
            res += getUrlParamsByMap(queryMap);
        }
        if (!headerMap.isEmpty()) {
            res += " " + getHeaderByMap(headerMap);
        }
        if (!jsonMap.isEmpty()) {
            if (jsonMap.size() == 1) {
                for (Entry<String, Object> entry : jsonMap.entrySet()) {
                    res += " '" + JsonUtils.writeJsonStr(entry.getValue()) + "'";
                }
            } else {
                res += " '" + JsonUtils.writeJsonStr(jsonMap) + "'";
            }
        }
        return res;
    }

    /**
     * 例子中,字段的默认值
     *
     * @param type      类型
     * @param modelAttr 引用的类型
     * @return
     */
    private Object getValue(String type, ModelAttr modelAttr) {
        int pos;
        if ((pos = type.indexOf(":")) != -1) {
            type = type.substring(0, pos);
        }
        switch (type) {
            case "string":
                return "string";
            case "string(date-time)":
                return "2020/01/01 00:00:00";
            case "integer":
            case "integer(int64)":
            case "integer(int32)":
                return 0;
            case "number":
                return 0.0;
            case "boolean":
                return true;
            case "file":
                return "(binary)";
            case "array":
                List list = new ArrayList();
                Map<String, Object> map = new LinkedHashMap<>();
                if (modelAttr != null && !CollectionUtils.isEmpty(modelAttr.getProperties())) {
                    for (ModelAttr subModelAttr : modelAttr.getProperties()) {
                        map.put(subModelAttr.getName(), getValue(subModelAttr.getType(), subModelAttr));
                    }
                }
                list.add(map);
                return list;
            case "object":
                map = new LinkedHashMap<>();
                if (modelAttr != null && !CollectionUtils.isEmpty(modelAttr.getProperties())) {
                    for (ModelAttr subModelAttr : modelAttr.getProperties()) {
                        map.put(subModelAttr.getName(), getValue(subModelAttr.getType(), subModelAttr));
                    }
                }
                return map;
            default:
                return null;
        }
    }

    /**
     * 将map转换成url
     */
    public static String getUrlParamsByMap(Map<String, Object> map) {
        if (map == null || map.isEmpty()) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            sb.append(entry.getKey() + "=" + entry.getValue());
            sb.append("&");
        }
        String s = sb.toString();
        if (s.endsWith("&")) {
            s = StringUtils.substringBeforeLast(s, "&");
        }
        return s;
    }

    /**
     * 将map转换成header
     */
    public static String getHeaderByMap(Map<String, Object> map) {
        if (map == null || map.isEmpty()) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            sb.append("--header '");
            sb.append(entry.getKey() + ":" + entry.getValue());
            sb.append("'");
        }
        return sb.toString();
    }
}

================================================
FILE: src/main/java/org/word/service/impl/WordServiceImpl.java
================================================
package org.word.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.word.model.ModelAttr;
import org.word.model.Request;
import org.word.model.Response;
import org.word.model.Table;
import org.word.service.WordService;
import org.word.utils.JsonUtils;

import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;

/**
 * @Author XiuYin.Cui
 * @Date 2018/1/12
 **/
@SuppressWarnings({"unchecked", "rawtypes"})
@Slf4j
@Service
public class WordServiceImpl implements WordService {

    @Autowired
    private RestTemplate restTemplate;

    @Override
    public Map<String, Object> tableList(String swaggerUrl) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            String jsonStr = restTemplate.getForObject(swaggerUrl, String.class);
            resultMap = tableListFromString(jsonStr);
            log.debug(JsonUtils.writeJsonStr(resultMap));
        } catch (Exception e) {
            log.error("parse error", e);
        }
        return resultMap;
    }

    @Override
    public Map<String, Object> tableListFromString(String jsonStr) {
        Map<String, Object> resultMap = new HashMap<>();
        List<Table> result = new ArrayList<>();
        try {
            Map<String, Object> map = getResultFromString(result, jsonStr);
            Map<String, List<Table>> tableMap = result.stream().parallel().collect(Collectors.groupingBy(Table::getTitle));
            resultMap.put("tableMap", new TreeMap<>(tableMap));
            resultMap.put("info", map.get("info"));

            log.debug(JsonUtils.writeJsonStr(resultMap));
        } catch (Exception e) {
            log.error("parse error", e);
        }
        return resultMap;
    }

    @Override
    public Map<String, Object> tableList(MultipartFile jsonFile) {
        Map<String, Object> resultMap = new HashMap<>();
        List<Table> result = new ArrayList<>();
        try {
            String jsonStr = new String(jsonFile.getBytes());
            resultMap = tableListFromString(jsonStr);
            log.debug(JsonUtils.writeJsonStr(resultMap));
        } catch (Exception e) {
            log.error("parse error", e);
        }
        return resultMap;
    }

    // 处理方案一: 同一路由下所有请求方式合并为一个表格
    private Map<String, Object> getResultFromString(List<Table> result, String jsonStr) throws IOException {
        // convert JSON string to Map
        Map<String, Object> map = JsonUtils.readValue(jsonStr, HashMap.class);

        //解析model
        Map<String, ModelAttr> definitinMap = parseDefinitions(map);

        //解析paths
        Map<String, Map<String, Object>> paths = (Map<String, Map<String, Object>>) map.get("paths");
        if (paths != null) {
            Iterator<Entry<String, Map<String, Object>>> it = paths.entrySet().iterator();
            while (it.hasNext()) {
                Entry<String, Map<String, Object>> path = it.next();

                Iterator<Entry<String, Object>> it2 = path.getValue().entrySet().iterator();
                // 1.请求路径
                String url = path.getKey();

                // 2. 循环解析每个子节点,适应同一个路径几种请求方式的场景
                while (it2.hasNext()) {
                    Entry<String, Object> request = it2.next();

                    // 2. 请求方式,类似为 get,post,delete,put 这样
                    String requestType = request.getKey();

                    Map<String, Object> content = (Map<String, Object>) request.getValue();

                    // 4. 大标题(类说明)
                    String title = String.valueOf(((List) content.get("tags")).get(0));

                    // 5.小标题 (方法说明)
                    String tag = String.valueOf(content.get("summary"));

                    // 6.接口描述
                    String description = String.valueOf(content.get("summary"));

                    // 7.请求参数格式,类似于 multipart/form-data
                    String requestForm = "";
                    List<String> consumes = (List) content.get("consumes");
                    if (consumes != null && consumes.size() > 0) {
                        requestForm = StringUtils.join(consumes, ",");
                    }

                    // 8.返回参数格式,类似于 application/json
                    String responseForm = "";
                    List<String> produces = (List) content.get("produces");
                    if (produces != null && produces.size() > 0) {
                        responseForm = StringUtils.join(produces, ",");
                    }

                    // 9. 请求体
                    List<LinkedHashMap> parameters = (ArrayList) content.get("parameters");

                    // 10.返回体
                    Map<String, Object> responses = (LinkedHashMap) content.get("responses");

                    //封装Table
                    Table table = new Table();

                    table.setTitle(title);
                    table.setUrl(url);
                    table.setTag(tag);
                    table.setDescription(description);
                    table.setRequestForm(requestForm);
                    table.setResponseForm(responseForm);
                    table.setRequestType(requestType);
                    table.setRequestList(processRequestList(parameters, definitinMap));
                    table.setResponseList(processResponseCodeList(responses));

                    // 取出来状态是200时的返回值
                    Map<String, Object> obj = (Map<String, Object>) responses.get("200");
                    if (obj != null && obj.get("schema") != null) {
                        table.setModelAttr(processResponseModelAttrs(obj, definitinMap));
                    }

                    //示例
                    table.setRequestParam(processRequestParam(table.getRequestList()));
                    table.setResponseParam(processResponseParam(obj, definitinMap));

                    result.add(table);
                }
            }
        }
        return map;
    }

    //  处理方案二: 新增: 同一路由下所有请求方式单独为一个表格
    /*private Map<String, Object> getResultFromString(List<Table> result, String jsonStr) throws IOException {
        // convert JSON string to Map
        Map<String, Object> map = JsonUtils.readValue(jsonStr, HashMap.class);

        //解析model
        Map<String, ModelAttr> definitinMap = parseDefinitions(map);

        //解析paths
        Map<String, Map<String, Object>> paths = (Map<String, Map<String, Object>>) map.get("paths");

        //获取全局请求参数格式作为默认请求参数格式
        List<String> defaultConsumes = (List) map.get("consumes");

        //获取全局响应参数格式作为默认响应参数格式
        List<String> defaultProduces = (List) map.get("produces");

        if (paths != null) {

            Iterator<Entry<String, Map<String, Object>>> it = paths.entrySet().iterator();
            while (it.hasNext()) {
                Entry<String, Map<String, Object>> path = it.next();

                // 0. 获取该路由下所有请求方式的公共参数
                Map<String, Object> methods = (Map<String, Object>) path.getValue();
                List<LinkedHashMap> commonParameters = (ArrayList) methods.get("parameters");

                Iterator<Entry<String, Object>> it2 = path.getValue().entrySet().iterator();
                // 1.请求路径
                String url = path.getKey();

                while (it2.hasNext()) {
                    Entry<String, Object> request = it2.next();

                    // 2.请求方式,类似为 get,post,delete,put 这样
                    String requestType = request.getKey();

                    if ("parameters".equals(requestType)) {
                        continue;
                    }

                    Map<String, Object> content = (Map<String, Object>) request.getValue();

                    // 4. 大标题(类说明)
                    String title = String.valueOf(((List) content.get("tags")).get(0));

                    // 5.小标题 (方法说明)
                    String tag = String.valueOf(content.get("operationId"));

                    // 6.接口描述
                    String description = String.valueOf(content.get("description"));

                    // 7.请求参数格式,类似于 multipart/form-data
                    String requestForm = "";
                    List<String> consumes = (List) content.get("consumes");
                    if (consumes != null && consumes.size() > 0) {
                        requestForm = StringUtils.join(consumes, ",");
                    } else {
                        requestForm = StringUtils.join(defaultConsumes, ",");
                    }

                    // 8.返回参数格式,类似于 application/json
                    String responseForm = "";
                    List<String> produces = (List) content.get("produces");
                    if (produces != null && produces.size() > 0) {
                        responseForm = StringUtils.join(produces, ",");
                    } else {
                        responseForm = StringUtils.join(defaultProduces, ",");
                    }

                    // 9. 请求体
                    List<LinkedHashMap> parameters = (ArrayList) content.get("parameters");

                    if (!CollectionUtils.isEmpty(parameters)) {
                        if (commonParameters != null) {
                            parameters.addAll(commonParameters);
                        }
                    } else {
                        if (commonParameters != null) {
                            parameters = commonParameters;
                        }
                    }

                    // 10.返回体
                    Map<String, Object> responses = (LinkedHashMap) content.get("responses");

                    //封装Table
                    Table table = new Table();

                    table.setTitle(title);
                    table.setUrl(url);
                    table.setTag(tag);
                    table.setDescription(description);
                    table.setRequestForm(requestForm);
                    table.setResponseForm(responseForm);
                    table.setRequestType(requestType);
                    table.setRequestList(processRequestList(parameters, definitinMap));
                    table.setResponseList(processResponseCodeList(responses));

                    // 取出来状态是200时的返回值
                    Map<String, Object> obj = (Map<String, Object>) responses.get("200");
                    if (obj != null && obj.get("schema") != null) {
                        table.setModelAttr(processResponseModelAttrs(obj, definitinMap));
                    }

                    //示例
                    table.setRequestParam(processRequestParam(table.getRequestList()));
                    table.setResponseParam(processResponseParam(obj, definitinMap));

                    result.add(table);
                }
            }
        }
        return map;
    }*/

    /**
     * 处理请求参数列表
     *
     * @param parameters
     * @param definitinMap
     * @return
     */
    private List<Request> processRequestList(List<LinkedHashMap> parameters, Map<String, ModelAttr> definitinMap) {
        List<Request> requestList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(parameters)) {
            for (Map<String, Object> param : parameters) {
                Object in = param.get("in");
                Request request = new Request();
                request.setName(String.valueOf(param.get("name")));
                request.setType(param.get("type") == null ? "object" : param.get("type").toString());
                if (param.get("format") != null) {
                    request.setType(request.getType() + "(" + param.get("format") + ")");
                }
                request.setParamType(String.valueOf(in));
                // 考虑对象参数类型
                if (in != null && "body".equals(in)) {
                    request.setType(String.valueOf(in));
                    Map<String, Object> schema = (Map) param.get("schema");
                    Object ref = schema.get("$ref");
                    // 数组情况另外处理
                    if (schema.get("type") != null && "array".equals(schema.get("type"))) {
                        ref = ((Map) schema.get("items")).get("$ref");
                        request.setType("array");
                    }
                    if (ref != null) {
                        request.setType(request.getType() + ":" + ref.toString().replaceAll("#/definitions/", ""));
                        request.setModelAttr(definitinMap.get(ref));
                    }
                }
                // 是否必填
                request.setRequire(false);
                if (param.get("required") != null) {
                    request.setRequire((Boolean) param.get("required"));
                }
                // 参数说明
                request.setRemark(String.valueOf(param.get("description")));
                requestList.add(request);
            }
        }
        return requestList;
    }


    /**
     * 处理返回码列表
     *
     * @param responses 全部状态码返回对象
     * @return
     */
    private List<Response> processResponseCodeList(Map<String, Object> responses) {
        List<Response> responseList = new ArrayList<>();
        Iterator<Map.Entry<String, Object>> resIt = responses.entrySet().iterator();
        while (resIt.hasNext()) {
            Map.Entry<String, Object> entry = resIt.next();
            Response response = new Response();
            // 状态码 200 201 401 403 404 这样
            response.setName(entry.getKey());
            LinkedHashMap<String, Object> statusCodeInfo = (LinkedHashMap) entry.getValue();
            response.setDescription(String.valueOf(statusCodeInfo.get("description")));
            Object schema = statusCodeInfo.get("schema");
            if (schema != null) {
                Object originalRef = ((LinkedHashMap) schema).get("originalRef");
                response.setRemark(originalRef == null ? "" : originalRef.toString());
            }
            responseList.add(response);
        }
        return responseList;
    }

    /**
     * 处理返回属性列表
     *
     * @param responseObj
     * @param definitinMap
     * @return
     */
    private ModelAttr processResponseModelAttrs(Map<String, Object> responseObj, Map<String, ModelAttr> definitinMap) {
        Map<String, Object> schema = (Map<String, Object>) responseObj.get("schema");
        String type = (String) schema.get("type");
        String ref = null;
        //数组
        if ("array".equals(type)) {
            Map<String, Object> items = (Map<String, Object>) schema.get("items");
            if (items != null && items.get("$ref") != null) {
                ref = (String) items.get("$ref");
            }
        }
        //对象
        if (schema.get("$ref") != null) {
            ref = (String) schema.get("$ref");
        }

        //其他类型
        ModelAttr modelAttr = new ModelAttr();
        modelAttr.setType(StringUtils.defaultIfBlank(type, StringUtils.EMPTY));

        if (StringUtils.isNotBlank(ref) && definitinMap.get(ref) != null) {
            modelAttr = definitinMap.get(ref);
        }
        return modelAttr;
    }

    /**
     * 解析Definition
     *
     * @param map
     * @return
     */
    private Map<String, ModelAttr> parseDefinitions(Map<String, Object> map) {
        Map<String, Map<String, Object>> definitions = (Map<String, Map<String, Object>>) map.get("definitions");
        Map<String, ModelAttr> definitinMap = new HashMap<>(256);
        if (definitions != null) {
            Iterator<String> modelNameIt = definitions.keySet().iterator();
            while (modelNameIt.hasNext()) {
                String modeName = modelNameIt.next();
                getAndPutModelAttr(definitions, definitinMap, modeName);
            }
        }
        return definitinMap;
    }

    /**
     * 递归生成ModelAttr
     * 对$ref类型设置具体属性
     */
    private ModelAttr getAndPutModelAttr(Map<String, Map<String, Object>> swaggerMap, Map<String, ModelAttr> resMap, String modeName) {
        ModelAttr modeAttr;
        if ((modeAttr = resMap.get("#/definitions/" + modeName)) == null) {
            modeAttr = new ModelAttr();
            resMap.put("#/definitions/" + modeName, modeAttr);
        } else if (modeAttr.isCompleted()) {
            return resMap.get("#/definitions/" + modeName);
        }
        Map<String, Object> modeProperties = (Map<String, Object>) swaggerMap.get(modeName).get("properties");
        if (modeProperties == null) {
            return null;
        }

        List<ModelAttr> attrList = getModelAttrs(swaggerMap, resMap, modeAttr, modeProperties);
        List allOf = (List) swaggerMap.get(modeName).get("allOf");
        if (allOf != null) {
            for (int i = 0; i < allOf.size(); i++) {
                Map c = (Map) allOf.get(i);
                if (c.get("$ref") != null) {
                    String refName = c.get("$ref").toString();
                    //截取 #/definitions/ 后面的
                    String clsName = refName.substring(14);
                    Map<String, Object> modeProperties1 = (Map<String, Object>) swaggerMap.get(clsName).get("properties");
                    List<ModelAttr> attrList1 = getModelAttrs(swaggerMap, resMap, modeAttr, modeProperties1);
                    if (attrList1 != null && attrList != null) {
                        attrList.addAll(attrList1);
                    } else if (attrList == null && attrList1 != null) {
                        attrList = attrList1;
                    }
                }
            }
        }

        Object title = swaggerMap.get(modeName).get("title");
        Object description = swaggerMap.get(modeName).get("description");
        modeAttr.setClassName(title == null ? "" : title.toString());
        modeAttr.setDescription(description == null ? "" : description.toString());
        modeAttr.setProperties(attrList);
        Object required = swaggerMap.get(modeName).get("required");
        if (Objects.nonNull(required)) {
            if ((required instanceof List) && !CollectionUtils.isEmpty(attrList)) {
                List requiredList = (List) required;
                attrList.stream().filter(m -> requiredList.contains(m.getName())).forEach(m -> m.setRequire(true));
            } else if (required instanceof Boolean) {
                modeAttr.setRequire(Boolean.parseBoolean(required.toString()));
            }
        }
        return modeAttr;
    }

    private List<ModelAttr> getModelAttrs(Map<String, Map<String, Object>> swaggerMap, Map<String, ModelAttr> resMap, ModelAttr modeAttr, Map<String, Object> modeProperties) {
        Iterator<Entry<String, Object>> mIt = modeProperties.entrySet().iterator();

        List<ModelAttr> attrList = new ArrayList<>();

        //解析属性
        while (mIt.hasNext()) {
            Entry<String, Object> mEntry = mIt.next();
            Map<String, Object> attrInfoMap = (Map<String, Object>) mEntry.getValue();
            ModelAttr child = new ModelAttr();
            child.setName(mEntry.getKey());
            child.setType((String) attrInfoMap.get("type"));
            if (attrInfoMap.get("format") != null) {
                child.setType(child.getType() + "(" + attrInfoMap.get("format") + ")");
            }
            child.setType(StringUtils.defaultIfBlank(child.getType(), "object"));

            Object ref = attrInfoMap.get("$ref");
            Object items = attrInfoMap.get("items");
            if (ref != null || (items != null && (ref = ((Map) items).get("$ref")) != null)) {
                String refName = ref.toString();
                //截取 #/definitions/ 后面的
                String clsName = refName.substring(14);
                modeAttr.setCompleted(true);
                ModelAttr refModel = getAndPutModelAttr(swaggerMap, resMap, clsName);
                if (refModel != null) {
                    child.setProperties(refModel.getProperties());
                }
                child.setType(child.getType() + ":" + clsName);
            }
            child.setDescription((String) attrInfoMap.get("description"));
            attrList.add(child);
        }
        return attrList;
    }

    /**
     * 处理返回值
     *
     * @param responseObj
     * @return
     */
    private String processResponseParam(Map<String, Object> responseObj, Map<String, ModelAttr> definitinMap) throws JsonProcessingException {
        if (responseObj != null && responseObj.get("schema") != null) {
            Map<String, Object> schema = (Map<String, Object>) responseObj.get("schema");
            String type = (String) schema.get("type");
            String ref = null;
            // 数组
            if ("array".equals(type)) {
                Map<String, Object> items = (Map<String, Object>) schema.get("items");
                if (items != null && items.get("$ref") != null) {
                    ref = (String) items.get("$ref");
                }
            }
            // 对象
            if (schema.get("$ref") != null) {
                ref = (String) schema.get("$ref");
            }
            if (StringUtils.isNotEmpty(ref)) {
                ModelAttr modelAttr = definitinMap.get(ref);
                if (modelAttr != null && !CollectionUtils.isEmpty(modelAttr.getProperties())) {
                    Map<String, Object> responseMap = new HashMap<>(8);
                    for (ModelAttr subModelAttr : modelAttr.getProperties()) {
                        responseMap.put(subModelAttr.getName(), getValue(subModelAttr.getType(), subModelAttr));
                    }
                    return JsonUtils.writeJsonStr(responseMap);
                }
            }
        }
        return StringUtils.EMPTY;
    }

    /**
     * 封装请求体
     *
     * @param list
     * @return
     */
    private String processRequestParam(List<Request> list) throws IOException {
        Map<String, Object> headerMap = new LinkedHashMap<>();
        Map<String, Object> queryMap = new LinkedHashMap<>();
        Map<String, Object> jsonMap = new LinkedHashMap<>();
        if (list != null && list.size() > 0) {
            for (Request request : list) {
                String name = request.getName();
                String paramType = request.getParamType();
                Object value = getValue(request.getType(), request.getModelAttr());
                switch (paramType) {
                    case "header":
                        headerMap.put(name, value);
                        break;
                    case "query":
                        queryMap.put(name, value);
                        break;
                    case "body":
                        //TODO 根据content-type序列化成不同格式,目前只用了json
                        jsonMap.put(name, value);
                        break;
                    default:
                        break;

                }
            }
        }
        String res = "";
        if (!queryMap.isEmpty()) {
            res += getUrlParamsByMap(queryMap);
        }
        if (!headerMap.isEmpty()) {
            res += " " + getHeaderByMap(headerMap);
        }
        if (!jsonMap.isEmpty()) {
            if (jsonMap.size() == 1) {
                for (Entry<String, Object> entry : jsonMap.entrySet()) {
                    res += " -d '" + JsonUtils.writeJsonStr(entry.getValue()) + "'";
                }
            } else {
                res += " -d '" + JsonUtils.writeJsonStr(jsonMap) + "'";
            }
        }
        return res;
    }

    /**
     * 例子中,字段的默认值
     *
     * @param type      类型
     * @param modelAttr 引用的类型
     * @return
     */
    private Object getValue(String type, ModelAttr modelAttr) {
        int pos;
        if ((pos = type.indexOf(":")) != -1) {
            type = type.substring(0, pos);
        }
        switch (type) {
            case "string":
                return "string";
            case "string(date-time)":
                return "2020/01/01 00:00:00";
            case "integer":
            case "integer(int64)":
            case "integer(int32)":
                return 0;
            case "number":
                return 0.0;
            case "boolean":
                return true;
            case "file":
                return "(binary)";
            case "array":
                List list = new ArrayList();
                Map<String, Object> map = new LinkedHashMap<>();
                if (modelAttr != null && !CollectionUtils.isEmpty(modelAttr.getProperties())) {
                    for (ModelAttr subModelAttr : modelAttr.getProperties()) {
                        map.put(subModelAttr.getName(), getValue(subModelAttr.getType(), subModelAttr));
                    }
                }
                list.add(map);
                return list;
            case "object":
                map = new LinkedHashMap<>();
                if (modelAttr != null && !CollectionUtils.isEmpty(modelAttr.getProperties())) {
                    for (ModelAttr subModelAttr : modelAttr.getProperties()) {
                        map.put(subModelAttr.getName(), getValue(subModelAttr.getType(), subModelAttr));
                    }
                }
                return map;
            default:
                return null;
        }
    }

    /**
     * 将map转换成url
     */
    public static String getUrlParamsByMap(Map<String, Object> map) {
        if (CollectionUtils.isEmpty(map)) {
            return "";
        }
        StringBuilder sBuilder = new StringBuilder();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            sBuilder.append(entry.getKey() + "=" + entry.getValue());
            sBuilder.append("&");
        }
        String s = sBuilder.toString();
        if (s.endsWith("&")) {
            s = StringUtils.substringBeforeLast(s, "&");
        }
        return s;
    }

    /**
     * 将map转换成header
     */
    public static String getHeaderByMap(Map<String, Object> map) {
        if (CollectionUtils.isEmpty(map)) {
            return "";
        }
        StringBuilder sBuilder = new StringBuilder();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            sBuilder.append("--header '");
            sBuilder.append(entry.getKey() + ":" + entry.getValue());
            sBuilder.append("'");
        }
        return sBuilder.toString();
    }
}


================================================
FILE: src/main/java/org/word/utils/JsonUtils.java
================================================
package org.word.utils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

import java.io.IOException;
import java.util.List;

/**
 * @author cuixiuyin
 * @Date: 2018/11/05
 */

public class JsonUtils {

    private static ObjectMapper objectMapper = new ObjectMapper();

    static {
        objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
    }

    public static <T> T readValue(String jsonStr, Class<T> clazz) throws IOException {
        return objectMapper.readValue(jsonStr, clazz);
    }

    public static <T> List<T> readListValue(String jsonStr, Class<T> clazz) throws IOException {
        JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class, clazz);
        return objectMapper.readValue(jsonStr, javaType);
    }

    public static ArrayNode readArray(String jsonStr) throws IOException {
        JsonNode node = objectMapper.readTree(jsonStr);
        if (node.isArray()) {
            return (ArrayNode) node;
        }
        return null;
    }

    public static JsonNode readNode(String jsonStr) throws IOException {
        return objectMapper.readTree(jsonStr);
    }

    public static String writeJsonStr(Object obj) throws JsonProcessingException {
        return objectMapper.writeValueAsString(obj);
    }

    public static ObjectNode createObjectNode() {
        return objectMapper.createObjectNode();
    }

    public static ArrayNode createArrayNode() {
        return objectMapper.createArrayNode();
    }

}


================================================
FILE: src/main/java/org/word/utils/MenuUtils.java
================================================
package org.word.utils;

/**
 * @author : cuixiuyin
 * @date : 2019/8/31
 */
public class MenuUtils {

    public static Integer count = 0;
    public static String menuStr = "null";

    public static boolean isMenu(String tags) {
        if (menuStr.equals(tags)) {
            count++;
        } else {
            menuStr = tags;
            count = 0;
        }
        if (count == 0) {
            return true;
        } else {
            return false;
        }
    }
}


================================================
FILE: src/main/java/org/word/utils/ModelAttrUtils.java
================================================
package org.word.utils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.StringUtils;
import org.word.model.ModelAttr;

/**
 * @author ivenhan
 * @Date: 2020/10/15
 */

public class ModelAttrUtils {

	// 封装schema - properties下某个具体property对象
    public static ModelAttr propertyModelAttr(Map<String, Map<String, Object>> property) {
    	ModelAttr modeAttr = new ModelAttr();

        Map<String, Object> modeProperties = (Map<String, Object>) property.get("properties");
        ArrayList modeRequired = (ArrayList) property.get("required");
        List<ModelAttr> attrList = new ArrayList<>();

    	if (modeProperties != null) {
        	Iterator<Entry<String, Object>> mIt = modeProperties.entrySet().iterator();

            //解析属性
            while (mIt.hasNext()) {
                Entry<String, Object> mEntry = mIt.next();
                Map<String, Object> attrInfoMap = (Map<String, Object>) mEntry.getValue();
                ModelAttr child = new ModelAttr();
                child.setName(mEntry.getKey());
                child.setType((String) attrInfoMap.get("type"));
                if (attrInfoMap.get("format") != null) {
                    child.setType(child.getType() + "(" + attrInfoMap.get("format") + ")");
                }
                child.setType(StringUtils.defaultIfBlank(child.getType(), "object"));

                Object ref = attrInfoMap.get("$ref");
                Object items = attrInfoMap.get("items");

                if (items != null && ((Map) items).get("$ref") == null) {
            		ModelAttr refModel = propertyModelAttr((Map<String, Map<String, Object>>)items);
					if (refModel != null) {
					    child.setProperties(refModel.getProperties());
					}
					child.setType(child.getType());
                }

                child.setDescription((String) attrInfoMap.get("description"));

                child.setRequire(false);
                if (modeRequired != null && modeRequired.contains(mEntry.getKey())) {
                    child.setRequire(true);
                }

                attrList.add(child);
            }
        }

        Object title = property.get("title");
        Object description = property.get("description");
        modeAttr.setClassName(title == null ? "" : title.toString());
        modeAttr.setDescription(description == null ? "" : description.toString());
        modeAttr.setProperties(attrList);
        return modeAttr;
    }
}

================================================
FILE: src/main/java/org/word/utils/RequestUtils.java
================================================
package org.word.utils;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.fasterxml.jackson.core.JsonProcessingException;


/**
 * @author : ivenhan
 * @date : 2020/10/16
 */
public class RequestUtils {

    public static void validateRequestKey(Map<String, Map> content) throws JsonProcessingException {
		Map<String, Map> applicationJSON = content.get("application/json");
        if (applicationJSON == null) {
        	throw new JsonProcessingException("content字段 缺少 application/json 字段") {};
        }

        Map<String, Map> schema = applicationJSON.get("schema");
        if (schema == null) {
        	throw new JsonProcessingException("content字段 application/json 缺少 schema 字段") {};
        }

        if (schema.get("type") == null) {
        	throw new JsonProcessingException("content字段 application/json 字段 schema 字段 缺少 type字段") {};
        }
    }
}

================================================
FILE: src/main/java/org/word/utils/ResponseUtils.java
================================================
package org.word.utils;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.fasterxml.jackson.core.JsonProcessingException;

/**
 * @author : ivenhan
 * @date : 2020/10/16
 */
public class ResponseUtils {

    public static void validateResponseKey(Map<String, Map> content) throws JsonProcessingException {
		Map<String, Map> applicationJSON = content.get("application/json");
        if (applicationJSON == null) {
        	throw new JsonProcessingException("content 字段缺少 application/json 字段") {};
        }

        Map<String, Map> schema = applicationJSON.get("schema");
        if (schema == null) {
        	throw new JsonProcessingException("content 字段 application/json 字段 缺少 schema 字段") {};
        }

        if (schema.get("type") == null) {
        	throw new JsonProcessingException("content 字段 application/json 字段 schema 字段 缺少 type字段") {};
        }

        Map items = schema.get("items");
        Map properties = schema.get("properties");
        if (items == null && properties == null) {
        	throw new JsonProcessingException("content 字段 application/json 字段 schema 字段 缺少  properties 或者 items 字段") {};
        }


        Set<Entry<String, Map>> contentValues = content.entrySet();

        int size = contentValues.size();
        if ((applicationJSON.get("examples") != null && size > 2) || (applicationJSON.get("examples") == null && size > 1) ) {
        	throw new JsonProcessingException("content 字段存在除 application/json 或者 examples 字段之外的其他字段") {};
        }
    }
}

================================================
FILE: src/main/resources/application.yml
================================================
server:
  port: 8080
  tomcat:
    max-threads: 800
    uri-encoding: UTF-8

spring:
  application:
    name: swagger2word
  thymeleaf:
    prefix: classpath:/templates/
    suffix: .html
    cache: false
    servlet:
      content-type: text/html
    enabled: true
    encoding: UTF-8
    mode: HTML5
  servlet:
    multipart:
      enabled: true
      max-file-size: 50MB
      max-request-size: 50MB
# Swagger json url address
# etc. https://petstore.swagger.io/
swagger.url: https://petstore.swagger.io/v2/swagger.json









================================================
FILE: src/main/resources/logback.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>

    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
    </root>

</configuration>

================================================
FILE: src/main/resources/templates/index.html
================================================
<!DOCTYPE html>
<html>
<body>
<h2>Hello Swagger2word !</h2>
</body>
</html>


================================================
FILE: src/main/resources/templates/word-en_US.html
================================================
<!-- 2020/12/11 - Olivier Bretteville
    English locale
-->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="application/msword; charset=utf-8"/>
    <title>toWord</title>
        <style type="text/css">
        .bg {
            font-family: "Verdana", sans-serif;
            font-size: 14.5px;
            font-weight: bold;
            color: #fff;
            background-color: #00A6D9;
        }

        table {
            border-width: 1px;
            border-style: solid;
            border-color: black;
            table-layout: fixed;
        }

        tr {
            height: 32px;
            font-size: 12px;
        }

        td {
            padding-left: 10px;
            border-width: 1px;
            border-style: solid;
            border-color: black;
            height: 32px;
            overflow: hidden;
            word-break: break-all;
            word-wrap: break-word;
            font-size: 14.5px;
        }

        .bg td {
            font-size: 14.5px;
        }

        tr td {
            font-size: 14.5px;
        }

        .specialHeight {
            height: 40px;
        }

        .first_title {
            height: 60px;
            line-height: 60px;
            margin: 0;
            font-weight: bold;
            font-size: 21px;
        }

        .second_title {
            height: 40px;
            line-height: 40px;
            margin: 0;
            font-size: 18.5px;
        }

        .doc_title {
            font-size: 42.5px;
            text-align: center;
        }

        .download_btn {
            float: right;
        }

        body {
            font-family: Sans-serif;
        }
    </style>
</head>

<body>
<div style="width:1000px; margin: 0 auto">
    <div>
        <p class="doc_title" th:text="${info.title +'('+ info.version +')'}"></p>
        <a class="download_btn" th:if="${download == 1}" th:href="${'/downloadWord?url='+ url}">Download</a>
        <br>
    </div>
    <div th:each="tableMap:${tableMap}" style="margin-bottom:20px;">
        <!--这个是类的说明-->
        <h4 class="first_title" th:text="${tableMap.key}"></h4>
        <div th:each="table,tableStat:${tableMap.value}">

            <!--这个是每个请求的说明,方便生成文档后进行整理-->
            <h5 class="second_title" th:text="${tableStat.count} + ')' + ${table.tag}"></h5>

            <table border="1" cellspacing="0" cellpadding="0" width="100%">
                <tr class="bg">
                    <td colspan="8" th:text="${table.tag}"></td>
                </tr>
                <tr>
                    <td colspan="2" width="25%">Description de l'interface</td>
                    <td colspan="6" th:text="${table.description}"></td>
                </tr>
                <tr>
                    <td colspan="2">URL</td>
                    <td colspan="6" th:text="${table.url}"></td>
                </tr>
                <tr>
                    <td colspan="2">HTTP verb</td>
                    <td colspan="6" th:text="${table.requestType}"></td>
                </tr>
                <tr>
                    <td colspan="2">Content type</td>
                    <td colspan="6" th:text="${table.requestForm}"></td>
                </tr>
                <tr>
                    <td colspan="2">Response type</td>
                    <td colspan="6" th:text="${table.responseForm}"></td>
                </tr>

                <tr class="bg">
                    <td colspan="2">Parameter name</td>
                    <td colspan="2">Type</td>
                    <td colspan="1">Location</td>
                    <td colspan="1">Mandatory</td>
                    <td colspan="2">Description</td>
                </tr>

                <th:block th:each="request, c:${table.requestList}">
                    <tr>
                        <td colspan="2" align="left" th:text="${c.count} + '.' + ${request.name}"></td>
                        <td colspan="2" th:text="${request.type}"></td>
                        <td colspan="1" th:text="${request.paramType}"></td>
                        <td colspan="1" th:if="${request.require}" th:text="yes"></td>
                        <td colspan="1" th:if="${!request.require}" th:text="no"></td>
                        <td colspan="2" style="width:40%" th:text="${request.remark}"></td>
                        <!--                        <td th:if="${request.modelAttr}" th:text="asdfagadfg"></td>-->
                    </tr>
                    <th:block th:if="${request.modelAttr}">
                        <tbody th:include="this::request(${request.modelAttr.properties},${c.count} + '.', 1)"/>
                    </th:block>


                </th:block>

                <tr class="bg">
                    <td colspan="2">Return code</td>
                    <td colspan="3">Description</td>
                    <td colspan="3">Comment</td>
                </tr>

                <tr th:each="response:${table.responseList}">
                    <td colspan="2" th:text="${response.name}"></td>
                    <td colspan="3" th:text="${response.description}"></td>
                    <td colspan="3" th:text="${response.remark}"></td>
                </tr>

                <tr class="bg">
                    <td colspan="2">Response format</td>
                    <td colspan="3">Type</td>
                    <td colspan="3">Description</td>
                </tr>

<!--               对返回参数 递归生成行-->
                <tbody th:include="this::response(${table.modelAttr.properties},'', 1)"/>

                <tr class="bg">
                    <td colspan="8">Example</td>
                </tr>
                <tr class="specialHeight">
                    <td class="bg">Request</td>
                    <td colspan="7" th:text="${table.requestParam}"></td>
                </tr>
                <tr class="specialHeight">
                    <td class="bg">Response</td>
                    <td colspan="7" th:text="${table.responseParam}"></td>
                </tr>

            </table>
            <br/>
        </div>
    </div>
</div>

<th:block th:fragment="request(properties,count, lv)">
    <th:block th:each="p,c : ${properties}">
        <tr>
            <td colspan="2" align="left" th:text="${count} + '' + ${c.count} + '.' + ${p.name}"
                th:style="|padding-left:${10*lv}px|"></td>
            <td colspan="2" th:text="${p.type}"></td>
            <td></td>
            <td th:if="${p.require}" th:text="yes"></td>
            <td th:if="${!p.require}" th:text="no"></td>
            <td colspan="2" th:text="${p.description}"></td>
        </tr>
        <th:block th:unless="${#lists.isEmpty(p.properties)}"
                  th:include="this::request(${p.properties},${count} + '' + ${c.count} + '.',${lv+1})"/>
    </th:block>
</th:block>

<th:block th:fragment="response(properties,count, lv)">
    <th:block th:each="p,c : ${properties}">
        <tr>
            <td colspan="2" align="left" th:text="${count} + '' + ${c.count} + '.' + ${p.name}"
                th:style="|padding-left:${10*lv}px|"></td>
            <td colspan="2" th:text="${p.type}"></td>
            <td colspan="4" th:text="${p.description}"></td>
        </tr>
        <th:block th:unless="${#lists.isEmpty(p.properties)}"
                  th:include="this::response(${p.properties},${count} + '' + ${c.count} + '.',${lv+1})"/>
    </th:block>
</th:block>
</body>
</html>


================================================
FILE: src/main/resources/templates/word-fr_FR.html
================================================
<!-- 2020/12/11 - Olivier Bretteville
    French locale
-->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="application/msword; charset=utf-8"/>
    <title>toWord</title>
        <style type="text/css">
        .bg {
            font-family: "Verdana", sans-serif;
            font-size: 14.5px;
            font-weight: bold;
            color: #fff;
            background-color: #00A6D9;
        }

        table {
            border-width: 1px;
            border-style: solid;
            border-color: black;
            table-layout: fixed;
        }

        tr {
            height: 32px;
            font-size: 12px;
        }

        td {
            padding-left: 10px;
            border-width: 1px;
            border-style: solid;
            border-color: black;
            height: 32px;
            overflow: hidden;
            word-break: break-all;
            word-wrap: break-word;
            font-size: 14.5px;
        }

        .bg td {
            font-size: 14.5px;
        }

        tr td {
            font-size: 14.5px;
        }

        .specialHeight {
            height: 40px;
        }

        .first_title {
            height: 60px;
            line-height: 60px;
            margin: 0;
            font-weight: bold;
            font-size: 21px;
        }

        .second_title {
            height: 40px;
            line-height: 40px;
            margin: 0;
            font-size: 18.5px;
        }

        .doc_title {
            font-size: 42.5px;
            text-align: center;
        }

        .download_btn {
            float: right;
        }

        body {
            font-family: Sans-serif;
        }
    </style>
</head>

<body>
<div style="width:1000px; margin: 0 auto">
    <div>
        <p class="doc_title" th:text="${info.title +'('+ info.version +')'}"></p>
        <a class="download_btn" th:if="${download == 1}" th:href="${'/downloadWord?url='+ url}">Télécharger</a>
        <br>
    </div>
    <div th:each="tableMap:${tableMap}" style="margin-bottom:20px;">
        <!--这个是类的说明-->
        <h4 class="first_title" th:text="${tableMap.key}"></h4>
        <div th:each="table,tableStat:${tableMap.value}">

            <!--这个是每个请求的说明,方便生成文档后进行整理-->
            <h5 class="second_title" th:text="${tableStat.count} + ')' + ${table.tag}"></h5>

            <table border="1" cellspacing="0" cellpadding="0" width="100%">
                <tr class="bg">
                    <td colspan="8" th:text="${table.tag}"></td>
                </tr>
                <tr>
                    <td colspan="2" width="25%">Description de l'interface</td>
                    <td colspan="6" th:text="${table.description}"></td>
                </tr>
                <tr>
                    <td colspan="2">URL</td>
                    <td colspan="6" th:text="${table.url}"></td>
                </tr>
                <tr>
                    <td colspan="2">Verbe HTTP</td>
                    <td colspan="6" th:text="${table.requestType}"></td>
                </tr>
                <tr>
                    <td colspan="2">Type de requête</td>
                    <td colspan="6" th:text="${table.requestForm}"></td>
                </tr>
                <tr>
                    <td colspan="2">Type de retour</td>
                    <td colspan="6" th:text="${table.responseForm}"></td>
                </tr>

                <tr class="bg">
                    <td colspan="2">Nom du paramètre</td>
                    <td colspan="2">Type</td>
                    <td colspan="1">Emplacement</td>
                    <td colspan="1">Obligatoire</td>
                    <td colspan="2">Description</td>
                </tr>

                <th:block th:each="request, c:${table.requestList}">
                    <tr>
                        <td colspan="2" align="left" th:text="${c.count} + '.' + ${request.name}"></td>
                        <td colspan="2" th:text="${request.type}"></td>
                        <td colspan="1" th:text="${request.paramType}"></td>
                        <td colspan="1" th:if="${request.require}" th:text="oui"></td>
                        <td colspan="1" th:if="${!request.require}" th:text="non"></td>
                        <td colspan="2" style="width:40%" th:text="${request.remark}"></td>
                        <!--                        <td th:if="${request.modelAttr}" th:text="asdfagadfg"></td>-->
                    </tr>
                    <th:block th:if="${request.modelAttr}">
                        <tbody th:include="this::request(${request.modelAttr.properties},${c.count} + '.', 1)"/>
                    </th:block>


                </th:block>

                <tr class="bg">
                    <td colspan="2">Code retour</td>
                    <td colspan="3">Description</td>
                    <td colspan="3">Commentaire</td>
                </tr>

                <tr th:each="response:${table.responseList}">
                    <td colspan="2" th:text="${response.name}"></td>
                    <td colspan="3" th:text="${response.description}"></td>
                    <td colspan="3" th:text="${response.remark}"></td>
                </tr>

                <tr class="bg">
                    <td colspan="2">Format de la réponse</td>
                    <td colspan="3">Type</td>
                    <td colspan="3">Description</td>
                </tr>

<!--               对返回参数 递归生成行-->
                <tbody th:include="this::response(${table.modelAttr.properties},'', 1)"/>

                <tr class="bg">
                    <td colspan="8">Exemple</td>
                </tr>
                <tr class="specialHeight">
                    <td class="bg">Requête</td>
                    <td colspan="7" th:text="${table.requestParam}"></td>
                </tr>
                <tr class="specialHeight">
                    <td class="bg">Résultat</td>
                    <td colspan="7" th:text="${table.responseParam}"></td>
                </tr>

            </table>
            <br/>
        </div>
    </div>
</div>

<th:block th:fragment="request(properties,count, lv)">
    <th:block th:each="p,c : ${properties}">
        <tr>
            <td colspan="2" align="left" th:text="${count} + '' + ${c.count} + '.' + ${p.name}"
                th:style="|padding-left:${10*lv}px|"></td>
            <td colspan="2" th:text="${p.type}"></td>
            <td></td>
            <td th:if="${p.require}" th:text="oui"></td>
            <td th:if="${!p.require}" th:text="non"></td>
            <td colspan="2" th:text="${p.description}"></td>
        </tr>
        <th:block th:unless="${#lists.isEmpty(p.properties)}"
                  th:include="this::request(${p.properties},${count} + '' + ${c.count} + '.',${lv+1})"/>
    </th:block>
</th:block>

<th:block th:fragment="response(properties,count, lv)">
    <th:block th:each="p,c : ${properties}">
        <tr>
            <td colspan="2" align="left" th:text="${count} + '' + ${c.count} + '.' + ${p.name}"
                th:style="|padding-left:${10*lv}px|"></td>
            <td colspan="2" th:text="${p.type}"></td>
            <td colspan="4" th:text="${p.description}"></td>
        </tr>
        <th:block th:unless="${#lists.isEmpty(p.properties)}"
                  th:include="this::response(${p.properties},${count} + '' + ${c.count} + '.',${lv+1})"/>
    </th:block>
</th:block>
</body>
</html>


================================================
FILE: src/main/resources/templates/word-zh_CN.html
================================================
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="application/msword; charset=utf-8"/>
    <title>toWord</title>
        <style type="text/css">
        .bg {
            font-size: 14.5px;
            font-weight: bold;
            color: #000;
            background-color: #559e68;
        }

        table {
            border-width: 1px;
            border-style: solid;
            border-color: black;
            table-layout: fixed;
        }

        tr {
            height: 32px;
            font-size: 12px;
        }

        td {
            padding-left: 10px;
            border-width: 1px;
            border-style: solid;
            border-color: black;
            height: 32px;
            overflow: hidden;
            word-break: break-all;
            word-wrap: break-word;
            font-size: 14.5px;
        }

        .bg td {
            font-size: 14.5px;
        }

        tr td {
            font-size: 14.5px;
        }

        .specialHeight {
            height: 40px;
        }

        .first_title {
            height: 60px;
            line-height: 60px;
            margin: 0;
            font-weight: bold;
            font-size: 21px;
        }

        .second_title {
            height: 40px;
            line-height: 40px;
            margin: 0;
            font-size: 18.5px;
        }

        .doc_title {
            font-size: 42.5px;
            text-align: center;
        }

        .download_btn {
            float: right;
        }

        body {
            font-family: 思源黑体 Normal;
        }
    </style>
</head>

<body>
<div style="width:1000px; margin: 0 auto">
    <div>
        <p class="doc_title" th:text="${info.title +'('+ info.version +')'}"></p>
        <a class="download_btn" th:if="${download == 1}" th:href="${'/downloadWord?url='+ url}">下载文档</a>
        <br>
    </div>
    <div th:each="tableMap:${tableMap}" style="margin-bottom:20px;">
        <!--这个是类的说明-->
        <h4 class="first_title" th:text="${tableMap.key}"></h4>
        <div th:each="table,tableStat:${tableMap.value}">

            <!--这个是每个请求的说明,方便生成文档后进行整理-->
            <h5 class="second_title" th:text="${tableStat.count} + ')' + ${table.tag}"></h5>

            <table border="1" cellspacing="0" cellpadding="0" width="100%">
                <tr class="bg">
                    <td colspan="5" th:text="${table.tag}"></td>
                </tr>
                <tr>
                    <td width="25%">接口描述</td>
                    <td colspan="4" th:text="${table.description}"></td>
                </tr>
                <tr>
                    <td>URL</td>
                    <td colspan="4" th:text="${table.url}"></td>
                </tr>
                <tr>
                    <td>请求方式</td>
                    <td colspan="4" th:text="${table.requestType}"></td>
                </tr>
                <tr>
                    <td>请求类型</td>
                    <td colspan="4" th:text="${table.requestForm}"></td>
                </tr>
                <tr>
                    <td>返回类型</td>
                    <td colspan="4" th:text="${table.responseForm}"></td>
                </tr>

                <tr class="bg">
                    <td>参数名</td>
                    <td width="15%">数据类型</td>
                    <td width="15%">参数类型</td>
                    <td width="15%">是否必填</td>
                    <td width="29%">说明</td>
                </tr>

                <th:block th:each="request, c:${table.requestList}">
                    <tr>
                        <td align="left" th:text="${c.count} + '.' + ${request.name}"></td>
                        <td th:text="${request.type}"></td>
                        <td th:text="${request.paramType}"></td>
                        <td th:if="${request.require}" th:text="Y"></td>
                        <td th:if="${!request.require}" th:text="N"></td>
                        <td th:text="${request.remark}"></td>
                        <!--                        <td th:if="${request.modelAttr}" th:text="asdfagadfg"></td>-->
                    </tr>
                    <th:block th:if="${request.modelAttr}">
                        <tbody th:include="this::request(${request.modelAttr.properties},${c.count} + '.', 1)"/>
                    </th:block>


                </th:block>

                <tr class="bg">
                    <td>状态码</td>
                    <td colspan="2">描述</td>
                    <td colspan="2">说明</td>
                </tr>

                <tr th:each="response:${table.responseList}">
                    <td th:text="${response.name}"></td>
                    <td colspan="2" th:text="${response.description}"></td>
                    <td colspan="2" th:text="${response.remark}"></td>
                </tr>

                <tr class="bg">
                    <td>返回属性名</td>
                    <td colspan="2">类型</td>
                    <td colspan="2">说明</td>
                </tr>

<!--               对返回参数 递归生成行-->
                <tbody th:include="this::response(${table.modelAttr.properties},'', 1)"/>

                <tr class="bg">
                    <td colspan="5">示例</td>
                </tr>
                <tr class="specialHeight">
                    <td class="bg">请求参数</td>
                    <td colspan="4" th:text="${table.requestParam}"></td>
                </tr>
                <tr class="specialHeight">
                    <td class="bg">返回值</td>
                    <td colspan="4" th:text="${table.responseParam}"></td>
                </tr>

            </table>
        </div>
    </div>
</div>

<th:block th:fragment="request(properties,count, lv)">
    <th:block th:each="p,c : ${properties}">
        <tr>
            <td align="left" th:text="${count} + '' + ${c.count} + '.' + ${p.name}"
                th:style="|padding-left:${10*lv}px|"></td>
            <td th:text="${p.type}"></td>
            <td></td>
            <td th:if="${p.require}" th:text="Y"></td>
            <td th:if="${!p.require}" th:text="N"></td>
            <td th:text="${p.description}"></td>
        </tr>
        <th:block th:unless="${#lists.isEmpty(p.properties)}"
                  th:include="this::request(${p.properties},${count} + '' + ${c.count} + '.',${lv+1})"/>
    </th:block>
</th:block>

<th:block th:fragment="response(properties,count, lv)">
    <th:block th:each="p,c : ${properties}">
        <tr>
            <td align="left" th:text="${count} + '' + ${c.count} + '.' + ${p.name}"
                th:style="|padding-left:${10*lv}px|"></td>
            <td colspan="2" th:text="${p.type}"></td>
            <td colspan="2" th:text="${p.description}"></td>
        </tr>
        <th:block th:unless="${#lists.isEmpty(p.properties)}"
                  th:include="this::response(${p.properties},${count} + '' + ${c.count} + '.',${lv+1})"/>
    </th:block>
</th:block>
</body>
</html>


================================================
FILE: src/main/resources/templates/word.html
================================================
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="application/msword; charset=utf-8"/>
    <title>toWord</title>
    <style type="text/css">
        .bg {
            font-size: 14.5px;
            font-weight: bold;
            color: #000;
            background-color: #559e68;
        }

        table {
            border-width: 1px;
            border-style: solid;
            border-color: black;
            table-layout: fixed;
        }

        tr {
            height: 32px;
            font-size: 12px;
        }

        td {
            padding-left: 10px;
            border-width: 1px;
            border-style: solid;
            border-color: black;
            height: 32px;
            overflow: hidden;
            word-break: break-all;
            word-wrap: break-word;
            font-size: 14.5px;
        }

        .bg td {
            font-size: 14.5px;
        }

        tr td {
            font-size: 14.5px;
        }

        .specialHeight {
            height: 40px;
        }

        .first_title {
            height: 60px;
            line-height: 60px;
            margin: 0;
            font-weight: bold;
            font-size: 21px;
        }

        .second_title {
            height: 40px;
            line-height: 40px;
            margin: 0;
            font-size: 18.5px;
        }

        .doc_title {
            font-size: 42.5px;
            text-align: center;
        }

        .download_btn {
            float: right;
        }

        body {
            font-family: 思源黑体 Normal;
        }
    </style>
</head>

<body>
<div style="width:800px; margin: 0 auto">
    <div>
        <p class="doc_title" th:text="${info.title +'('+ info.version +')'}"></p>
        <a class="download_btn" th:if="${download == 1}" th:href="${'/downloadWord?url='+ url}">下载文档</a>
        <br>
    </div>
    <div th:each="tableMap:${tableMap}" style="margin-bottom:20px;">
        <!--这个是类的说明-->
        <h4 class="first_title" th:text="${tableMap.key}"></h4>
        <div th:each="table,tableStat:${tableMap.value}">

            <!--这个是每个请求的说明,方便生成文档后进行整理-->
            <h5 class="second_title" th:text="${tableStat.count} + ')' + ${table.tag}"></h5>

            <table border="1" cellspacing="0" cellpadding="0" width="100%">
                <tr class="bg">
                    <td colspan="5" th:text="${table.tag}"></td>
                </tr>
                <tr>
                    <td width="25%">接口描述</td>
                    <td colspan="4" th:text="${table.description}"></td>
                </tr>
                <tr>
                    <td>URL</td>
                    <td colspan="4" th:text="${table.url}"></td>
                </tr>
                <tr>
                    <td>请求方式</td>
                    <td colspan="4" th:text="${#strings.toUpperCase(table.requestType)}"></td>
                </tr>
                <tr>
                    <td>请求类型</td>
                    <td colspan="4" th:text="${table.requestForm}"></td>
                </tr>
                <tr>
                    <td>返回类型</td>
                    <td colspan="4" th:text="${table.responseForm}"></td>
                </tr>

                <tr class="bg">
                    <td>参数名</td>
                    <td width="15%">数据类型</td>
                    <td width="15%">参数类型</td>
                    <td width="15%">是否必填</td>
                    <td width="29%">说明</td>
                </tr>

                <th:block th:each="request, c:${table.requestList}">
                    <tr>
                        <td align="left" th:text="${c.count} + '.' + ${request.name}"></td>
                        <td th:text="${request.type}"></td>
                        <td th:text="${request.paramType}"></td>
                        <td th:if="${request.require}" th:text="Y"></td>
                        <td th:if="${!request.require}" th:text="N"></td>
                        <td th:text="${request.remark}"></td>
                        <!--                        <td th:if="${request.modelAttr}" th:text="asdfagadfg"></td>-->
                    </tr>
                    <th:block th:if="${request.modelAttr}">
                        <tbody th:include="this::request(${request.modelAttr.properties},${c.count} + '.', 1)"/>
                    </th:block>


                </th:block>

                <tr class="bg">
                    <td>状态码</td>
                    <td colspan="2">描述</td>
                    <td colspan="2">说明</td>
                </tr>

                <tr th:each="response:${table.responseList}">
                    <td th:text="${response.name}"></td>
                    <td colspan="2" th:text="${response.description}"></td>
                    <td colspan="2" th:text="${response.remark}"></td>
                </tr>

                <tr class="bg">
                    <td>返回属性名</td>
                    <td colspan="2">类型</td>
                    <td colspan="2">说明</td>
                </tr>

                <!--               对返回参数 递归生成行-->
                <tbody th:include="this::response(${table.modelAttr.properties},'', 1)"/>

                <tr class="bg">
                    <td colspan="5">示例</td>
                </tr>
                <tr class="specialHeight">
                    <td class="bg">请求参数</td>
                    <td colspan="4" th:text="${table.requestParam}"></td>
                </tr>
                <tr class="specialHeight">
                    <td class="bg">返回值</td>
                    <td colspan="4" th:text="${table.responseParam}"></td>
                </tr>

            </table>
        </div>
    </div>
</div>

<th:block th:fragment="request(properties,count, lv)">
    <th:block th:each="p,c : ${properties}">
        <tr>
            <td align="left" th:text="${count} + '' + ${c.count} + '.' + ${p.name}"
                th:style="|padding-left:${10*lv}px|"></td>
            <td th:text="${p.type}"></td>
            <td></td>
            <td th:if="${p.require}" th:text="Y"></td>
            <td th:if="${!p.require}" th:text="N"></td>
            <td th:text="${p.description}"></td>
        </tr>
        <th:block th:unless="${#lists.isEmpty(p.properties)}"
                  th:include="this::request(${p.properties},${count} + '' + ${c.count} + '.',${lv+1})"/>
    </th:block>
</th:block>

<th:block th:fragment="response(properties,count, lv)">
    <th:block th:each="p,c : ${properties}">
        <tr>
            <td align="left" th:text="${count} + '' + ${c.count} + '.' + ${p.name}"
                th:style="|padding-left:${10*lv}px|"></td>
            <td colspan="2" th:text="${p.type}"></td>
            <td colspan="2" th:text="${p.description}"></td>
        </tr>
        <th:block th:unless="${#lists.isEmpty(p.properties)}"
                  th:include="this::response(${p.properties},${count} + '' + ${c.count} + '.',${lv+1})"/>
    </th:block>
</th:block>
</body>
</html>
Download .txt
gitextract_o1xkyn5v/

├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
└── src/
    └── main/
        ├── java/
        │   └── org/
        │       └── word/
        │           ├── Application.java
        │           ├── config/
        │           │   ├── JavaConfig.java
        │           │   └── SwaggerDocumentationConfig.java
        │           ├── controller/
        │           │   ├── IndexController.java
        │           │   ├── OpenApiWordController.java
        │           │   └── WordController.java
        │           ├── model/
        │           │   ├── ModelAttr.java
        │           │   ├── Request.java
        │           │   ├── Response.java
        │           │   └── Table.java
        │           ├── service/
        │           │   ├── OpenApiWordService.java
        │           │   ├── WordService.java
        │           │   └── impl/
        │           │       ├── OpenApiWordServiceImpl.java
        │           │       └── WordServiceImpl.java
        │           └── utils/
        │               ├── JsonUtils.java
        │               ├── MenuUtils.java
        │               ├── ModelAttrUtils.java
        │               ├── RequestUtils.java
        │               └── ResponseUtils.java
        └── resources/
            ├── application.yml
            ├── logback.xml
            └── templates/
                ├── index.html
                ├── word-en_US.html
                ├── word-fr_FR.html
                ├── word-zh_CN.html
                └── word.html
Download .txt
SYMBOL INDEX (144 symbols across 19 files)

FILE: src/main/java/org/word/Application.java
  class Application (line 12) | @SpringBootApplication
    method main (line 16) | public static void main(String[] args) {

FILE: src/main/java/org/word/config/JavaConfig.java
  class JavaConfig (line 23) | @Configuration
    method restTemplate (line 26) | @Bean

FILE: src/main/java/org/word/config/SwaggerDocumentationConfig.java
  class SwaggerDocumentationConfig (line 20) | @Configuration
    method apiInfo (line 23) | ApiInfo apiInfo() {
    method customImplementation (line 35) | @Bean

FILE: src/main/java/org/word/controller/IndexController.java
  class IndexController (line 20) | @Controller
    method index (line 22) | @ApiIgnore

FILE: src/main/java/org/word/controller/OpenApiWordController.java
  class OpenApiWordController (line 28) | @Controller
    method getWord (line 51) | @ApiOperation(value = "将 swagger json文件转换成 word文档并下载", notes = "", tag...
    method generateModelData (line 59) | private void generateModelData(Model model, MultipartFile jsonFile) th...
    method generateModelData (line 74) | private void generateModelData(Model model, String url, Integer downlo...
    method writeContentToResponse (line 82) | private void writeContentToResponse(Model model, HttpServletResponse r...

FILE: src/main/java/org/word/controller/WordController.java
  class WordController (line 29) | @Controller
    method getWord (line 51) | @Deprecated
    method generateModelData (line 74) | private void generateModelData(Model model, String url, Integer downlo...
    method word (line 89) | @ApiOperation(value = "将 swagger 文档一键下载为 doc 文档", notes = "", tags = {...
    method writeContentToResponse (line 97) | private void writeContentToResponse(Model model, HttpServletResponse r...
    method getWord (line 121) | @ApiOperation(value = "将 swagger json文件转换成 word文档并下载", notes = "", tag...
    method getWord (line 137) | @ApiOperation(value = "将 swagger json字符串转换成 word文档并下载", notes = "", ta...
    method generateModelData (line 145) | private void generateModelData(Model model, String jsonStr) {
    method generateModelData (line 152) | private void generateModelData(Model model, MultipartFile jsonFile) {

FILE: src/main/java/org/word/model/ModelAttr.java
  class ModelAttr (line 15) | @Data
    method getClassName (line 18) | public String getClassName() {
    method setClassName (line 22) | public void setClassName(String className) {
    method getName (line 26) | public String getName() {
    method setName (line 30) | public void setName(String name) {
    method getType (line 34) | public String getType() {
    method setType (line 38) | public void setType(String type) {
    method getRequire (line 42) | public Boolean getRequire() {
    method setRequire (line 46) | public void setRequire(Boolean require) {
    method getDescription (line 50) | public String getDescription() {
    method setDescription (line 54) | public void setDescription(String description) {
    method getProperties (line 58) | public List<ModelAttr> getProperties() {
    method setProperties (line 62) | public void setProperties(List<ModelAttr> properties) {
    method isCompleted (line 66) | public boolean isCompleted() {
    method setCompleted (line 70) | public void setCompleted(boolean isCompleted) {
    method getSerialversionuid (line 74) | public static long getSerialversionuid() {

FILE: src/main/java/org/word/model/Request.java
  class Request (line 10) | @Data
    method getName (line 13) | public String getName() {
    method setName (line 17) | public void setName(String name) {
    method getType (line 21) | public String getType() {
    method setType (line 25) | public void setType(String type) {
    method getParamType (line 29) | public String getParamType() {
    method setParamType (line 33) | public void setParamType(String paramType) {
    method getRequire (line 37) | public Boolean getRequire() {
    method setRequire (line 41) | public void setRequire(Boolean require) {
    method getRemark (line 45) | public String getRemark() {
    method setRemark (line 49) | public void setRemark(String remark) {
    method getModelAttr (line 53) | public ModelAttr getModelAttr() {
    method setModelAttr (line 57) | public void setModelAttr(ModelAttr modelAttr) {

FILE: src/main/java/org/word/model/Response.java
  class Response (line 10) | @Data
    method getDescription (line 13) | public String getDescription() {
    method setDescription (line 17) | public void setDescription(String description) {
    method getName (line 21) | public String getName() {
    method setName (line 25) | public void setName(String name) {
    method getRemark (line 29) | public String getRemark() {
    method setRemark (line 33) | public void setRemark(String remark) {

FILE: src/main/java/org/word/model/Table.java
  class Table (line 10) | @Data
    method getTitle (line 13) | public String getTitle() {
    method setTitle (line 17) | public void setTitle(String title) {
    method getTag (line 21) | public String getTag() {
    method setTag (line 25) | public void setTag(String tag) {
    method getUrl (line 29) | public String getUrl() {
    method setUrl (line 33) | public void setUrl(String url) {
    method getDescription (line 37) | public String getDescription() {
    method setDescription (line 41) | public void setDescription(String description) {
    method getRequestForm (line 45) | public String getRequestForm() {
    method setRequestForm (line 49) | public void setRequestForm(String requestForm) {
    method getResponseForm (line 53) | public String getResponseForm() {
    method setResponseForm (line 57) | public void setResponseForm(String responseForm) {
    method getRequestType (line 61) | public String getRequestType() {
    method setRequestType (line 65) | public void setRequestType(String requestType) {
    method getRequestList (line 69) | public List<Request> getRequestList() {
    method setRequestList (line 73) | public void setRequestList(List<Request> requestList) {
    method getResponseList (line 77) | public List<Response> getResponseList() {
    method setResponseList (line 81) | public void setResponseList(List<Response> responseList) {
    method getRequestParam (line 85) | public String getRequestParam() {
    method setRequestParam (line 89) | public void setRequestParam(String requestParam) {
    method getResponseParam (line 93) | public String getResponseParam() {
    method setResponseParam (line 97) | public void setResponseParam(String responseParam) {
    method getModelAttr (line 101) | public ModelAttr getModelAttr() {
    method setModelAttr (line 105) | public void setModelAttr(ModelAttr modelAttr) {

FILE: src/main/java/org/word/service/OpenApiWordService.java
  type OpenApiWordService (line 11) | public interface OpenApiWordService {
    method tableList (line 13) | Map<String,Object> tableList(String swaggerUrl);
    method tableListFromString (line 15) | Map<String, Object> tableListFromString(String jsonStr) throws IOExcep...
    method tableList (line 17) | Map<String, Object> tableList(MultipartFile jsonFile) throws IOException;

FILE: src/main/java/org/word/service/WordService.java
  type WordService (line 10) | public interface WordService {
    method tableList (line 12) | Map<String,Object> tableList(String swaggerUrl);
    method tableListFromString (line 14) | Map<String, Object> tableListFromString(String jsonStr);
    method tableList (line 16) | Map<String, Object> tableList(MultipartFile jsonFile);

FILE: src/main/java/org/word/service/impl/OpenApiWordServiceImpl.java
  class OpenApiWordServiceImpl (line 38) | @SuppressWarnings({"unchecked", "rawtypes"})
    method tableList (line 46) | @Override
    method tableListFromString (line 59) | @Override
    method tableList (line 77) | @Override
    method getResultFromString (line 91) | private Map<String, Object> getResultFromString(List<Table> result, St...
    method getRequestParamsFormate (line 209) | private List<String> getRequestParamsFormate(Map<String, Object> obj) {
    method getResponseParamsFormate (line 224) | private List<String> getResponseParamsFormate(Map<String, Object> resp...
    method processRequestList (line 242) | private List<Request> processRequestList(List<LinkedHashMap> parameter...
    method processResponseCodeList (line 341) | private List<Response> processResponseCodeList(Map<String, Object> res...
    method processResponseModelAttrs (line 396) | private ModelAttr processResponseModelAttrs(Map<String, Object> respon...
    method parseComponents (line 445) | private Map<String, ModelAttr> parseComponents(Map<String, Object> map) {
    method getAndPutModelAttr (line 484) | private ModelAttr getAndPutModelAttr(Map<String, Map<String, Object>> ...
    method getRequestSchemaModelAttr (line 548) | private ModelAttr getRequestSchemaModelAttr(Map<String, Object> schema...
    method getSchemaModelAttr (line 610) | private ModelAttr getSchemaModelAttr(Map<String, Object> schemaMap) {
    method processResponseParam (line 666) | private String processResponseParam(Map<String, Object> responseObj, M...
    method processResponseParam1 (line 717) | private String processResponseParam1(Map<String, Object> responseObj, ...
    method processRequestParam (line 754) | private String processRequestParam(List<Request> list) throws IOExcept...
    method getValue (line 809) | private Object getValue(String type, ModelAttr modelAttr) {
    method getUrlParamsByMap (line 855) | public static String getUrlParamsByMap(Map<String, Object> map) {
    method getHeaderByMap (line 874) | public static String getHeaderByMap(Map<String, Object> map) {

FILE: src/main/java/org/word/service/impl/WordServiceImpl.java
  class WordServiceImpl (line 27) | @SuppressWarnings({"unchecked", "rawtypes"})
    method tableList (line 35) | @Override
    method tableListFromString (line 48) | @Override
    method tableList (line 65) | @Override
    method getResultFromString (line 80) | private Map<String, Object> getResultFromString(List<Table> result, St...
    method processRequestList (line 289) | private List<Request> processRequestList(List<LinkedHashMap> parameter...
    method processResponseCodeList (line 336) | private List<Response> processResponseCodeList(Map<String, Object> res...
    method processResponseModelAttrs (line 363) | private ModelAttr processResponseModelAttrs(Map<String, Object> respon...
    method parseDefinitions (line 395) | private Map<String, ModelAttr> parseDefinitions(Map<String, Object> ma...
    method getAndPutModelAttr (line 412) | private ModelAttr getAndPutModelAttr(Map<String, Map<String, Object>> ...
    method getModelAttrs (line 462) | private List<ModelAttr> getModelAttrs(Map<String, Map<String, Object>>...
    method processResponseParam (line 504) | private String processResponseParam(Map<String, Object> responseObj, M...
    method processRequestParam (line 540) | private String processRequestParam(List<Request> list) throws IOExcept...
    method getValue (line 592) | private Object getValue(String type, ModelAttr modelAttr) {
    method getUrlParamsByMap (line 638) | public static String getUrlParamsByMap(Map<String, Object> map) {
    method getHeaderByMap (line 657) | public static String getHeaderByMap(Map<String, Object> map) {

FILE: src/main/java/org/word/utils/JsonUtils.java
  class JsonUtils (line 21) | public class JsonUtils {
    method readValue (line 33) | public static <T> T readValue(String jsonStr, Class<T> clazz) throws I...
    method readListValue (line 37) | public static <T> List<T> readListValue(String jsonStr, Class<T> clazz...
    method readArray (line 42) | public static ArrayNode readArray(String jsonStr) throws IOException {
    method readNode (line 50) | public static JsonNode readNode(String jsonStr) throws IOException {
    method writeJsonStr (line 54) | public static String writeJsonStr(Object obj) throws JsonProcessingExc...
    method createObjectNode (line 58) | public static ObjectNode createObjectNode() {
    method createArrayNode (line 62) | public static ArrayNode createArrayNode() {

FILE: src/main/java/org/word/utils/MenuUtils.java
  class MenuUtils (line 7) | public class MenuUtils {
    method isMenu (line 12) | public static boolean isMenu(String tags) {

FILE: src/main/java/org/word/utils/ModelAttrUtils.java
  class ModelAttrUtils (line 17) | public class ModelAttrUtils {
    method propertyModelAttr (line 20) | public static ModelAttr propertyModelAttr(Map<String, Map<String, Obje...

FILE: src/main/java/org/word/utils/RequestUtils.java
  class RequestUtils (line 16) | public class RequestUtils {
    method validateRequestKey (line 18) | public static void validateRequestKey(Map<String, Map> content) throws...

FILE: src/main/java/org/word/utils/ResponseUtils.java
  class ResponseUtils (line 15) | public class ResponseUtils {
    method validateResponseKey (line 17) | public static void validateResponseKey(Map<String, Map> content) throw...
Condensed preview — 30 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (152K chars).
[
  {
    "path": ".gitignore",
    "chars": 21,
    "preview": ".idea\n/*.iml\ntarget/\n"
  },
  {
    "path": "LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 1767,
    "preview": "### 使用步骤(Google Chrome)\n1. 启动工程,访问地址: http://127.0.0.1:8080/swagger-ui.html\n2. swagger2Word 提供了多种方式生成 word 文档,可以通过 swagg"
  },
  {
    "path": "pom.xml",
    "chars": 4044,
    "preview": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:sc"
  },
  {
    "path": "src/main/java/org/word/Application.java",
    "chars": 456,
    "preview": "package org.word;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.Spri"
  },
  {
    "path": "src/main/java/org/word/config/JavaConfig.java",
    "chars": 2005,
    "preview": "package org.word.config;\n\nimport org.apache.http.conn.ssl.SSLConnectionSocketFactory;\nimport org.apache.http.conn.ssl.Tr"
  },
  {
    "path": "src/main/java/org/word/config/SwaggerDocumentationConfig.java",
    "chars": 1589,
    "preview": "package org.word.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotat"
  },
  {
    "path": "src/main/java/org/word/controller/IndexController.java",
    "chars": 751,
    "preview": "package org.word.controller;\n\n\nimport io.swagger.annotations.ApiOperation;\nimport io.swagger.annotations.ApiResponse;\nim"
  },
  {
    "path": "src/main/java/org/word/controller/OpenApiWordController.java",
    "chars": 3718,
    "preview": "package org.word.controller;\n\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport io.s"
  },
  {
    "path": "src/main/java/org/word/controller/WordController.java",
    "chars": 6571,
    "preview": "package org.word.controller;\n\nimport io.swagger.annotations.*;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commo"
  },
  {
    "path": "src/main/java/org/word/model/ModelAttr.java",
    "chars": 1854,
    "preview": "package org.word.model;\n\nimport lombok.Data;\nimport org.apache.commons.lang3.StringUtils;\n\nimport java.io.Serializable;\n"
  },
  {
    "path": "src/main/java/org/word/model/Request.java",
    "chars": 1253,
    "preview": "package org.word.model;\n\nimport java.io.Serializable;\n\nimport lombok.Data;\n\n/**\n * Created by XiuYin.Cui on 2018/1/11.\n "
  },
  {
    "path": "src/main/java/org/word/model/Response.java",
    "chars": 718,
    "preview": "package org.word.model;\n\nimport java.io.Serializable;\n\nimport lombok.Data;\n\n/**\n * Created by XiuYin.Cui on 2018/1/11.\n "
  },
  {
    "path": "src/main/java/org/word/model/Table.java",
    "chars": 2590,
    "preview": "package org.word.model;\n\nimport lombok.Data;\n\nimport java.util.List;\n\n/**\n * Created by XiuYin.Cui on 2018/1/11.\n */\n@Da"
  },
  {
    "path": "src/main/java/org/word/service/OpenApiWordService.java",
    "chars": 435,
    "preview": "package org.word.service;\n\nimport org.springframework.web.multipart.MultipartFile;\n\nimport java.io.IOException;\nimport j"
  },
  {
    "path": "src/main/java/org/word/service/WordService.java",
    "chars": 363,
    "preview": "package org.word.service;\n\nimport org.springframework.web.multipart.MultipartFile;\n\nimport java.util.Map;\n\n/**\n * Create"
  },
  {
    "path": "src/main/java/org/word/service/impl/OpenApiWordServiceImpl.java",
    "chars": 35545,
    "preview": "package org.word.service.impl;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport lombok.extern.slf4j.Sl"
  },
  {
    "path": "src/main/java/org/word/service/impl/WordServiceImpl.java",
    "chars": 26538,
    "preview": "package org.word.service.impl;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport lombok.extern.slf4j.Sl"
  },
  {
    "path": "src/main/java/org/word/utils/JsonUtils.java",
    "chars": 2264,
    "preview": "package org.word.utils;\n\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.core.JsonPars"
  },
  {
    "path": "src/main/java/org/word/utils/MenuUtils.java",
    "chars": 479,
    "preview": "package org.word.utils;\n\n/**\n * @author : cuixiuyin\n * @date : 2019/8/31\n */\npublic class MenuUtils {\n\n    public static"
  },
  {
    "path": "src/main/java/org/word/utils/ModelAttrUtils.java",
    "chars": 2547,
    "preview": "package org.word.utils;\n\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util."
  },
  {
    "path": "src/main/java/org/word/utils/RequestUtils.java",
    "chars": 958,
    "preview": "package org.word.utils;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.u"
  },
  {
    "path": "src/main/java/org/word/utils/ResponseUtils.java",
    "chars": 1588,
    "preview": "package org.word.utils;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.u"
  },
  {
    "path": "src/main/resources/application.yml",
    "chars": 530,
    "preview": "server:\n  port: 8080\n  tomcat:\n    max-threads: 800\n    uri-encoding: UTF-8\n\nspring:\n  application:\n    name: swagger2wo"
  },
  {
    "path": "src/main/resources/logback.xml",
    "chars": 445,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n    <include resource=\"org/springframework/boot/logging/logback/d"
  },
  {
    "path": "src/main/resources/templates/index.html",
    "chars": 76,
    "preview": "<!DOCTYPE html>\n<html>\n<body>\n<h2>Hello Swagger2word !</h2>\n</body>\n</html>\n"
  },
  {
    "path": "src/main/resources/templates/word-en_US.html",
    "chars": 7471,
    "preview": "<!-- 2020/12/11 - Olivier Bretteville\n    English locale\n-->\n<!DOCTYPE html>\n<html xmlns:th=\"http://www.thymeleaf.org\">\n"
  },
  {
    "path": "src/main/resources/templates/word-fr_FR.html",
    "chars": 7496,
    "preview": "<!-- 2020/12/11 - Olivier Bretteville\n    French locale\n-->\n<!DOCTYPE html>\n<html xmlns:th=\"http://www.thymeleaf.org\">\n<"
  },
  {
    "path": "src/main/resources/templates/word-zh_CN.html",
    "chars": 6960,
    "preview": "<!DOCTYPE html>\n<html xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"applicati"
  },
  {
    "path": "src/main/resources/templates/word.html",
    "chars": 6993,
    "preview": "<!DOCTYPE html>\n<html xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"applicati"
  }
]

About this extraction

This page contains the full source code of the JMCuixy/SwaggerToWord GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 30 files (136.1 KB), approximately 31.8k tokens, and a symbol index with 144 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!