当前位置: 代码迷 >> 综合 >> swagger-ui生成word文档
  详细解决方案

swagger-ui生成word文档

热度:43   发布时间:2023-11-17 13:45:25.0

现在写接口文档都比较费劲,后来出现了swagger在线文档,是一个多么好用的东西啊,当时这个东西上线了就不能开启了,如果甲方需要接口文档当然那边要是觉得在线的也可以就给他们,如果人家说这个不行我们就用swagger生成word离线文档

1. 引入pom jar包

<!-- https://mvnrepository.com/artifact/io.github.swagger2markup/swagger2markup -->
<dependency><groupId>io.github.swagger2markup</groupId><artifactId>swagger2markup</artifactId><version>1.3.3</version>
</dependency>

如果下不下来手动下载jar放在仓库里面就好了

2.开始我们愉快的编写代码

  • 创建实体类
SwaggerModel
import java.util.List;/*** @Author:zhuzi* @Explanation:*/
public class SwaggerModel {/*** 大标题*/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;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 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 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;}}
Response

/*** @Author:zhuzi* @Explanation:*/
public class Response {/*** 返回参数*/private String description;/*** 参数名*/private String name;/*** 说明*/private String remark;public Response(String description, String name, String remark) {this.description = description;this.name = name;this.remark = remark;}public Response() {}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;}}

 

Request
/*** @Author:zhuzi* @Explanation:*/
public class Request {/*** 请求参数*/private String description;/*** 参数名*/private String name;/*** 数据类型*/private String type;/*** 参数类型*/private String paramType;/*** 是否必填*/private Boolean require;/*** 说明*/private String remark;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 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 getRemark() {return remark;}public void setRemark(String remark) {this.remark = remark;}public String getParamType() {return paramType;}public void setParamType(String paramType) {this.paramType = paramType;}}
  • 添加几个工具类
JsonUtils
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:zhuzi* @Explanation:*/
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();}}

 

MenuUtils
/*** @Author:zhuzi* @Explanation:*/
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;}}}
  • 添加restTemplate配置
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.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.stereotype.Component;
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;/*** @Author:zhuzi* @Explanation:*/
@Component
public class JavaConfig {@Beanpublic 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);//60srequestFactory.setConnectTimeout(60 * 1000);requestFactory.setReadTimeout(60 * 1000);RestTemplate restTemplate = new RestTemplate(requestFactory);restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));return restTemplate;}}
  • 编写service
SwaggerService
import java.util.List;/*** @Author:zhuzi* @Explanation:*/
public interface SwaggerService {List<SwaggerModel> tableList(String jsonUrl);}
SwaggerServiceImpl
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;import java.io.IOException;
import java.util.*;@Service("swagger")
public class SwaggerServiceImpl implements SwaggerService {@Autowiredprivate RestTemplate restTemplate;@Value("${swagger.url}")private String swaggerUrl;@Overridepublic List<SwaggerModel> tableList(String jsonUrl) {jsonUrl = Optional.ofNullable(jsonUrl).orElse(swaggerUrl);List<SwaggerModel> result = new ArrayList<>();try {String jsonStr = restTemplate.getForObject(jsonUrl, String.class);// convert JSON string to MapMap<String, Object> map = JsonUtils.readValue(jsonStr, HashMap.class);//解析pathsMap<String, LinkedHashMap> paths = (LinkedHashMap) map.get("paths");if (paths != null) {Iterator<Map.Entry<String, LinkedHashMap>> it = paths.entrySet().iterator();while (it.hasNext()) {Map.Entry<String, LinkedHashMap> path = it.next();Iterator<Map.Entry<String, LinkedHashMap>> it2 = path.getValue().entrySet().iterator();// 1.请求路径String url = path.getKey();// 2.请求方式,类似为 get,post,delete,put 这样String requestType = StringUtils.join(path.getValue().keySet(), ",");//不管有几种请求方式,都只解析第一种Map.Entry<String, LinkedHashMap> firstRequest = it2.next();Map<String, Object> content = firstRequest.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-dataString requestForm = "";List<String> consumes = (List) content.get("consumes");if (consumes != null && consumes.size() > 0) {requestForm = StringUtils.join(consumes, ",");}// 8.返回参数格式,类似于 application/jsonString responseForm = "";List<String> produces = (List) content.get("produces");if (produces != null && produces.size() > 0) {responseForm = StringUtils.join(produces, ",");}// 9. 请求体List<Request> requestList = new ArrayList<>();List<LinkedHashMap> parameters = (ArrayList) content.get("parameters");if (!CollectionUtils.isEmpty(parameters)) {for (Map<String, Object> param : parameters) {Request request = new Request();request.setName(String.valueOf(param.get("name")));Object in = param.get("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.setParamType(ref == null ? "{}" : ref.toString());} else {request.setType(param.get("type") == null ? "Object" : param.get("type").toString());request.setParamType(String.valueOf(in));}request.setRequire((Boolean) param.get("required"));request.setRemark(String.valueOf(param.get("description")));requestList.add(request);}}// 10.返回体List<Response> responseList = new ArrayList<>();Map<String, Object> responses = (LinkedHashMap) content.get("responses");Iterator<Map.Entry<String, Object>> it3 = responses.entrySet().iterator();while (it3.hasNext()) {Response response = new Response();Map.Entry<String, Object> entry = it3.next();// 状态码 200 201 401 403 404 这样response.setName(entry.getKey());LinkedHashMap<String, Object> statusCodeInfo = (LinkedHashMap) entry.getValue();response.setDescription(String.valueOf(statusCodeInfo.get("description")));response.setRemark(String.valueOf(statusCodeInfo.get("description")));responseList.add(response);}//封装TableSwaggerModel table = new SwaggerModel();//是否添加为菜单if (MenuUtils.isMenu(title)) {table.setTitle(title);}table.setUrl(url);table.setTag(tag);table.setDescription(description);table.setRequestForm(requestForm);table.setResponseForm(responseForm);table.setRequestType(requestType);table.setResponseList(responseList);table.setRequestParam(JsonUtils.writeJsonStr(buildParamMap(requestList, map)));for (Request request : requestList) {request.setParamType(request.getParamType().replaceAll("#/definitions/", ""));}table.setRequestList(requestList);// 取出来状态是200时的返回值Object obj = responses.get("200");if (obj == null) {table.setResponseParam("");result.add(table);continue;}Object schema = ((Map) obj).get("schema");if (schema == null) {table.setResponseParam("");result.add(table);continue;}if (((Map) schema).get("$ref") != null) {//非数组类型返回值String ref = (String) ((Map) schema).get("$ref");//解析swagger2 ref链接ObjectNode objectNode = parseRef(ref, map);table.setResponseParam(objectNode.toString());result.add(table);continue;}Object items = ((Map) schema).get("items");if (items != null && ((Map) items).get("$ref") != null) {//数组类型返回值String ref = (String) ((Map) items).get("$ref");//解析swagger2 ref链接ObjectNode objectNode = parseRef(ref, map);ArrayNode arrayNode = JsonUtils.createArrayNode();arrayNode.add(objectNode);table.setResponseParam(arrayNode.toString());result.add(table);continue;}result.add(table);}}} catch (Exception e) {}return result;}/*** 从map中解析出指定的ref** @param ref ref链接 例如:"#/definitions/PageInfoBT?Customer?"* @param map 是整个swagger json转成map对象* @return* @author fpzhan*/private ObjectNode parseRef(String ref, Map<String, Object> map) {ObjectNode objectNode = JsonUtils.createObjectNode();if (StringUtils.isNotEmpty(ref) && ref.startsWith("#")) {String[] refs = ref.split("/");Map<String, Object> tmpMap = map;//取出ref最后一个参数 startfor (String tmp : refs) {if (!"#".equals(tmp)) {tmpMap = (Map<String, Object>) tmpMap.get(tmp);}}//取出ref最后一个参数 end//取出参数if (tmpMap == null) {return objectNode;}Object properties = tmpMap.get("properties");if (properties == null) {return objectNode;}Map<String, Object> propertiesMap = (Map<String, Object>) properties;Set<String> keys = propertiesMap.keySet();//遍历keyfor (String key : keys) {Map<String, Object> keyMap = (Map) propertiesMap.get(key);if ("array".equals(keyMap.get("type"))) {//数组的处理方式String sonRef = (String) ((Map) keyMap.get("items")).get("$ref");//对象自包含,跳过解析if (ref.equals(sonRef)) {continue;}JsonNode jsonNode = parseRef(sonRef, map);ArrayNode arrayNode = JsonUtils.createArrayNode();arrayNode.add(jsonNode);objectNode.set(key, arrayNode);} else if (keyMap.get("$ref") != null) {//对象的处理方式String sonRef = (String) keyMap.get("$ref");//对象自包含,跳过解析if (ref.equals(sonRef)) {continue;}ObjectNode object = parseRef(sonRef, map);objectNode.set(key, object);} else {//其他参数的处理方式,string、intString str = "";if (keyMap.get("description") != null) {str = str + keyMap.get("description");}if (keyMap.get("format") != null) {str = str + String.format("格式为(%s)", keyMap.get("format"));}objectNode.put(key, str);}}}return objectNode;}/*** 封装post请求体** @param list* @param map* @return*/private Map<String, Object> buildParamMap(List<Request> list, Map<String, Object> map) throws IOException {Map<String, Object> paramMap = new HashMap<>(8);if (list != null && list.size() > 0) {for (Request request : list) {String name = request.getName();String type = request.getType();switch (type) {case "string":paramMap.put(name, "string");break;case "integer":paramMap.put(name, 0);break;case "number":paramMap.put(name, 0.0);break;case "boolean":paramMap.put(name, true);break;case "body":String paramType = request.getParamType();ObjectNode objectNode = parseRef(paramType, map);paramMap = JsonUtils.readValue(objectNode.toString(), Map.class);break;default:paramMap.put(name, null);break;}}}return paramMap;}
  • 实现controller

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.RestTemplate;import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;/*** @Author:zhuzi* @Explanation:*/
@Controller
public class SwaggerController {@Autowired@Qualifier("swagger")private SwaggerService swaggerService;@Autowiredprivate RestTemplate restTemplate;@Value("${server.port}")private Integer port;/*** 将 swagger 文档转换成 html 文档,可通过在网页上右键另存为 xxx.doc 的方式转换为 word 文档** @param model* @param url   需要转换成 word 文档的资源地址* @return*/@Deprecated@GetMapping("/toWord")public String getWord(Model model, @RequestParam(value = "url", required = false) String url) {List<SwaggerModel> tables = swaggerService.tableList(url);model.addAttribute("tables", tables);return "word";}/*** 将 swagger 文档一键下载为 doc 文档** @param url      需要转换成 word 文档的资源地址* @param response*/@RequestMapping("/downloadWord")public void word(@RequestParam String url, HttpServletResponse response) {ResponseEntity<String> forEntity = restTemplate.getForEntity("http://localhost:" + port + "/toWord?url=" + url, String.class);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("toWord.doc", "utf-8"));byte[] bytes = forEntity.getBody().getBytes();bos.write(bytes, 0, bytes.length);bos.flush();} catch (IOException e) {e.printStackTrace();}}}
  •  配置yml配置文件
swagger:url: http://localhost:8100/v2/api-docs

3.测试 访问:  http://localhost:8080/toWord

可以看到

 输入:http://localhost:8080/downloadWord?url=http://localhost:8100/v2/api-docs

这样就可以下周再下来了

注意:如果有编码问题 打开设置  -> file encodings 将编码全部设置为 UTF-8

  相关解决方案