diff --git a/front/src/views/doc/EditTable/index.vue b/front/src/views/doc/EditTable/index.vue
index 4967dcdc0a50feef6da0c8cda74332528bdb8767..27eef590e6febb2430b336c59e769fdd53254b92 100644
--- a/front/src/views/doc/EditTable/index.vue
+++ b/front/src/views/doc/EditTable/index.vue
@@ -215,9 +215,34 @@ export default {
}
}
},
+ computed: {
+ watchList: function() {
+ const obj = {}
+ Object.keys(this.rows).forEach(index => {
+ obj[index] = JSON.parse(JSON.stringify(this.rows[index]))
+ })
+ return obj
+ }
+ },
watch: {
data(val) {
this.rows = val
+ },
+ watchList: {
+ deep: true,
+ handler: function(newVal, oldVal) {
+ Object.keys(oldVal).forEach(index => {
+ if (oldVal[index].gmtModified !== undefined) {
+ newVal[index].gmtModified = undefined
+ oldVal[index].gmtModified = undefined
+ const l = JSON.stringify(oldVal[index])
+ const r = JSON.stringify(newVal[index])
+ if (l !== r) {
+ this.rows[index].isModified = true
+ }
+ }
+ })
+ }
}
},
mounted() {
diff --git a/server/server-common/src/main/java/cn/torna/common/enums/SyncModeEnum.java b/server/server-common/src/main/java/cn/torna/common/enums/SyncModeEnum.java
new file mode 100644
index 0000000000000000000000000000000000000000..aebab022e7467cb1fb438e73a9dca519c574f0dc
--- /dev/null
+++ b/server/server-common/src/main/java/cn/torna/common/enums/SyncModeEnum.java
@@ -0,0 +1,20 @@
+package cn.torna.common.enums;
+
+/**
+ * @author tanghc
+ */
+public enum SyncModeEnum {
+ COVER(0),
+ MERGE(1),
+ ;
+
+ SyncModeEnum(int type) {
+ this.type = type;
+ }
+
+ private final int type;
+
+ public int getType() {
+ return type;
+ }
+}
diff --git a/server/server-common/src/main/java/cn/torna/common/util/DataIdUtil.java b/server/server-common/src/main/java/cn/torna/common/util/DataIdUtil.java
index c0a204231151e80226c1ce27bb799482be57d619..c213fbfbef90752e8f682e966f1cb78d1cb8b1a2 100644
--- a/server/server-common/src/main/java/cn/torna/common/util/DataIdUtil.java
+++ b/server/server-common/src/main/java/cn/torna/common/util/DataIdUtil.java
@@ -11,6 +11,8 @@ public class DataIdUtil {
private static final String TPL_PARAM = "%s:%s:%s:%s";
private static final String TPL_ENUM = "%s:%s";
+ private static final String TPL_API = "%s:%s:%s:%s";
+ private static final String TPL_FOLDER = "%s:%s:%s";
/**
* 文档参数唯一id,md5(doc_id:parent_id:style:name)
@@ -39,4 +41,18 @@ public class DataIdUtil {
return DigestUtils.md5DigestAsHex(content.getBytes(StandardCharsets.UTF_8));
}
+ public static String getDocInfoDataId(boolean isFolder, Long moduleId, Long parentId, String name, String url, String httpMethod) {
+ if (parentId == null) {
+ parentId = 0L;
+ }
+ String content = isFolder?
+ String.format(TPL_FOLDER, moduleId, parentId, name) :
+ String.format(TPL_API, moduleId, parentId, url, httpMethod);
+ return DigestUtils.md5DigestAsHex(content.getBytes(StandardCharsets.UTF_8));
+ }
+
+ public static String getFolderDataId(Long moduleId, Long parentId, String name) {
+ return getDocInfoDataId(true, moduleId, parentId, name, null, null);
+ }
+
}
diff --git a/server/server-dao/src/main/java/cn/torna/dao/entity/DocInfo.java b/server/server-dao/src/main/java/cn/torna/dao/entity/DocInfo.java
index 248e718ce61a0c6a28d67a2f26139173d4d2b98c..f9217fdc9923e4ef129b3b82ab06d0dea1d01303 100755
--- a/server/server-dao/src/main/java/cn/torna/dao/entity/DocInfo.java
+++ b/server/server-dao/src/main/java/cn/torna/dao/entity/DocInfo.java
@@ -115,5 +115,7 @@ public class DocInfo {
/** 数据库字段:gmt_modified */
private Date gmtModified;
+ /** 数据库字段:version */
+ private Double version;
}
\ No newline at end of file
diff --git a/server/server-dao/src/main/java/cn/torna/dao/entity/DocParam.java b/server/server-dao/src/main/java/cn/torna/dao/entity/DocParam.java
index 82bd4b14ce99cde26bbcb7e0821033ef7b5dd28e..a36e52c302fc0fc7f60cfb9875797dde6a2b7544 100755
--- a/server/server-dao/src/main/java/cn/torna/dao/entity/DocParam.java
+++ b/server/server-dao/src/main/java/cn/torna/dao/entity/DocParam.java
@@ -1,13 +1,12 @@
package cn.torna.dao.entity;
-import java.util.Date;
-
import lombok.Data;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
+import java.util.Date;
/**
* 表名:doc_param
@@ -88,5 +87,7 @@ public class DocParam {
/** 数据库字段:gmt_modified */
private Date gmtModified;
+ /** 数据库字段:version */
+ private Double version;
}
\ No newline at end of file
diff --git a/server/server-dao/src/main/java/cn/torna/dao/entity/Module.java b/server/server-dao/src/main/java/cn/torna/dao/entity/Module.java
index 05a9896c1b9e86e382d430143064f8cbc9641ad0..c9b708840ec3415264aed300e94a5e160c042848 100755
--- a/server/server-dao/src/main/java/cn/torna/dao/entity/Module.java
+++ b/server/server-dao/src/main/java/cn/torna/dao/entity/Module.java
@@ -70,5 +70,6 @@ public class Module {
/** 数据库字段:gmt_modified */
private Date gmtModified;
-
+ /** 数据库字段:version */
+ private Double version;
}
\ No newline at end of file
diff --git a/server/server-dao/src/main/resources/mybatis/mapper/DocInfoMapper.xml b/server/server-dao/src/main/resources/mybatis/mapper/DocInfoMapper.xml
index 5ed7f4f4f2e007b3be5bf3cf9b66f5f3f82d0a91..233063b769db0f6790530595f3df43c5f32f6cd8 100644
--- a/server/server-dao/src/main/resources/mybatis/mapper/DocInfoMapper.xml
+++ b/server/server-dao/src/main/resources/mybatis/mapper/DocInfoMapper.xml
@@ -93,6 +93,14 @@
remark = VALUES(remark),
is_show = VALUES(is_show),
is_deleted = 0,
+
+
+ version = VALUES(version),
+
+
+ version = 1,
+
+
gmt_modified = now()
diff --git a/server/server-dao/src/main/resources/mybatis/mapper/DocParamMapper.xml b/server/server-dao/src/main/resources/mybatis/mapper/DocParamMapper.xml
index ef9f4940b5c4a904b78baffd5ec440fdcb1afc4e..d62768f96464ebf507803d1349fa2249c7c5e9af 100644
--- a/server/server-dao/src/main/resources/mybatis/mapper/DocParamMapper.xml
+++ b/server/server-dao/src/main/resources/mybatis/mapper/DocParamMapper.xml
@@ -73,6 +73,14 @@
modifier_name = VALUES(modifier_name),
order_index = VALUES(order_index),
is_deleted = VALUES(is_deleted),
+
+
+ version = VALUES(version),
+
+
+ version = 1,
+
+
gmt_modified = now()
diff --git a/server/server-manager/src/main/java/cn/torna/manager/doc/swagger/SwaggerDocParserV2.java b/server/server-manager/src/main/java/cn/torna/manager/doc/swagger/SwaggerDocParserV2.java
index f70bbf109f7ba9031d2ffad5c7a01010cf8d5e7b..876fac196299e506cc8dbd740e922a672d74b572 100644
--- a/server/server-manager/src/main/java/cn/torna/manager/doc/swagger/SwaggerDocParserV2.java
+++ b/server/server-manager/src/main/java/cn/torna/manager/doc/swagger/SwaggerDocParserV2.java
@@ -198,6 +198,10 @@ public class SwaggerDocParserV2 implements DocParser {
List docParameterList = new ArrayList<>();
for (int i = 0; i < parameters.size(); i++) {
JSONObject fieldJson = parameters.getJSONObject(i);
+ //request参数列表里不应该出现header
+ if ("header".equals(fieldJson.get("in"))) {
+ continue;
+ }
RefInfo refInfo = getRefInfo(fieldJson.getJSONObject("schema"));
if (refInfo == null) {
refInfo = getRefInfo(fieldJson.getJSONObject("items"));
@@ -248,6 +252,10 @@ public class SwaggerDocParserV2 implements DocParser {
*/
JSONObject fieldJson = parameters.getJSONObject(i);
fieldJson = formatFieldJson(docRoot, fieldJson);
+ //query参数列表里不应该出现body
+ if ("body".equals(fieldJson.get("in"))) {
+ continue;
+ }
DocParameter docParameter = fieldJson.toJavaObject(DocParameter.class);
// @RequestBody String reqEntity
// 这种情况下name为null
diff --git a/server/server-manager/src/main/java/cn/torna/manager/doc/swagger/SwaggerDocParserV3.java b/server/server-manager/src/main/java/cn/torna/manager/doc/swagger/SwaggerDocParserV3.java
index 245779aa0d21db3c0e56f8d16aa87e6b467e12f4..76c7a31471214c206dd28b32537b3ba25db00cb8 100644
--- a/server/server-manager/src/main/java/cn/torna/manager/doc/swagger/SwaggerDocParserV3.java
+++ b/server/server-manager/src/main/java/cn/torna/manager/doc/swagger/SwaggerDocParserV3.java
@@ -172,6 +172,10 @@ public class SwaggerDocParserV3 implements DocParser {
List docParameterList = new ArrayList<>();
for (int i = 0; i < parameters.size(); i++) {
JSONObject fieldJson = parameters.getJSONObject(i);
+ //request参数列表里不应该出现header
+ if ("header".equals(fieldJson.get("in"))) {
+ continue;
+ }
RefInfo refInfo = getRefInfo(fieldJson.getJSONObject("schema"));
if (refInfo == null) {
refInfo = getRefInfo(fieldJson.getJSONObject("items"));
@@ -221,6 +225,10 @@ public class SwaggerDocParserV3 implements DocParser {
}
*/
JSONObject fieldJson = parameters.getJSONObject(i);
+ //query参数列表里不应该出现body
+ if ("body".equals(fieldJson.get("in"))) {
+ continue;
+ }
fieldJson = formatFieldJson(docRoot, fieldJson);
DocParameter docParameter = fieldJson.toJavaObject(DocParameter.class);
// @RequestBody String reqEntity
diff --git a/server/server-service/src/main/java/cn/torna/service/DocInfoService.java b/server/server-service/src/main/java/cn/torna/service/DocInfoService.java
index ee7489221d320ce8864950030e9267abeb291498..8e79f3869d815233f887e8d587586dc6ca3939cc 100755
--- a/server/server-service/src/main/java/cn/torna/service/DocInfoService.java
+++ b/server/server-service/src/main/java/cn/torna/service/DocInfoService.java
@@ -255,6 +255,8 @@ public class DocInfoService extends BaseService {
private DocInfo modifyDocInfo(DocInfoDTO docInfoDTO, User user) {
DocInfo docInfo = buildDocInfo(docInfoDTO, user);
+ DocInfo temp = this.getById(docInfo.getId());
+ docInfo.setVersion(temp.getVersion() + 0.001);
this.update(docInfo);
return docInfo;
}
@@ -323,6 +325,7 @@ public class DocInfoService extends BaseService {
folder.setModifyMode(user.getOperationModel());
folder.setModifierId(user.getUserId());
folder.setIsDeleted(Booleans.FALSE);
+ folder.setVersion(folder.getVersion() + 0.001);
this.update(folder);
}
diff --git a/server/server-service/src/main/java/cn/torna/service/DocParamService.java b/server/server-service/src/main/java/cn/torna/service/DocParamService.java
index 5bb2d8387788afc498fdf99b4400dc743256106e..a13275a1e0fb921dfbe2e827df682cec7b12dc2b 100644
--- a/server/server-service/src/main/java/cn/torna/service/DocParamService.java
+++ b/server/server-service/src/main/java/cn/torna/service/DocParamService.java
@@ -43,7 +43,7 @@ public class DocParamService extends BaseService {
}
}
- private List listParentParam(long docId, ParamStyleEnum paramStyleEnum) {
+ public List listParentParam(long docId, ParamStyleEnum paramStyleEnum) {
Query query = new Query()
.eq("doc_id", docId)
.eq("style", paramStyleEnum.getStyle())
@@ -51,6 +51,13 @@ public class DocParamService extends BaseService {
return this.list(query);
}
+ public List listParentParam(long docId) {
+ Query query = new Query()
+ .eq("doc_id", docId)
+ .eq("parent_id", 0);
+ return this.list(query);
+ }
+
/**
* 删除参数,同时会删除子节点
* @param id id
@@ -106,6 +113,10 @@ public class DocParamService extends BaseService {
if (docParam.getId() == null) {
savedParam = this.saveParam(docParam);
} else {
+ if (Byte.valueOf("1").equals(docParamDTO.getIsModified())) {
+ DocParam temp = this.getById(docParam.getId());
+ docParam.setVersion(temp.getVersion() + 0.001);
+ }
this.update(docParam);
savedParam = docParam;
}
diff --git a/server/server-service/src/main/java/cn/torna/service/DocImportService.java b/server/server-service/src/main/java/cn/torna/service/DocPostManImportService.java
similarity index 62%
rename from server/server-service/src/main/java/cn/torna/service/DocImportService.java
rename to server/server-service/src/main/java/cn/torna/service/DocPostManImportService.java
index 1bee124b79f2b5a011089d576647446c19afb185..08a756cb5d67c402f5e683cfb7b26c65475a2173 100644
--- a/server/server-service/src/main/java/cn/torna/service/DocImportService.java
+++ b/server/server-service/src/main/java/cn/torna/service/DocPostManImportService.java
@@ -1,52 +1,30 @@
package cn.torna.service;
import cn.torna.common.bean.Booleans;
-import cn.torna.common.bean.HttpHelper;
import cn.torna.common.bean.User;
import cn.torna.common.enums.ParamStyleEnum;
-import cn.torna.common.exception.BizException;
import cn.torna.common.util.DataIdUtil;
import cn.torna.dao.entity.DocInfo;
import cn.torna.dao.entity.DocParam;
import cn.torna.dao.entity.Module;
import cn.torna.manager.doc.DocParser;
import cn.torna.manager.doc.IParam;
-import cn.torna.manager.doc.postman.Body;
-import cn.torna.manager.doc.postman.Item;
-import cn.torna.manager.doc.postman.Param;
-import cn.torna.manager.doc.postman.Postman;
-import cn.torna.manager.doc.postman.Request;
-import cn.torna.manager.doc.postman.Url;
-import cn.torna.manager.doc.swagger.DocBean;
-import cn.torna.manager.doc.swagger.DocItem;
-import cn.torna.manager.doc.swagger.DocModule;
-import cn.torna.manager.doc.swagger.DocParameter;
-import cn.torna.manager.doc.swagger.Server;
+import cn.torna.manager.doc.postman.*;
import cn.torna.service.dto.DocItemCreateDTO;
import cn.torna.service.dto.ImportPostmanDTO;
-import cn.torna.service.dto.ImportSwaggerDTO;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
-import com.alibaba.fastjson.parser.Feature;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
+import java.util.*;
import java.util.function.Function;
/**
@@ -54,15 +32,7 @@ import java.util.function.Function;
*/
@Service
@Slf4j
-public class DocImportService {
-
- @Autowired
- @Qualifier("swaggerDocParserV2")
- private DocParser docParserV2;
-
- @Autowired
- @Qualifier("swaggerDocParserV3")
- private DocParser docParserV3;
+public class DocPostManImportService {
@Autowired
@Qualifier("postmanDocParser")
@@ -77,9 +47,6 @@ public class DocImportService {
@Autowired
private ModuleService moduleService;
- @Autowired
- private ModuleConfigService moduleConfigService;
-
private static final Map CONTEXT_TYPE_MAP = new HashMap<>();
static {
CONTEXT_TYPE_MAP.put("json", "application/json");
@@ -87,43 +54,6 @@ public class DocImportService {
CONTEXT_TYPE_MAP.put("text", "text/plain");
}
-
- /**
- * 导入swagger文档
- *
- * @param importSwaggerDTO importSwaggerDTO
- */
- @Transactional(rollbackFor = Exception.class)
- public Module importSwagger(ImportSwaggerDTO importSwaggerDTO) {
- String json;
- String url = importSwaggerDTO.getImportUrl();
- try {
- HttpHelper.ResponseResult responseResult = HttpHelper
- .create()
- .basicAuth(importSwaggerDTO.getBasicAuthUsername(), importSwaggerDTO.getBasicAuthPassword())
- .url(url)
- .method("get")
- .execute();
- String body = responseResult.asString();
- int status = responseResult.getStatus();
- if (status == HttpStatus.UNAUTHORIZED.value()) {
- throw new BizException("认证失败");
- }
- if (status != HttpStatus.OK.value()) {
- log.error("导入swagger错误,url:{}, \n{}", url, body);
- throw new BizException("导入错误,请查看日志");
- }
- json = body;
- } catch (IOException e) {
- log.error("导入swagger异常, url:{}", url, e);
- throw new BizException("导入异常, msg:" + e.getMessage());
- }
- JSONObject docRoot = JSON.parseObject(json, Feature.OrderedField, Feature.DisableCircularReferenceDetect);
- DocParser docParser = docRoot.containsKey("openapi") ? docParserV3 : docParserV2;
- DocBean docBean = docParser.parseJson(json);
- return this.saveDocToDb(docBean, importSwaggerDTO);
- }
-
/**
* 导入postman文档
*
@@ -203,8 +133,20 @@ public class DocImportService {
if (StringUtils.isEmpty(json)) {
return Collections.emptyList();
}
- JSONObject jsonObject = JSON.parseObject(json);
- return this.parseParams(jsonObject);
+ if (json.startsWith("[")) {
+ JSONArray jsonArray = JSON.parseArray(json);
+ return Collections.emptyList();
+ }else {
+ JSONObject jsonObject = JSON.parseObject(json);
+ return this.parseParams(jsonObject);
+ }
+// try {
+// JSONObject jsonObject = JSON.p(json);
+// return this.parseParams(jsonObject);
+// }catch (Exception e) {
+// log.warn("解析body参数时异常已忽略:{},{}",body.getRaw(), e.getMessage());
+// return Collections.emptyList();
+// }
case "urlencoded":
return body.getUrlencoded();
default:
@@ -261,59 +203,6 @@ public class DocImportService {
return true;
}
- /**
- * 保存文档到数据库
- *
- * @param docBean
- * @param importSwaggerDTO
- */
- private Module saveDocToDb(DocBean docBean, ImportSwaggerDTO importSwaggerDTO) {
- User user = importSwaggerDTO.getUser();
- String title = docBean.getTitle();
- // 创建模块
- Module module = moduleService.createSwaggerModule(importSwaggerDTO, title);
- // 保存调试环境
- for (Server server : docBean.getServers()) {
- moduleConfigService.setDebugEnv(module.getId(), server.getDescription(), server.getUrl());
- }
- // 创建文档分类
- List docModules = docBean.getDocModules();
- docModules.sort(Comparator.comparing(DocModule::getOrder));
- for (DocModule docModule : docModules) {
- DocInfo moduleDocInfo = docInfoService.createDocFolder(docModule.getModule(), module.getId(), user);
- // 创建模块下的文档
- List items = docModule.getItems();
- for (DocItem item : items) {
- DocItemCreateDTO docItemCreateDTO = this.buildDocItemCreateDTO(item, moduleDocInfo, user);
- DocInfo docItem = docInfoService.createDocItem(docItemCreateDTO);
- // query参数
- List queryParameters = item.getQueryParameters();
- this.saveParams(queryParameters, docItem, this::buildStyleEnum, user);
- // body参数
- List requestParameters = item.getRequestParameters();
- this.saveParams(requestParameters, docItem, this::buildStyleEnum, user);
- List responseParameters = item.getResponseParameters();
- this.saveParams(responseParameters, docItem, p -> ParamStyleEnum.RESPONSE, user);
- }
- }
- return module;
- }
-
- private void saveParams(
- List parameters
- , DocInfo docItem
- , Function styleEnumFunction
- , User user
- ) {
- if (CollectionUtils.isEmpty(parameters)) {
- return;
- }
- for (DocParameter parameter : parameters) {
- this.saveDocParam(parameter, docItem, 0, styleEnumFunction, user);
- }
-
- }
-
private void savePostmanParams(
List parameters
, DocInfo docItem
@@ -369,19 +258,6 @@ public class DocImportService {
}
- private DocItemCreateDTO buildDocItemCreateDTO(DocItem item, DocInfo parent, User user) {
- DocItemCreateDTO docItemCreateDTO = new DocItemCreateDTO();
- docItemCreateDTO.setName(item.getSummary());
- docItemCreateDTO.setUrl(item.getPath());
- docItemCreateDTO.setContentType(StringUtils.join(item.getConsumes(), ','));
- docItemCreateDTO.setHttpMethod(item.getMethod());
- docItemCreateDTO.setDescription(item.getDescription());
- docItemCreateDTO.setModuleId(parent.getModuleId());
- docItemCreateDTO.setParentId(parent.getId());
- docItemCreateDTO.setUser(user);
- return docItemCreateDTO;
- }
-
private DocItemCreateDTO buildPostmanDocItemCreateDTO(Item item, DocInfo parent, Module module, User user) {
Request request = item.getRequest();
String url = request.getUrl().getFullUrl();
@@ -422,21 +298,4 @@ public class DocImportService {
}
}
- private ParamStyleEnum buildStyleEnum(IParam docParameter) {
- String in = ((DocParameter)docParameter).getIn();
- if (in == null) {
- in = "request";
- }
- switch (in) {
- case "path":
- return ParamStyleEnum.PATH;
- case "query":
- return ParamStyleEnum.QUERY;
- case "header":
- return ParamStyleEnum.HEADER;
- default:
- return ParamStyleEnum.REQUEST;
- }
- }
-
}
diff --git a/server/server-service/src/main/java/cn/torna/service/DocSwaggerImportService.java b/server/server-service/src/main/java/cn/torna/service/DocSwaggerImportService.java
new file mode 100644
index 0000000000000000000000000000000000000000..35bcc2ad0977ce3cfc7317c910f3aa0ccec53304
--- /dev/null
+++ b/server/server-service/src/main/java/cn/torna/service/DocSwaggerImportService.java
@@ -0,0 +1,328 @@
+package cn.torna.service;
+
+import cn.torna.common.bean.Booleans;
+import cn.torna.common.bean.HttpHelper;
+import cn.torna.common.bean.User;
+import cn.torna.common.enums.ModuleTypeEnum;
+import cn.torna.common.enums.ParamStyleEnum;
+import cn.torna.common.enums.SyncModeEnum;
+import cn.torna.common.exception.BizException;
+import cn.torna.common.util.DataIdUtil;
+import cn.torna.dao.entity.DocInfo;
+import cn.torna.dao.entity.DocParam;
+import cn.torna.dao.entity.Module;
+import cn.torna.manager.doc.DocParser;
+import cn.torna.manager.doc.IParam;
+import cn.torna.manager.doc.swagger.*;
+import cn.torna.service.dto.DocItemCreateDTO;
+import cn.torna.service.dto.ImportSwaggerDTO;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.parser.Feature;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.BooleanUtils;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.Assert;
+import org.springframework.util.CollectionUtils;
+
+import java.io.IOException;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * @author tanghc
+ */
+@Service
+@Slf4j
+public class DocSwaggerImportService {
+
+ @Autowired
+ @Qualifier("swaggerDocParserV2")
+ private DocParser docParserV2;
+
+ @Autowired
+ @Qualifier("swaggerDocParserV3")
+ private DocParser docParserV3;
+
+ @Autowired
+ private DocInfoService docInfoService;
+
+ @Autowired
+ private DocParamService docParamService;
+
+ @Autowired
+ private ModuleService moduleService;
+
+ @Autowired
+ private ModuleConfigService moduleConfigService;
+
+ /**
+ * 导入swagger文档
+ *
+ * @param importSwaggerDTO importSwaggerDTO
+ */
+ @Transactional(rollbackFor = Exception.class)
+ public Module importSwagger(ImportSwaggerDTO importSwaggerDTO) {
+ String json;
+ String url = importSwaggerDTO.getImportUrl();
+ try {
+ HttpHelper.ResponseResult responseResult = HttpHelper
+ .create()
+ .basicAuth(importSwaggerDTO.getBasicAuthUsername(), importSwaggerDTO.getBasicAuthPassword())
+ .url(url)
+ .method("get")
+ .execute();
+ String body = responseResult.asString();
+ int status = responseResult.getStatus();
+ if (status == HttpStatus.UNAUTHORIZED.value()) {
+ throw new BizException("认证失败");
+ }
+ if (status != HttpStatus.OK.value()) {
+ log.error("导入swagger错误,url:{}, \n{}", url, body);
+ throw new BizException("导入错误,请查看日志");
+ }
+ json = body;
+ } catch (IOException e) {
+ log.error("导入swagger异常, url:{}", url, e);
+ throw new BizException("导入异常, msg:" + e.getMessage());
+ }
+ JSONObject docRoot = JSON.parseObject(json, Feature.OrderedField, Feature.DisableCircularReferenceDetect);
+ DocParser docParser = docRoot.containsKey("openapi") ? docParserV3 : docParserV2;
+ DocBean docBean = docParser.parseJson(json);
+ if (SyncModeEnum.COVER.equals(importSwaggerDTO.getSyncMode())) {
+ return this.saveDocToDb(docBean, importSwaggerDTO);
+ }
+ return this.mergeDocToDb(docBean, importSwaggerDTO);
+ }
+
+ /**
+ * 保存文档到数据库
+ *
+ * @param docBean
+ * @param importSwaggerDTO
+ */
+ private Module saveDocToDb(DocBean docBean, ImportSwaggerDTO importSwaggerDTO) {
+ User user = importSwaggerDTO.getUser();
+ String title = docBean.getTitle();
+ // 创建模块
+ Module module = moduleService.createSwaggerModule(importSwaggerDTO, title);
+ // 保存调试环境
+ for (Server server : docBean.getServers()) {
+ moduleConfigService.setDebugEnv(module.getId(), server.getDescription(), server.getUrl());
+ }
+ // 创建文档分类
+ List docModules = docBean.getDocModules();
+ docModules.sort(Comparator.comparing(DocModule::getOrder));
+ for (DocModule docModule : docModules) {
+ DocInfo moduleDocInfo = docInfoService.createDocFolder(docModule.getModule(), module.getId(), user);
+ // 创建模块下的文档
+ List items = docModule.getItems();
+ for (DocItem item : items) {
+ DocItemCreateDTO docItemCreateDTO = this.buildDocItemCreateDTO(item, moduleDocInfo, user);
+ DocInfo docItem = docInfoService.createDocItem(docItemCreateDTO);
+ // query参数
+ List queryParameters = item.getQueryParameters();
+ this.saveParams(queryParameters, docItem, Function.identity(), user);
+ // body参数
+ List requestParameters = item.getRequestParameters();
+ this.saveParams(requestParameters, docItem, Function.identity(), user);
+ List responseParameters = item.getResponseParameters();
+ this.saveParams(responseParameters, docItem, docParam -> {
+ docParam.setStyle(ParamStyleEnum.RESPONSE.getStyle());
+ return docParam;
+ }, user);
+ }
+ }
+ return module;
+ }
+
+
+ /**
+ * 合并文档到数据库
+ *
+ * @param docBean
+ * @param importSwaggerDTO
+ */
+ private Module mergeDocToDb(DocBean docBean, ImportSwaggerDTO importSwaggerDTO) {
+ User user = importSwaggerDTO.getUser();
+ String title = docBean.getTitle();
+ // 创建模块
+ Module module = this.mergeSwaggerModule(importSwaggerDTO, title);
+ // 保存调试环境
+ for (Server server : docBean.getServers()) {
+ moduleConfigService.setDebugEnv(module.getId(), server.getDescription(), server.getUrl());
+ }
+ // 创建文档分类
+ List docModules = docBean.getDocModules();
+ docModules.sort(Comparator.comparing(DocModule::getOrder));
+ List oldDocModules = docInfoService.listModuleDoc(module.getId());
+ Map oldDocModuleVersionMap = oldDocModules.stream().collect(Collectors.toMap(DocInfo::getDataId, a->a));
+ for (DocModule docModule : docModules) {
+ String docModuleDataId = DataIdUtil.getFolderDataId(module.getId(), 0L, docModule.getModule());
+ DocInfo moduleDocInfo;
+ if ((moduleDocInfo = oldDocModuleVersionMap.get(docModuleDataId)) == null|| isToUpdate(moduleDocInfo.getVersion())) {
+ moduleDocInfo = docInfoService.createDocFolder(docModule.getModule(), module.getId(), user);
+ }
+ // 创建模块下的文档
+ List items = docModule.getItems();
+ for (DocItem item : items) {
+ DocItemCreateDTO docItemCreateDTO = this.buildDocItemCreateDTO(item, moduleDocInfo, user);
+ String docInfoDataId = DataIdUtil.getDocInfoDataId(false, module.getId(), moduleDocInfo.getId(), docModule.getModule(), item.getPath(), item.getMethod());
+ DocInfo docItem;
+ if ((docItem = oldDocModuleVersionMap.get(docInfoDataId)) == null|| isToUpdate(docItem.getVersion())) {
+ docItem = docInfoService.createDocItem(docItemCreateDTO);
+ }
+ // query参数
+ List oldDocParams = docParamService.listParentParam(docItem.getId());
+ Map oldDocParamsVersionMap = oldDocParams.stream().collect(Collectors.toMap(DocParam::getDataId, a->a));
+ List queryParameters = item.getQueryParameters();
+ this.saveParams(queryParameters, docItem, docParam -> oldDocParamsVersionMap.get(docParam.getDataId()), user);
+ // body参数
+ List requestParameters = item.getRequestParameters();
+ this.saveParams(requestParameters, docItem, docParam -> oldDocParamsVersionMap.get(docParam.getDataId()), user);
+ List responseParameters = item.getResponseParameters();
+ this.saveParams(responseParameters, docItem, docParam -> {
+ docParam.setStyle(ParamStyleEnum.RESPONSE.getStyle());
+ return oldDocParamsVersionMap.get(docParam.getDataId());
+ }, user);
+ }
+ }
+ return module;
+ }
+
+ private boolean isToUpdate(Double version) {
+ return (version == null || (version - version.intValue()) == 0);
+ }
+
+ /**
+ * 合并swagger导入模块
+ */
+ public Module mergeSwaggerModule(ImportSwaggerDTO importSwaggerDTO, String name) {
+ Assert.notNull(name, () -> "name不能为空");
+ User user = importSwaggerDTO.getUser();
+ Long projectId = importSwaggerDTO.getProjectId();
+ Module module = moduleService.getByProjectIdAndUrl(projectId, importSwaggerDTO.getImportUrl());
+ if (module == null) {
+ module = new Module();
+ module.setName(name);
+ module.setProjectId(projectId);
+ module.setType(ModuleTypeEnum.SWAGGER_IMPORT.getType());
+ module.setImportUrl(importSwaggerDTO.getImportUrl());
+ module.setBasicAuthUsername(importSwaggerDTO.getBasicAuthUsername());
+ module.setBasicAuthPassword(importSwaggerDTO.getBasicAuthPassword());
+ module.setToken(ModuleService.createToken());
+ module.setCreateMode(user.getOperationModel());
+ module.setModifyMode(user.getOperationModel());
+ module.setCreatorId(user.getUserId());
+ module.setModifierId(user.getUserId());
+ moduleService.save(module);
+ } else {
+ if (module.getVersion() == null || (module.getVersion() - module.getVersion().intValue()) == 0) {
+ module.setName(name);
+ module.setVersion(1.0);
+ moduleService.update(module);
+ }
+ }
+ return module;
+ }
+
+ private void saveParams(
+ List parameters
+ , DocInfo docItem
+ , Function processFunction
+ , User user
+ ) {
+ if (CollectionUtils.isEmpty(parameters)) {
+ return;
+ }
+ for (DocParameter parameter : parameters) {
+ this.saveDocParam(parameter, docItem, 0, processFunction, user);
+ }
+
+ }
+
+ private void saveDocParam(
+ IParam docParameter
+ , DocInfo docInfo
+ , long parentId
+ , Function processFunction
+ , User user
+ ) {
+ DocParam docParam = new DocParam();
+ ParamStyleEnum styleEnum = buildStyleEnum(docParameter);
+ String dataId = DataIdUtil.getDocParamDataId(docInfo.getId(), parentId, styleEnum.getStyle(), docParameter.getName());
+ docParam.setDataId(dataId);
+ docParam.setName(docParameter.getName());
+ docParam.setType(docParameter.getType());
+ docParam.setRequired(BooleanUtils.toIntegerObject(docParameter.getRequired()).byteValue());
+ docParam.setMaxLength(docParameter.getMaxLength());
+ docParam.setExample(docParameter.getExample());
+ docParam.setDescription(docParameter.getDescription());
+ docParam.setDocId(docInfo.getId());
+ docParam.setParentId(parentId);
+ docParam.setStyle(styleEnum.getStyle());
+ docParam.setCreatorId(user.getUserId());
+ docParam.setCreateMode(user.getOperationModel());
+ docParam.setCreatorName(user.getNickname());
+ docParam.setModifierId(user.getUserId());
+ docParam.setModifyMode(user.getOperationModel());
+ docParam.setModifierName(user.getNickname());
+ docParam.setIsDeleted(Booleans.FALSE);
+ // 保存操作
+ DocParam temp = processFunction.apply(docParam);
+ if (temp == null || isToUpdate(temp.getVersion())) {
+ docParam = docParamService.saveParam(docParam);
+ }else {
+ docParam.setId(temp.getId());
+ }
+
+ // 处理子节点
+ List children = docParameter.getChildren();
+ if (children != null) {
+ for (IParam child : children) {
+ this.saveDocParam(child, docInfo, docParam.getId(), processFunction, user);
+ }
+ }
+ }
+
+
+ private DocItemCreateDTO buildDocItemCreateDTO(DocItem item, DocInfo parent, User user) {
+ DocItemCreateDTO docItemCreateDTO = new DocItemCreateDTO();
+ docItemCreateDTO.setName(item.getSummary());
+ docItemCreateDTO.setUrl(item.getPath());
+ docItemCreateDTO.setContentType(StringUtils.join(item.getConsumes(), ','));
+ docItemCreateDTO.setHttpMethod(item.getMethod());
+ docItemCreateDTO.setDescription(item.getDescription());
+ docItemCreateDTO.setModuleId(parent.getModuleId());
+ docItemCreateDTO.setParentId(parent.getId());
+ docItemCreateDTO.setUser(user);
+ return docItemCreateDTO;
+ }
+
+
+ private ParamStyleEnum buildStyleEnum(IParam docParameter) {
+ String in = ((DocParameter)docParameter).getIn();
+ if (in == null) {
+ in = "request";
+ }
+ switch (in) {
+ case "path":
+ return ParamStyleEnum.PATH;
+ case "query":
+ return ParamStyleEnum.QUERY;
+ case "header":
+ return ParamStyleEnum.HEADER;
+ default:
+ return ParamStyleEnum.REQUEST;
+ }
+ }
+
+}
diff --git a/server/server-service/src/main/java/cn/torna/service/ModuleService.java b/server/server-service/src/main/java/cn/torna/service/ModuleService.java
index 4ee5a81b41359dc5cfcbea24c1db4e1aa7acad42..2a7a37daec51884963162dc6443f8a85935a546d 100644
--- a/server/server-service/src/main/java/cn/torna/service/ModuleService.java
+++ b/server/server-service/src/main/java/cn/torna/service/ModuleService.java
@@ -78,7 +78,7 @@ public class ModuleService extends BaseService {
Assert.notNull(name, () -> "name不能为空");
User user = importSwaggerDTO.getUser();
Long projectId = importSwaggerDTO.getProjectId();
- Module module = getByProjectIdAndName(projectId, name);
+ Module module = getByProjectIdAndUrl(projectId, importSwaggerDTO.getImportUrl());
if (module == null) {
module = new Module();
module.setName(name);
@@ -122,6 +122,13 @@ public class ModuleService extends BaseService {
return get(query);
}
+ public Module getByProjectIdAndUrl(long projectId, String url) {
+ Query query = new Query()
+ .eq("project_id", projectId)
+ .eq("import_url", url);
+ return get(query);
+ }
+
public void delete(long moduleId, User user) {
if (user.isSuperAdmin()) {
Module module = getById(moduleId);
diff --git a/server/server-service/src/main/java/cn/torna/service/dto/DocParamDTO.java b/server/server-service/src/main/java/cn/torna/service/dto/DocParamDTO.java
index 078cb0018390afb5aea7742a92e55ecfecc70ab4..0534cbfa67ee59fb894faff7ff9db64dbd5e4c1b 100644
--- a/server/server-service/src/main/java/cn/torna/service/dto/DocParamDTO.java
+++ b/server/server-service/src/main/java/cn/torna/service/dto/DocParamDTO.java
@@ -66,6 +66,8 @@ public class DocParamDTO {
private Byte isDeleted;
+ private Byte isModified;
+
/** 数据库字段:gmt_create */
private Date gmtCreate;
diff --git a/server/server-service/src/main/java/cn/torna/service/dto/ImportSwaggerDTO.java b/server/server-service/src/main/java/cn/torna/service/dto/ImportSwaggerDTO.java
index a62dff56b442a285c81f07f276775779203c32f9..f67e3a4439ddc08458a48583f0f24cb2b97baf07 100644
--- a/server/server-service/src/main/java/cn/torna/service/dto/ImportSwaggerDTO.java
+++ b/server/server-service/src/main/java/cn/torna/service/dto/ImportSwaggerDTO.java
@@ -1,6 +1,7 @@
package cn.torna.service.dto;
import cn.torna.common.bean.User;
+import cn.torna.common.enums.SyncModeEnum;
import cn.torna.common.support.IdCodec;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
@@ -22,4 +23,10 @@ public class ImportSwaggerDTO {
private User user;
+ /**
+ * 同步模式
+ * 0:覆盖 1:合并
+ */
+ private SyncModeEnum syncMode;
+
}
diff --git a/server/server-web/src/main/java/cn/torna/web/controller/module/ModuleController.java b/server/server-web/src/main/java/cn/torna/web/controller/module/ModuleController.java
index 747b1bf439ae9d54a151034d4bce26463a28d308..6f2ae2d348357af89a9a9294359e4ef6a4b17093 100644
--- a/server/server-web/src/main/java/cn/torna/web/controller/module/ModuleController.java
+++ b/server/server-web/src/main/java/cn/torna/web/controller/module/ModuleController.java
@@ -5,13 +5,15 @@ import cn.torna.common.bean.Result;
import cn.torna.common.bean.User;
import cn.torna.common.context.UserContext;
import cn.torna.common.enums.ModuleTypeEnum;
+import cn.torna.common.enums.SyncModeEnum;
import cn.torna.common.exception.BizException;
import cn.torna.common.util.CopyUtil;
import cn.torna.common.util.IdUtil;
import cn.torna.dao.entity.DocInfo;
import cn.torna.dao.entity.Module;
-import cn.torna.service.DocImportService;
+import cn.torna.service.DocPostManImportService;
import cn.torna.service.DocInfoService;
+import cn.torna.service.DocSwaggerImportService;
import cn.torna.service.ModuleService;
import cn.torna.service.dto.ImportPostmanDTO;
import cn.torna.service.dto.ImportSwaggerDTO;
@@ -23,11 +25,7 @@ import cn.torna.web.controller.module.vo.ModuleVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;
@@ -46,7 +44,9 @@ public class ModuleController {
private ModuleService moduleService;
@Autowired
- private DocImportService docImportService;
+ private DocPostManImportService docPostManImportService;
+ @Autowired
+ private DocSwaggerImportService docSwaggerImportService;
@Autowired
private DocInfoService docInfoService;
@@ -104,6 +104,7 @@ public class ModuleController {
module.setName(param.getName());
module.setModifierId(user.getUserId());
module.setModifyMode(user.getOperationModel());
+ module.setVersion(module.getVersion() + 0.001);
moduleService.update(module);
return Result.ok();
}
@@ -130,7 +131,7 @@ public class ModuleController {
ImportSwaggerDTO importSwaggerDTO = CopyUtil.copyBean(param, ImportSwaggerDTO::new);
User user = UserContext.getUser();
importSwaggerDTO.setUser(user);
- Module module = docImportService.importSwagger(importSwaggerDTO);
+ Module module = docSwaggerImportService.importSwagger(importSwaggerDTO);
ModuleVO moduleVO = CopyUtil.copyBean(module, ModuleVO::new);
return Result.ok(moduleVO);
}
@@ -150,7 +151,7 @@ public class ModuleController {
importPostmanDTO.setJson(json);
importPostmanDTO.setProjectId(IdUtil.decode(projectId));
importPostmanDTO.setUser(user);
- Module module = docImportService.importPostman(importPostmanDTO);
+ Module module = docPostManImportService.importPostman(importPostmanDTO);
ModuleVO moduleVO = CopyUtil.copyBean(module, ModuleVO::new);
return Result.ok(moduleVO);
} catch (Exception e) {
@@ -165,13 +166,14 @@ public class ModuleController {
* @return
*/
@GetMapping("refresh/swagger")
- public Result refreshSwaggerDoc(@HashId Long moduleId) {
+ public Result refreshSwaggerDoc(@HashId Long moduleId, @RequestParam(required = false, defaultValue = "MERGE") String syncMode) {
Module module = moduleService.getById(moduleId);
if (module != null && module.getType() == ModuleTypeEnum.SWAGGER_IMPORT.getType()) {
ImportSwaggerDTO importSwaggerDTO = CopyUtil.copyBean(module, ImportSwaggerDTO::new);
User user = UserContext.getUser();
importSwaggerDTO.setUser(user);
- docImportService.importSwagger(importSwaggerDTO);
+ importSwaggerDTO.setSyncMode(SyncModeEnum.valueOf(syncMode));
+ docSwaggerImportService.importSwagger(importSwaggerDTO);
}
return Result.ok();
}