From 635d762aef37b5de6cd2e34f4a076ab56d9a239d Mon Sep 17 00:00:00 2001
From: feiyu02 <risaku@163.com>
Date: 星期五, 11 四月 2025 17:35:11 +0800
Subject: [PATCH] 1. 添加自动输出接口API文档功能
---
src/main/kotlin/com/flightfeather/uav/common/api2word/utils/MenuUtils.java | 25
src/main/kotlin/com/flightfeather/uav/common/api2word/utils/ModelAttrUtils.java | 72 ++
src/main/kotlin/com/flightfeather/uav/lightshare/web/OpenApiWordController.java | 106 +++
src/main/kotlin/com/flightfeather/uav/common/api2word/JavaConfig.java | 47 +
src/main/kotlin/com/flightfeather/uav/socket/ServerHandler.kt | 1
src/main/kotlin/com/flightfeather/uav/common/api2word/model/Response.java | 48 +
src/main/kotlin/com/flightfeather/uav/lightshare/service/OpenApiWordService.java | 18
src/main/kotlin/com/flightfeather/uav/common/api2word/model/ModelAttr.java | 107 +++
pom.xml | 22
src/main/kotlin/com/flightfeather/uav/common/api2word/utils/RequestUtils.java | 29
src/main/kotlin/com/flightfeather/uav/common/api2word/model/Request.java | 87 ++
src/main/resources/templates/word.html | 212 ++++++
src/main/kotlin/com/flightfeather/uav/common/api2word/model/Table.java | 163 ++++
src/main/kotlin/com/flightfeather/uav/config/Swagger2Configuration.kt | 12
src/main/kotlin/com/flightfeather/uav/domain/entity/ExpandFun.kt | 1
src/main/kotlin/com/flightfeather/uav/common/api2word/utils/JsonUtils.java | 66 ++
src/main/kotlin/com/flightfeather/uav/common/api2word/utils/ResponseUtils.java | 44 +
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/OpenApiWordServiceImpl.java | 884 ++++++++++++++++++++++++++
src/main/resources/application.yml | 8
19 files changed, 1,945 insertions(+), 7 deletions(-)
diff --git a/pom.xml b/pom.xml
index b8e37db..5655f62 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,7 +17,7 @@
<properties>
<java.version>1.8</java.version>
- <kotlin.version>1.5.0</kotlin.version>
+ <kotlin.version>2.1.0</kotlin.version>
<itext.version>7.2.2</itext.version>
<!-- tk.mybatis -->
<mapper.plugin>tk.mybatis.mapper.generator.MapperPlugin</mapper.plugin>
@@ -35,6 +35,10 @@
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
@@ -165,6 +169,17 @@
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
+ <dependency>
+ <groupId>org.springframework.plugin</groupId>
+ <artifactId>spring-plugin-core</artifactId>
+ <version>2.0.0.RELEASE</version>
+ </dependency>
+<!-- <dependency>-->
+<!-- <groupId>org.springframework.plugin</groupId>-->
+<!-- <artifactId>spring-plugin-metadata</artifactId>-->
+<!-- <version>2.0.0.RELEASE</version>-->
+<!-- </dependency>-->
+
<!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
<dependency>
@@ -247,6 +262,11 @@
<artifactId>axis2-kernel</artifactId>
<version>1.8.2</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.17.0</version>
+ </dependency>
</dependencies>
diff --git a/src/main/kotlin/com/flightfeather/uav/common/api2word/JavaConfig.java b/src/main/kotlin/com/flightfeather/uav/common/api2word/JavaConfig.java
new file mode 100644
index 0000000..3586ec6
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/common/api2word/JavaConfig.java
@@ -0,0 +1,47 @@
+package com.flightfeather.uav.common.api2word;
+
+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;
+ }
+}
diff --git a/src/main/kotlin/com/flightfeather/uav/common/api2word/model/ModelAttr.java b/src/main/kotlin/com/flightfeather/uav/common/api2word/model/ModelAttr.java
new file mode 100644
index 0000000..38958e2
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/common/api2word/model/ModelAttr.java
@@ -0,0 +1,107 @@
+package com.flightfeather.uav.common.api2word.model;
+
+import com.github.jknack.handlebars.internal.lang3.StringUtils;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 杩斿洖灞炴��
+ *
+ * @author kevin
+ */
+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;
+}
diff --git a/src/main/kotlin/com/flightfeather/uav/common/api2word/model/Request.java b/src/main/kotlin/com/flightfeather/uav/common/api2word/model/Request.java
new file mode 100644
index 0000000..44b4494
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/common/api2word/model/Request.java
@@ -0,0 +1,87 @@
+package com.flightfeather.uav.common.api2word.model;
+
+import java.io.Serializable;
+
+/**
+ * Created by XiuYin.Cui on 2018/1/11.
+ */
+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;
+}
diff --git a/src/main/kotlin/com/flightfeather/uav/common/api2word/model/Response.java b/src/main/kotlin/com/flightfeather/uav/common/api2word/model/Response.java
new file mode 100644
index 0000000..f5209c6
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/common/api2word/model/Response.java
@@ -0,0 +1,48 @@
+package com.flightfeather.uav.common.api2word.model;
+
+import java.io.Serializable;
+
+/**
+ * Created by XiuYin.Cui on 2018/1/11.
+ */
+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;
+}
diff --git a/src/main/kotlin/com/flightfeather/uav/common/api2word/model/Table.java b/src/main/kotlin/com/flightfeather/uav/common/api2word/model/Table.java
new file mode 100644
index 0000000..b7a2e12
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/common/api2word/model/Table.java
@@ -0,0 +1,163 @@
+package com.flightfeather.uav.common.api2word.model;
+
+import java.util.List;
+
+/**
+ * Created by XiuYin.Cui on 2018/1/11.
+ */
+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();
+}
diff --git a/src/main/kotlin/com/flightfeather/uav/common/api2word/utils/JsonUtils.java b/src/main/kotlin/com/flightfeather/uav/common/api2word/utils/JsonUtils.java
new file mode 100644
index 0000000..deca1a7
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/common/api2word/utils/JsonUtils.java
@@ -0,0 +1,66 @@
+package com.flightfeather.uav.common.api2word.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();
+ }
+
+}
diff --git a/src/main/kotlin/com/flightfeather/uav/common/api2word/utils/MenuUtils.java b/src/main/kotlin/com/flightfeather/uav/common/api2word/utils/MenuUtils.java
new file mode 100644
index 0000000..8e70ff2
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/common/api2word/utils/MenuUtils.java
@@ -0,0 +1,25 @@
+package com.flightfeather.uav.common.api2word.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;
+ }
+ }
+}
diff --git a/src/main/kotlin/com/flightfeather/uav/common/api2word/utils/ModelAttrUtils.java b/src/main/kotlin/com/flightfeather/uav/common/api2word/utils/ModelAttrUtils.java
new file mode 100644
index 0000000..6c94ec2
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/common/api2word/utils/ModelAttrUtils.java
@@ -0,0 +1,72 @@
+package com.flightfeather.uav.common.api2word.utils;
+
+
+import com.flightfeather.uav.common.api2word.model.ModelAttr;
+import com.github.jknack.handlebars.internal.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * @author ivenhan
+ * @Date: 2020/10/15
+ */
+
+public class ModelAttrUtils {
+
+ // 灏佽schema - properties涓嬫煇涓叿浣損roperty瀵硅薄
+ 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();
+
+ //瑙f瀽灞炴��
+ 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;
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/common/api2word/utils/RequestUtils.java b/src/main/kotlin/com/flightfeather/uav/common/api2word/utils/RequestUtils.java
new file mode 100644
index 0000000..51b0c60
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/common/api2word/utils/RequestUtils.java
@@ -0,0 +1,29 @@
+package com.flightfeather.uav.common.api2word.utils;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+import java.util.Map;
+
+
+/**
+ * @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瀛楁") {};
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/common/api2word/utils/ResponseUtils.java b/src/main/kotlin/com/flightfeather/uav/common/api2word/utils/ResponseUtils.java
new file mode 100644
index 0000000..dca0ef0
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/common/api2word/utils/ResponseUtils.java
@@ -0,0 +1,44 @@
+package com.flightfeather.uav.common.api2word.utils;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * @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 瀛楁涔嬪鐨勫叾浠栧瓧娈�") {};
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/config/Swagger2Configuration.kt b/src/main/kotlin/com/flightfeather/uav/config/Swagger2Configuration.kt
index d485339..b91354e 100644
--- a/src/main/kotlin/com/flightfeather/uav/config/Swagger2Configuration.kt
+++ b/src/main/kotlin/com/flightfeather/uav/config/Swagger2Configuration.kt
@@ -16,20 +16,22 @@
*/
@Configuration
@EnableSwagger2
-class Swagger2Configuration {
+class Swagger2Configuration(
+ @Value("\${springfox.documentation.swagger.v2.enabled}") var swagger2Enable: Boolean,
+) {
companion object {
- const val SWAGGER_SCAN_BASE_PACKAGE = "cn.flightfeather.uav"
+ const val SWAGGER_SCAN_BASE_PACKAGE = "com.flightfeather.uav"
const val VERSION = "1.0.0"
}
- @Value("\${springfox.documentation.swagger.v2.enabled}")
- private val swagger2Enable: Boolean = true
+// @Value("\${springfox.documentation.swagger.v2.enabled}")
+// private val swagger2Enable: Boolean = true
@Bean
fun createRestApi(): Docket =
- Docket(DocumentationType.SWAGGER_2)
+ Docket(DocumentationType.OAS_30)
.enable(swagger2Enable)
.apiInfo(apiInfo())
.select()
diff --git a/src/main/kotlin/com/flightfeather/uav/domain/entity/ExpandFun.kt b/src/main/kotlin/com/flightfeather/uav/domain/entity/ExpandFun.kt
index c0bf033..15b6b78 100644
--- a/src/main/kotlin/com/flightfeather/uav/domain/entity/ExpandFun.kt
+++ b/src/main/kotlin/com/flightfeather/uav/domain/entity/ExpandFun.kt
@@ -142,6 +142,7 @@
VELOCITY -> TODO("no such factor")
TIME -> TODO("no such factor")
HEIGHT -> TODO("no such factor")
+ else -> TODO("no such factor")
}
}
diff --git a/src/main/kotlin/com/flightfeather/uav/lightshare/service/OpenApiWordService.java b/src/main/kotlin/com/flightfeather/uav/lightshare/service/OpenApiWordService.java
new file mode 100644
index 0000000..1886d2f
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/lightshare/service/OpenApiWordService.java
@@ -0,0 +1,18 @@
+package com.flightfeather.uav.lightshare.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;
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/OpenApiWordServiceImpl.java b/src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/OpenApiWordServiceImpl.java
new file mode 100644
index 0000000..d120472
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/OpenApiWordServiceImpl.java
@@ -0,0 +1,884 @@
+package com.flightfeather.uav.lightshare.service.impl;
+
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.flightfeather.uav.common.api2word.model.ModelAttr;
+import com.flightfeather.uav.common.api2word.model.Request;
+import com.flightfeather.uav.common.api2word.model.Response;
+import com.flightfeather.uav.common.api2word.model.Table;
+import com.flightfeather.uav.common.api2word.utils.JsonUtils;
+import com.flightfeather.uav.lightshare.service.OpenApiWordService;
+import com.github.jknack.handlebars.internal.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 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"})
+@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) {
+ }
+ 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) {
+ 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) {
+ 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);
+
+ //瑙f瀽model
+ Map<String, ModelAttr> definitinMap = parseComponents(map);
+
+ //瑙f瀽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("summary"));
+
+ // 6.鎺ュ彛鎻忚堪
+ Object descObj = content.get("description");
+ String description = descObj == null ? tag : 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) {
+ e.printStackTrace();
+// 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) {
+ 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<Entry<String, Map>> applications = content.entrySet().iterator();
+ while (applications.hasNext()) {
+ 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") == 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 ) {
+ List<Response> responseList = new ArrayList<>();
+ Iterator<Entry<String, Object>> resIt = responses.entrySet().iterator();
+ while (resIt.hasNext()) {
+ 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<Entry<String, Map>> applications = content.entrySet().iterator();
+
+ while (applications.hasNext()) {
+ 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 != "null" && 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<Entry<String, Map>> applications = content.entrySet().iterator();
+
+ while (applications.hasNext()) {
+ 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);
+ }
+
+ // 鏈娇鐢╮ef鏂瑰紡 浣跨敤properties鏂瑰紡
+ if (schema.get("properties") != null) {
+ modelAttr = getSchemaModelAttr(schema);
+ }
+ }
+ }
+ return modelAttr;
+ }
+
+ /**
+ * 瑙f瀽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瀛楁锛岄亶鍘唒roperties娣诲姞鏄惁蹇呭~灞炴��
+ ArrayList modeRequired = (ArrayList) swaggerMap.get(modeName).get("required");
+
+ if (modeProperties != null) {
+ Iterator<Entry<String, Object>> mIt = modeProperties.entrySet().iterator();
+
+ //瑙f瀽灞炴��
+ 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<>();
+ //瑙f瀽灞炴��
+ 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<>();
+ //瑙f瀽灞炴��
+ 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<Entry<String, Map>> applications = content.entrySet().iterator();
+ while (applications.hasNext()) {
+ 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) {
+ Map<String, Map> content = (Map) responseObj.get("content");
+ // if (responseObj != null && content.get("application/json") != null) {
+ if (content != null) {
+ Iterator<Entry<String, Map>> applications = content.entrySet().iterator();
+ while (applications.hasNext()) {
+ 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");
+ try {
+ return JsonUtils.writeJsonStr(value);
+ } catch (JsonProcessingException e) {
+ e.printStackTrace();
+ }
+ }
+ } else {
+ return "";
+ }
+
+ }
+ }
+ }
+ }
+ return StringUtils.EMPTY;
+ }
+
+ /**
+ * 灏佽璇锋眰浣�
+ *
+ * @param list
+ * @return
+ */
+ private String processRequestParam(List<Request> list) {
+ 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()) {
+ try {
+ res += " '" + JsonUtils.writeJsonStr(entry.getValue()) + "'";
+ } catch (JsonProcessingException e) {
+ e.printStackTrace();
+ }
+ }
+ } else {
+ try {
+ res += " '" + JsonUtils.writeJsonStr(jsonMap) + "'";
+ } catch (JsonProcessingException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ 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;
+ }
+ }
+
+ /**
+ * 灏唌ap杞崲鎴恥rl
+ */
+ public static String getUrlParamsByMap(Map<String, Object> map) {
+ if (map == null || map.isEmpty()) {
+ return "";
+ }
+ StringBuffer sb = new StringBuffer();
+ for (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;
+ }
+
+ /**
+ * 灏唌ap杞崲鎴恏eader
+ */
+ public static String getHeaderByMap(Map<String, Object> map) {
+ if (map == null || map.isEmpty()) {
+ return "";
+ }
+ StringBuffer sb = new StringBuffer();
+ for (Entry<String, Object> entry : map.entrySet()) {
+ sb.append("--header '");
+ sb.append(entry.getKey() + ":" + entry.getValue());
+ sb.append("'");
+ }
+ return sb.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/lightshare/web/OpenApiWordController.java b/src/main/kotlin/com/flightfeather/uav/lightshare/web/OpenApiWordController.java
new file mode 100644
index 0000000..15e6eab
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/lightshare/web/OpenApiWordController.java
@@ -0,0 +1,106 @@
+package com.flightfeather.uav.lightshare.web;
+
+import com.flightfeather.uav.lightshare.service.OpenApiWordService;
+import com.github.jknack.handlebars.internal.lang3.StringUtils;
+import io.swagger.annotations.*;
+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 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 鏂囨。鐨剆wagger json鏂囦欢
+ * @param response
+ * @return
+ * @throws Exception
+ */
+ @ApiOperation(value = "灏� swagger json鏂囦欢杞崲鎴� word鏂囨。骞朵笅杞�", notes = "")
+ @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);
+ }
+
+ @ApiOperation(value = "灏� swagger json鏂囦欢杞崲鎴� word鏂囨。骞朵笅杞�", notes = "")
+ @ApiResponses(value = {@ApiResponse(code = 200, message = "璇锋眰鎴愬姛銆�")})
+ @RequestMapping(value = "/OpenApiFileToWord2", method = {RequestMethod.POST})
+ public void getWord2(
+ Model model,
+ @ApiParam("swagger json url") @RequestParam("url") String url,
+ HttpServletResponse response
+ ) throws Exception {
+ generateModelData(model, url);
+ 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) {
+ url = StringUtils.defaultIfBlank(url, swaggerUrl);
+ Map<String, Object> result = openApiWordService.tableList(url);
+ model.addAttribute("url", url);
+ model.addAttribute("download", 0);
+ 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();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/socket/ServerHandler.kt b/src/main/kotlin/com/flightfeather/uav/socket/ServerHandler.kt
index 27954b2..61a2d8c 100644
--- a/src/main/kotlin/com/flightfeather/uav/socket/ServerHandler.kt
+++ b/src/main/kotlin/com/flightfeather/uav/socket/ServerHandler.kt
@@ -77,6 +77,7 @@
super.channelInactive(ctx)
}
+ @Deprecated("Deprecated in Java")
override fun exceptionCaught(ctx: ChannelHandlerContext?, cause: Throwable?) {
cause?.printStackTrace()
ctx?.close()
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 89e2e89..f94f027 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -35,4 +35,10 @@
helperDialect: mysql
reasonable: true
supportMethodsArguments: true
- params: count=countSql
\ No newline at end of file
+ params: count=countSql
+
+# Swagger json url address
+# etc. https://petstore.swagger.io/
+swagger.url: http://localhost:8080/v3/api-docs
+# api璁块棶缃戝潃
+# api url : http://localhost:8080/swagger-ui/index.html
\ No newline at end of file
diff --git a/src/main/resources/templates/word.html b/src/main/resources/templates/word.html
new file mode 100644
index 0000000..0fd7619
--- /dev/null
+++ b/src/main/resources/templates/word.html
@@ -0,0 +1,212 @@
+<!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: #D7D7D7;
+ }
+
+ 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, tableMapStat:${tableMap}" style="margin-bottom:20px;">
+ <!--杩欎釜鏄被鐨勮鏄�-->
+ <h4 class="first_title" th:text="${tableMapStat.count} + '. ' + ${tableMap.key}"></h4>
+ <div th:each="table,tableStat:${tableMap.value}">
+
+ <!--杩欎釜鏄瘡涓姹傜殑璇存槑锛屾柟渚跨敓鎴愭枃妗e悗杩涜鏁寸悊-->
+ <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>
--
Gitblit v1.9.3