From f21a4a5c5dea8759ae9fdf19fc6ce8de2b99c642 Mon Sep 17 00:00:00 2001 From: guoyuqi Date: Wed, 29 Jun 2022 17:15:57 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E6=8E=A5=E5=8F=A3=E6=B5=8B=E8=AF=95):=20?= =?UTF-8?q?=E5=9C=BA=E6=99=AF=E6=8E=A5=E5=8F=A3=E6=A8=A1=E5=9D=97=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E9=80=BB=E8=BE=91=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --user=郭雨琦 --- .../automation/UpdateScenarioModuleDTO.java | 1 + .../dto/definition/UpdateApiModuleDTO.java | 3 +- .../api/service/ApiAutomationService.java | 20 +- .../api/service/ApiDefinitionService.java | 20 +- .../api/service/ApiModuleService.java | 429 +++++++++++------- .../api/service/ApiScenarioModuleService.java | 223 +++++---- .../mapper/ext/ExtApiDefinitionMapper.java | 4 +- .../mapper/ext/ExtApiDefinitionMapper.xml | 10 +- .../base/mapper/ext/ExtApiScenarioMapper.java | 4 +- .../base/mapper/ext/ExtApiScenarioMapper.xml | 9 +- 10 files changed, 462 insertions(+), 261 deletions(-) diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/UpdateScenarioModuleDTO.java b/backend/src/main/java/io/metersphere/api/dto/automation/UpdateScenarioModuleDTO.java index 25db523151..534d963ba8 100644 --- a/backend/src/main/java/io/metersphere/api/dto/automation/UpdateScenarioModuleDTO.java +++ b/backend/src/main/java/io/metersphere/api/dto/automation/UpdateScenarioModuleDTO.java @@ -11,5 +11,6 @@ import java.util.List; @Setter public class UpdateScenarioModuleDTO { private List moduleList; + private List needUpdateList; private List apiScenarioWithBLOBsList; } diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/UpdateApiModuleDTO.java b/backend/src/main/java/io/metersphere/api/dto/definition/UpdateApiModuleDTO.java index 6a6159cdc1..de4b644e26 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/UpdateApiModuleDTO.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/UpdateApiModuleDTO.java @@ -11,6 +11,7 @@ import java.util.List; @Setter public class UpdateApiModuleDTO { private List moduleList; - private List apiDefinitionWithBLOBsList; + private List needUpdateList; + private List definitionWithBLOBs; } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java index c96f88c526..725c2756f0 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java @@ -76,6 +76,8 @@ import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; +import static java.util.stream.Collectors.toList; + @Service @Transactional(rollbackFor = Exception.class) public class ApiAutomationService { @@ -1336,17 +1338,21 @@ public class ApiAutomationService { ApiDefinitionMapper apiDefinitionMapper = sqlSession.getMapper(ApiDefinitionMapper.class); ApiScenarioModuleMapper apiScenarioModuleMapper = sqlSession.getMapper(ApiScenarioModuleMapper.class); - List data = apiImport.getData(); + List initData = apiImport.getData(); currentScenarioOrder.remove(); - UpdateScenarioModuleDTO updateScenarioModuleDTO = apiScenarioModuleService.checkScenarioModule(request.getModuleId(), request.getProjectId(), data, StringUtils.equals("fullCoverage", request.getModeId()), request.getCoverModule()); + UpdateScenarioModuleDTO updateScenarioModuleDTO = apiScenarioModuleService.checkScenarioModule(request, initData, StringUtils.equals("fullCoverage", request.getModeId()), request.getCoverModule()); List moduleList = updateScenarioModuleDTO.getModuleList(); - List apiScenarioWithBLOBsList = updateScenarioModuleDTO.getApiScenarioWithBLOBsList(); - for (ApiScenarioModule apiScenarioModule : moduleList) { - apiScenarioModuleMapper.insert(apiScenarioModule); + List data = updateScenarioModuleDTO.getApiScenarioWithBLOBsList(); + List needUpdateList = updateScenarioModuleDTO.getNeedUpdateList(); + + if (moduleList != null) { + for (ApiScenarioModule apiScenarioModule : moduleList) { + apiScenarioModuleMapper.insert(apiScenarioModule); + } } int num = 0; - Project project = new Project(); + Project project; if (!CollectionUtils.isEmpty(data) && data.get(0) != null && data.get(0).getProjectId() != null) { project = projectMapper.selectByPrimaryKey(data.get(0).getProjectId()); ProjectConfig config = projectApplicationService.getSpecificTypeValue(project.getId(), ProjectApplicationType.SCENARIO_CUSTOM_NUM.name()); @@ -1358,7 +1364,7 @@ public class ApiAutomationService { for (int i = 0; i < data.size(); i++) { ApiScenarioWithBLOBs item = data.get(i); - List sameList = apiScenarioWithBLOBsList.stream().filter(t -> t.getName().equals(item.getName())).collect(Collectors.toList()); + List sameList = needUpdateList.stream().filter(t -> t.getId().equals(item.getId())).collect(toList()); if (StringUtils.isBlank(item.getCreateUser())) { item.setCreateUser(SessionUtils.getUserId()); } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java index c5c68b7b2f..a76e380703 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java @@ -1376,25 +1376,29 @@ public class ApiDefinitionService { SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); currentApiCaseOrder.remove(); currentApiOrder.remove(); - List data = apiImport.getData(); + String defaultVersion = extProjectVersionMapper.getDefaultVersion(request.getProjectId()); + request.setDefaultVersion(defaultVersion); + List initData = apiImport.getData(); Project project = projectMapper.selectByPrimaryKey(request.getProjectId()); ProjectConfig config = projectApplicationService.getSpecificTypeValue(project.getId(), ProjectApplicationType.URL_REPEATABLE.name()); boolean urlRepeat = config.getUrlRepeatable(); - UpdateApiModuleDTO updateApiModuleDTO = apiModuleService.checkApiModule(request.getModuleId(), request.getProjectId(), apiImport.getProtocol(), data, StringUtils.equals("fullCoverage", request.getModeId()), request.getCoverModule(), urlRepeat); - List updateList = updateApiModuleDTO.getApiDefinitionWithBLOBsList(); + UpdateApiModuleDTO updateApiModuleDTO = apiModuleService.checkApiModule(request, apiImport, initData, StringUtils.equals("fullCoverage", request.getModeId()), urlRepeat); + List updateList = updateApiModuleDTO.getNeedUpdateList(); + List data = updateApiModuleDTO.getDefinitionWithBLOBs(); + List moduleList = updateApiModuleDTO.getModuleList(); ApiDefinitionMapper batchMapper = sqlSession.getMapper(ApiDefinitionMapper.class); ApiTestCaseMapper apiTestCaseMapper = sqlSession.getMapper(ApiTestCaseMapper.class); ExtApiDefinitionMapper extApiDefinitionMapper = sqlSession.getMapper(ExtApiDefinitionMapper.class); ApiModuleMapper apiModuleMapper = sqlSession.getMapper(ApiModuleMapper.class); + int num = 0; if (!CollectionUtils.isEmpty(data) && data.get(0) != null && data.get(0).getProjectId() != null) { num = getNextNum(data.get(0).getProjectId()); } - String defaultVersion = extProjectVersionMapper.getDefaultVersion(request.getProjectId()); - request.setDefaultVersion(defaultVersion); + for (int i = 0; i < data.size(); i++) { ApiDefinitionWithBLOBs item = data.get(i); this.setModule(item); @@ -1416,8 +1420,10 @@ public class ApiDefinitionService { } else { importCreate(item, batchMapper, apiTestCaseMapper, extApiDefinitionMapper, request, apiImport.getCases(), apiImport.getMocks(), updateList); } - for (ApiModule apiModule : updateApiModuleDTO.getModuleList()) { - apiModuleMapper.insert(apiModule); + if (moduleList != null) { + for (ApiModule apiModule : moduleList) { + apiModuleMapper.insert(apiModule); + } } if (i % 300 == 0) { sqlSession.flushStatements(); diff --git a/backend/src/main/java/io/metersphere/api/service/ApiModuleService.java b/backend/src/main/java/io/metersphere/api/service/ApiModuleService.java index feab6487c2..75ad5e01ec 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiModuleService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiModuleService.java @@ -2,7 +2,9 @@ package io.metersphere.api.service; import com.alibaba.fastjson.JSON; +import io.metersphere.api.dto.ApiTestImportRequest; import io.metersphere.api.dto.definition.*; +import io.metersphere.api.dto.definition.parse.ApiDefinitionImport; import io.metersphere.base.domain.*; import io.metersphere.base.mapper.ApiDefinitionMapper; import io.metersphere.base.mapper.ApiModuleMapper; @@ -10,6 +12,7 @@ import io.metersphere.base.mapper.ext.ExtApiDefinitionMapper; import io.metersphere.base.mapper.ext.ExtApiModuleMapper; import io.metersphere.commons.constants.TestCaseConstants; import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.utils.BeanUtils; import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.i18n.Translator; @@ -600,190 +603,307 @@ public class ApiModuleService extends NodeTreeService { /** * 上传文件时对文件的模块进行检测 * - * @param moduleId 上传文件时选的模块ID - * @param projectId - * @param protocol * @param data - * @param fullCoverage 是否覆盖接口 - * @param fullCoverageApi 是否更新当前接口所在模块 (如果开启url重复,可重复的是某一模块下的接口,注:只在这个模块下,不包含其子模块) + * @param fullCoverage 是否覆盖接口 * @return Return to the newly added module list and api list */ - public UpdateApiModuleDTO checkApiModule(String moduleId, String projectId, String protocol, List data, Boolean fullCoverage, Boolean fullCoverageApi, boolean urlRepeat) { - Map map = new HashMap<>(); - Map updateApiMap = new HashMap<>(); + public UpdateApiModuleDTO checkApiModule(ApiTestImportRequest request, ApiDefinitionImport apiImport, List data, Boolean fullCoverage, boolean urlRepeat) { + Boolean fullCoverageApi = request.getCoverModule(); + String projectId = request.getProjectId(); + String protocol = request.getProtocol(); + //上传文件时选的模块ID + String chooseModuleId = request.getModuleId(); + //标准版ESB数据导入不区分是否覆盖,默认都为覆盖 + if (apiImport.getEsbApiParamsMap() != null) { + fullCoverage = true; + } + String updateVersionId = getUpdateVersionId(request, fullCoverage); + + //需要新增的模块,key 为模块路径 + Map moduleMap = new HashMap<>(); + //系统原有的需要更新的list, + List toUpdateList = new ArrayList<>(); //获取当前项目的当前协议下的所有模块的Tree List apiModules = this.getApiModulesByProjectAndPro(projectId, protocol); List nodeTreeByProjectId = this.getNodeTrees(apiModules); - Map> pidChildrenMap = new HashMap<>(); - Map idPathMap = new HashMap<>(); + //所有模块的ID 及其自身 的map Map idModuleMap = apiModules.stream().collect(Collectors.toMap(ApiModuleDTO::getId, apiModuleDTO -> apiModuleDTO)); - buildProcessData(nodeTreeByProjectId, pidChildrenMap, idPathMap); - Map methodPathMap = data.stream().collect(Collectors.toMap(t -> t.getMethod() + t.getPath(), apiDefinition -> apiDefinition)); + //父级ID与其子模块集合的map + Map> pidChildrenMap = new HashMap<>(); + //所有模块的ID 及其全路径的map + Map idPathMap = new HashMap<>(); + + String initParentModulePath = "/root"; + Map initParentModulePathMap = new HashMap<>(); + initParentModulePathMap.put("root", initParentModulePath); + buildProcessData(nodeTreeByProjectId, pidChildrenMap, idPathMap, initParentModulePathMap); + //获取选中的模块 ApiModuleDTO chooseModule = null; - if (moduleId != null) { - chooseModule = idModuleMap.get(moduleId); + if (chooseModuleId != null) { + chooseModule = idModuleMap.get(chooseModuleId); } + + List optionData = new ArrayList<>(); + + //去重 如果url可重复 则模块+名称+请求方式+路径 唯一,否则 请求方式+路径唯一, + //覆盖模式留重复的最后一个,不覆盖留第一个 + removeRepeat(data, fullCoverage, urlRepeat, optionData); + + //处理模块 + setModule(moduleMap, pidChildrenMap, idPathMap, idModuleMap, optionData, chooseModule); + + //系统内重复的数据 List repeatApiDefinitionWithBLOBs; if (chooseModule != null) { - repeatApiDefinitionWithBLOBs = extApiDefinitionMapper.selectRepeatByBLOBsSameUrl(data, chooseModule.getId()); + repeatApiDefinitionWithBLOBs = extApiDefinitionMapper.selectRepeatByBLOBsSameUrl(data, projectId, chooseModule.getId(), updateVersionId); } else { - repeatApiDefinitionWithBLOBs = extApiDefinitionMapper.selectRepeatByBLOBs(data); + repeatApiDefinitionWithBLOBs = extApiDefinitionMapper.selectRepeatByBLOBs(data, projectId, updateVersionId); } - //允许接口重复 + //处理数据 if (urlRepeat) { - //允许覆盖接口 + //按照原来的顺序 + Map methodPathMap = data.stream().collect(Collectors.toMap(t -> t.getName() + t.getMethod() + t.getPath() + (t.getModulePath() == null ? "" : t.getModulePath()), api -> api)); + //覆盖接口 if (fullCoverage) { - //允许覆盖模块 + //允许覆盖模块,用导入的重复数据的最后一条覆盖查询的所有重复数据 if (fullCoverageApi) { - coverApiModule(map, updateApiMap, pidChildrenMap, idPathMap, idModuleMap, methodPathMap, chooseModule, repeatApiDefinitionWithBLOBs); + if (!repeatApiDefinitionWithBLOBs.isEmpty()) { + Map> repeatDataMap = repeatApiDefinitionWithBLOBs.stream().collect(Collectors.groupingBy(t -> t.getName() + t.getMethod() + t.getPath() + t.getModulePath())); + startCoverModule(toUpdateList, optionData, methodPathMap, repeatDataMap); + } } else { //覆盖但不覆盖模块 - justCoverApi(map, updateApiMap, pidChildrenMap, idPathMap, idModuleMap, methodPathMap, chooseModule, repeatApiDefinitionWithBLOBs); + if (!repeatApiDefinitionWithBLOBs.isEmpty()) { + Map> repeatDataMap = repeatApiDefinitionWithBLOBs.stream().collect(Collectors.groupingBy(t -> t.getName() + t.getMethod() + t.getPath() + t.getModulePath())); + moduleMap = judgeModuleMap(moduleMap, methodPathMap, repeatDataMap); + startCover(toUpdateList, optionData, methodPathMap, repeatDataMap); + } } } else { - //不覆盖接口,直接新增 - setModule(map, pidChildrenMap, idPathMap, idModuleMap, methodPathMap, chooseModule); + //不覆盖,同一接口不做更新 + if (!repeatApiDefinitionWithBLOBs.isEmpty()) { + Map> repeatDataMap = repeatApiDefinitionWithBLOBs.stream().collect(Collectors.groupingBy(t -> t.getName() + t.getMethod() + t.getPath() + t.getModulePath())); + removeSameData(repeatDataMap, methodPathMap, optionData); + } + } } else { - //不允许接口重复 + Map methodPathMap = optionData.stream().collect(Collectors.toMap(t -> t.getMethod() + t.getPath(), api -> api)); if (fullCoverage) { if (fullCoverageApi) { - coverApiModule(map, updateApiMap, pidChildrenMap, idPathMap, idModuleMap, methodPathMap, chooseModule, repeatApiDefinitionWithBLOBs); + if (!repeatApiDefinitionWithBLOBs.isEmpty()) { + Map> repeatDataMap = repeatApiDefinitionWithBLOBs.stream().collect(Collectors.groupingBy(t -> t.getMethod() + t.getPath())); + startCoverModule(toUpdateList, optionData, methodPathMap, repeatDataMap); + } } else { - //覆盖但不覆盖模块 - justCoverApi(map, updateApiMap, pidChildrenMap, idPathMap, idModuleMap, methodPathMap, chooseModule, repeatApiDefinitionWithBLOBs); - } - - } else { - //不覆盖接口 - if (!repeatApiDefinitionWithBLOBs.isEmpty()) { - Map collect = repeatApiDefinitionWithBLOBs.stream().collect(Collectors.toMap(t -> t.getMethod() + t.getPath(), apiDefinition -> apiDefinition)); - collect.forEach((k, v) -> { - if (methodPathMap.get(k) != null) { - methodPathMap.remove(k); + //不覆盖模块 + if (!repeatApiDefinitionWithBLOBs.isEmpty()) { + Map> repeatDataMap = repeatApiDefinitionWithBLOBs.stream().collect(Collectors.groupingBy(t -> t.getMethod() + t.getPath())); + if (repeatDataMap.size() >= methodPathMap.size()) { + //导入文件没有新增接口无需创建接口模块 + moduleMap = new HashMap<>(); } - }); + startCover(toUpdateList, optionData, methodPathMap, repeatDataMap); + } + } + } else { + //不覆盖,同一接口不做更新 + if (!repeatApiDefinitionWithBLOBs.isEmpty()) { + Map> repeatDataMap = repeatApiDefinitionWithBLOBs.stream().collect(Collectors.groupingBy(t -> t.getMethod() + t.getPath())); + removeSameData(repeatDataMap, methodPathMap, optionData); } - setModule(map, pidChildrenMap, idPathMap, idModuleMap, methodPathMap, chooseModule); } } - UpdateApiModuleDTO updateApiModuleDTO = new UpdateApiModuleDTO(); - updateApiModuleDTO.setModuleList((List) map.values()); - updateApiModuleDTO.setApiDefinitionWithBLOBsList((List) updateApiMap.values()); + updateApiModuleDTO.setModuleList(new ArrayList<>(moduleMap.values())); + updateApiModuleDTO.setNeedUpdateList(toUpdateList); + updateApiModuleDTO.setDefinitionWithBLOBs(optionData); return updateApiModuleDTO; } - private void coverApiModule(Map map, Map updateApiMap, Map> pidChildrenMap, Map idPathMap, Map idModuleMap, Map methodPathMap, ApiModuleDTO chooseModule, List repeatApiDefinitionWithBLOBs) { - if (!repeatApiDefinitionWithBLOBs.isEmpty()) { - Map collect = repeatApiDefinitionWithBLOBs.stream().collect(Collectors.toMap(t -> t.getMethod() + t.getPath(), apiDefinition -> apiDefinition)); - collect.forEach((k, v) -> { - ApiDefinitionWithBLOBs apiDefinitionWithBLOBs = methodPathMap.get(k); - if (apiDefinitionWithBLOBs != null) { - //Check whether the content has changed, if not, do not change the creatoCover - Boolean toCover = apiDefinitionService.checkIsSynchronize(v, apiDefinitionWithBLOBs); - //需要更新 - if (toCover) { - if (updateApiMap.get(k) != null) { - apiDefinitionWithBLOBs.setId(v.getId()); - updateApiMap.put(k, apiDefinitionWithBLOBs); - } - } else { - methodPathMap.remove(k); - } - } - }); - } - setModule(map, pidChildrenMap, idPathMap, idModuleMap, methodPathMap, chooseModule); - } - - private void justCoverApi(Map map, Map updateApiMap, Map> pidChildrenMap, Map idPathMap, Map idModuleMap, Map methodPathMap, ApiModuleDTO chooseModule, List repeatApiDefinitionWithBLOBs) { - if (!repeatApiDefinitionWithBLOBs.isEmpty()) { - Map collect = repeatApiDefinitionWithBLOBs.stream().collect(Collectors.toMap(t -> t.getMethod() + t.getPath(), apiDefinition -> apiDefinition)); - collect.forEach((k, v) -> { - ApiDefinitionWithBLOBs apiDefinitionWithBLOBs = methodPathMap.get(k); - if (apiDefinitionWithBLOBs != null) { - //Check whether the content has changed, if not, do not change the creatoCover - Boolean toCover = apiDefinitionService.checkIsSynchronize(v, apiDefinitionWithBLOBs); - //需要更新 - if (toCover) { - if (updateApiMap.get(k) != null) { - apiDefinitionWithBLOBs.setId(v.getId()); - updateApiMap.put(k, apiDefinitionWithBLOBs); - } - } - methodPathMap.remove(k); - } - }); - } - setModule(map, pidChildrenMap, idPathMap, idModuleMap, methodPathMap, chooseModule); - } - - private void setModule(Map map, Map> pidChildrenMap, Map idPathMap, Map idModuleMap, Map methodPathMap, ApiModuleDTO chooseModule) { - methodPathMap.forEach((methodPath, datum) -> { - String[] pathTree; - String modulePath = datum.getModulePath(); - ApiModule apiModule = map.get(modulePath); - if (chooseModule != null) { - if (chooseModule.getParentId() == null) { - chooseModule.setParentId("root"); - } - String chooseModuleParentId = chooseModule.getParentId(); - //导入时选了模块,且接口有模块的 - if (StringUtils.isNotBlank(modulePath)) { - List moduleList = pidChildrenMap.get(chooseModuleParentId); - String s; - if (chooseModuleParentId.equals("root")) { - s = "/" + chooseModule.getName(); - } else { - s = idPathMap.get(chooseModuleParentId); - } - pathTree = getPathTree(s + modulePath); - - ApiModule chooseModuleOne = JSON.parseObject(JSON.toJSONString(chooseModule), ApiModule.class); - ApiModule minModule = getMinModule(pathTree, moduleList, chooseModuleOne, pidChildrenMap, map, idPathMap, idModuleMap); - String id = minModule.getId(); - datum.setModuleId(id); - datum.setModulePath(idPathMap.get(id)); - } else { - //导入时选了模块,且接口没有模块的 - datum.setModuleId(chooseModule.getId()); - datum.setModulePath(idPathMap.get(chooseModule.getId())); - } + private void removeRepeat(List data, Boolean fullCoverage, boolean urlRepeat, List optionData) { + if (urlRepeat) { + LinkedHashMap> methodPathMap = data.stream().collect(Collectors.groupingBy(t -> t.getName() + t.getMethod() + t.getPath() + (t.getModulePath() == null ? "" : t.getModulePath()), LinkedHashMap::new, Collectors.toList())); + if (fullCoverage) { + methodPathMap.forEach((k, v) -> { + optionData.add(v.get(v.size() - 1)); + }); } else { - if (StringUtils.isNotBlank(modulePath)) { - //导入时没选模块但接口有模块的,根据modulePath,和当前协议查询当前项目里是否有同名称模块,如果有,就在该模块下建立接口,否则新建模块 - pathTree = getPathTree(modulePath); - if (apiModule != null) { - datum.setModuleId(apiModule.getId()); - datum.setModulePath(modulePath); - } else { - List moduleList = pidChildrenMap.get("root"); - ApiModule minModule = getMinModule(pathTree, moduleList, null, pidChildrenMap, map, idPathMap, idModuleMap); - String id = minModule.getId(); - datum.setModuleId(id); - datum.setModulePath(idPathMap.get(id)); - } - } else { - //导入时即没选中模块,接口自身也没模块的,直接返会当前项目,当前协议下的默认模块 - List moduleList = pidChildrenMap.get("root"); - for (ApiModule module : moduleList) { - if (module.getName().equals("未规划接口")) { - datum.setModuleId(module.getId()); - datum.setModulePath("/" + module.getName()); - } - } - } + methodPathMap.forEach((k, v) -> { + optionData.add(v.get(0)); + }); + } + } else { + LinkedHashMap> methodPathMap = data.stream().collect(Collectors.groupingBy(t -> t.getMethod() + t.getPath(), LinkedHashMap::new, Collectors.toList())); + if (fullCoverage) { + methodPathMap.forEach((k, v) -> { + optionData.add(v.get(v.size() - 1)); + }); + } else { + methodPathMap.forEach((k, v) -> { + optionData.add(v.get(0)); + }); + } + } + } + + private String getUpdateVersionId(ApiTestImportRequest request, Boolean fullCoverage) { + String updateVersionId; + if (!fullCoverage) { + if (request.getVersionId() == null) { + updateVersionId = request.getDefaultVersion(); + } else { + updateVersionId = request.getVersionId(); + } + } else { + if (request.getUpdateVersionId() == null) { + updateVersionId = request.getDefaultVersion(); + } else { + updateVersionId = request.getUpdateVersionId(); + } + } + return updateVersionId; + } + + private void removeSameData(Map> repeatDataMap, Map methodPathMap, List optionData) { + repeatDataMap.forEach((k, v) -> { + ApiDefinitionWithBLOBs apiDefinitionWithBLOBs = methodPathMap.get(k); + if (apiDefinitionWithBLOBs != null) { + optionData.remove(apiDefinitionWithBLOBs); } }); } + private void startCoverModule(List toUpdateList, List optionData, Map methodPathMap, Map> repeatDataMap) { + List coverApiList = new ArrayList<>(); + repeatDataMap.forEach((k, v) -> { + ApiDefinitionWithBLOBs apiDefinitionWithBLOBs = methodPathMap.get(k); + if (apiDefinitionWithBLOBs != null) { + for (ApiDefinitionWithBLOBs definitionWithBLOBs : v) { + ApiDefinitionWithBLOBs api = new ApiDefinitionWithBLOBs(); + BeanUtils.copyBean(api, apiDefinitionWithBLOBs); + api.setId(definitionWithBLOBs.getId()); + coverApiList.add(api); + } + optionData.remove(apiDefinitionWithBLOBs); + } + }); + buildOtherParam(toUpdateList, optionData, coverApiList); + } + + private void startCover(List toUpdateList, List optionData, Map methodPathMap, Map> repeatDataMap) { + List coverApiList = new ArrayList<>(); + repeatDataMap.forEach((k, v) -> { + ApiDefinitionWithBLOBs apiDefinitionWithBLOBs = methodPathMap.get(k); + if (apiDefinitionWithBLOBs != null) { + for (ApiDefinitionWithBLOBs definitionWithBLOBs : v) { + ApiDefinitionWithBLOBs api = new ApiDefinitionWithBLOBs(); + BeanUtils.copyBean(api, apiDefinitionWithBLOBs); + api.setId(definitionWithBLOBs.getId()); + api.setModuleId(definitionWithBLOBs.getModuleId()); + api.setModulePath(definitionWithBLOBs.getModulePath()); + coverApiList.add(api); + } + optionData.remove(apiDefinitionWithBLOBs); + } + }); + buildOtherParam(toUpdateList, optionData, coverApiList); + } + + private Map judgeModuleMap(Map moduleMap, Map methodPathMap, Map> repeatDataMap) { + Set repeatKeys = repeatDataMap.keySet(); + Set importKeys = methodPathMap.keySet(); + List repeatKeyList = new ArrayList<>(repeatKeys); + List importKeysList = new ArrayList<>(importKeys); + List intersection = repeatKeyList.stream().filter(item -> importKeysList.contains(item)).collect(Collectors.toList()); + if (intersection.size() == importKeysList.size()) { + //导入文件没有新增接口无需创建接口模块 + moduleMap = new HashMap<>(); + } + return moduleMap; + } + + private void buildOtherParam(List toUpdateList, List optionData, List coverApiList) { + optionData.addAll(coverApiList); + toUpdateList.addAll(coverApiList); + } + + private List setModule(Map moduleMap, Map> pidChildrenMap, + Map idPathMap, Map idModuleMap, List data, ApiModuleDTO chooseModule) { + for (ApiDefinitionWithBLOBs datum : data) { + String modulePath = datum.getModulePath(); + ApiModule apiModule = moduleMap.get(modulePath); + if (chooseModule != null) { + dealChooseModuleData(moduleMap, pidChildrenMap, idPathMap, idModuleMap, chooseModule, datum, modulePath); + } else { + dealNoModuleData(moduleMap, pidChildrenMap, idPathMap, idModuleMap, datum, modulePath, apiModule); + } + } + return data; + } + + private void dealNoModuleData(Map moduleMap, Map> pidChildrenMap, Map idPathMap, Map idModuleMap, ApiDefinitionWithBLOBs datum, String modulePath, ApiModule apiModule) { + String[] pathTree; + if (StringUtils.isNotBlank(modulePath)) { + //导入时没选模块但接口有模块的,根据modulePath,和当前协议查询当前项目里是否有同名称模块,如果有,就在该模块下建立接口,否则新建模块 + pathTree = getPathTree(modulePath); + if (apiModule != null) { + datum.setModuleId(apiModule.getId()); + datum.setModulePath(modulePath); + } else { + List moduleList = pidChildrenMap.get("root"); + ApiModule minModule = getMinModule(pathTree, moduleList, null, pidChildrenMap, moduleMap, idPathMap, idModuleMap); + String id = minModule.getId(); + datum.setModuleId(id); + datum.setModulePath(idPathMap.get(id)); + } + } else { + //导入时即没选中模块,接口自身也没模块的,直接返会当前项目,当前协议下的默认模块 + List moduleList = pidChildrenMap.get("root"); + for (ApiModule module : moduleList) { + if (module.getName().equals("未规划接口")) { + datum.setModuleId(module.getId()); + datum.setModulePath("/" + module.getName()); + } + } + } + } + + private void dealChooseModuleData(Map moduleMap, Map> pidChildrenMap, Map idPathMap, Map idModuleMap, ApiModuleDTO chooseModule, ApiDefinitionWithBLOBs datum, String modulePath) { + String[] pathTree; + if (chooseModule.getParentId() == null) { + chooseModule.setParentId("root"); + } + String chooseModuleParentId = chooseModule.getParentId(); + //导入时选了模块,且接口有模块的 + if (StringUtils.isNotBlank(modulePath)) { + List moduleList = pidChildrenMap.get(chooseModuleParentId); + String s; + if (chooseModuleParentId.equals("root")) { + s = "/" + chooseModule.getName(); + } else { + s = idPathMap.get(chooseModuleParentId); + } + pathTree = getPathTree(s + modulePath); + + ApiModule chooseModuleOne = JSON.parseObject(JSON.toJSONString(chooseModule), ApiModule.class); + ApiModule minModule = getMinModule(pathTree, moduleList, chooseModuleOne, pidChildrenMap, moduleMap, idPathMap, idModuleMap); + String id = minModule.getId(); + datum.setModuleId(id); + datum.setModulePath(idPathMap.get(id)); + } else { + //导入时选了模块,且接口没有模块的 + datum.setModuleId(chooseModule.getId()); + datum.setModulePath(idPathMap.get(chooseModule.getId())); + } + } + private String[] getPathTree(String modulePath) { String substring = modulePath.substring(0, 1); if (substring.equals("/")) { @@ -797,7 +917,8 @@ public class ApiModuleService extends NodeTreeService { } } - private ApiModule getMinModule(String[] tagTree, List moduleList, ApiModule parentModule, Map> pidChildrenMap, Map map, Map idPathMap, Map idModuleMap) { + private ApiModule getMinModule(String[] tagTree, List moduleList, ApiModule parentModule, Map> pidChildrenMap, Map moduleMap + , Map idPathMap, Map idModuleMap) { //如果parentModule==null 则证明需要创建根目录同级的模块 ApiModule returnModule = null; for (int i = 0; i < tagTree.length; i++) { @@ -817,7 +938,7 @@ public class ApiModuleService extends NodeTreeService { parentModule = JSON.parseObject(JSON.toJSONString(apiModuleDTO), ApiModule.class); } } - return createModule(tagTree, i, parentModule, map, pidChildrenMap, idPathMap); + return createModule(tagTree, i, parentModule, moduleMap, pidChildrenMap, idPathMap); } else { returnModule = collect.get(0); moduleList = pidChildrenMap.get(collect.get(0).getId()); @@ -826,8 +947,7 @@ public class ApiModuleService extends NodeTreeService { return returnModule; } - - private ApiModule createModule(String[] tagTree, int i, ApiModule parentModule, Map map, Map> pidChildrenMap, Map idPathMap) { + private ApiModule createModule(String[] tagTree, int i, ApiModule parentModule, Map moduleMap, Map> pidChildrenMap, Map idPathMap) { ApiModule returnModule = null; for (int i1 = i; i1 < tagTree.length; i1++) { String pathName = tagTree[i1]; @@ -859,27 +979,30 @@ public class ApiModuleService extends NodeTreeService { path = "/" + pathName; } idPathMap.put(newModule.getId(), path); - map.putIfAbsent(path, newModule); + moduleMap.putIfAbsent(path, newModule); parentModule = newModule; returnModule = newModule; } return returnModule; } - private void buildProcessData(List nodeTreeByProjectId, Map> pidChildrenMap, Map idPathMap) { + private void buildProcessData(List nodeTreeByProjectId, Map> pidChildrenMap, Map idPathMap, Map parentModulePathMap) { + //当前层级的模块的所有子模块的集合 List childrenList = new ArrayList<>(); int i = 0; List moduleList = new ArrayList<>(); for (ApiModuleDTO apiModuleDTO : nodeTreeByProjectId) { - if (apiModuleDTO.getPath() != null) { - apiModuleDTO.setPath(apiModuleDTO.getPath() + "/" + apiModuleDTO.getName()); + if (StringUtils.isBlank(apiModuleDTO.getParentId())) { + apiModuleDTO.setParentId("root"); + } + String parentModulePath = parentModulePathMap.get(apiModuleDTO.getParentId()); + if (parentModulePath != null) { + apiModuleDTO.setPath(parentModulePath + "/" + apiModuleDTO.getName()); } else { apiModuleDTO.setPath("/" + apiModuleDTO.getName()); } idPathMap.put(apiModuleDTO.getId(), apiModuleDTO.getPath()); - if (StringUtils.isBlank(apiModuleDTO.getParentId())) { - apiModuleDTO.setParentId("root"); - } + ApiModule apiModule = buildModule(moduleList, apiModuleDTO); if (pidChildrenMap.get(apiModuleDTO.getParentId()) != null) { pidChildrenMap.get(apiModuleDTO.getParentId()).add(apiModule); @@ -895,9 +1018,10 @@ public class ApiModuleService extends NodeTreeService { pidChildrenMap.put(apiModuleDTO.getId(), new ArrayList<>()); } } + parentModulePathMap.put(apiModuleDTO.getId(), apiModuleDTO.getPath()); } if (i == nodeTreeByProjectId.size() && nodeTreeByProjectId.size() > 0) { - buildProcessData(childrenList, pidChildrenMap, idPathMap); + buildProcessData(childrenList, pidChildrenMap, idPathMap, parentModulePathMap); } } @@ -913,5 +1037,4 @@ public class ApiModuleService extends NodeTreeService { return apiModule; } - } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java b/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java index 1e14fb4bce..2c60850d4f 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java @@ -2,6 +2,7 @@ package io.metersphere.api.service; import com.alibaba.fastjson.JSON; +import io.metersphere.api.dto.ApiTestImportRequest; import io.metersphere.api.dto.automation.*; import io.metersphere.base.domain.*; import io.metersphere.base.mapper.ApiScenarioMapper; @@ -472,111 +473,161 @@ public class ApiScenarioModuleService extends NodeTreeService data, Boolean fullCoverage, Boolean fullCoverageApi) { - Map map = new HashMap<>(); - Map updateMap = new HashMap<>(); + public UpdateScenarioModuleDTO checkScenarioModule(ApiTestImportRequest request, List data, Boolean fullCoverage, Boolean fullCoverageApi) { + //需要新增的模块,key 为模块路径 + Map moduleMap = new HashMap<>(); + List toUpdateList = new ArrayList<>(); + + //上传文件时选的模块ID + String chooseModuleId = request.getModuleId(); + String projectId = request.getProjectId(); + //获取当前项目的当前协议下的所有模块的Tree List scenarioModules = extApiScenarioModuleMapper.getNodeTreeByProjectId(projectId); List nodeTreeByProjectId = this.getNodeTrees(scenarioModules); + + Map idModuleMap = scenarioModules.stream().collect(Collectors.toMap(ApiScenarioModuleDTO::getId, scenarioModuleDTO -> scenarioModuleDTO)); + Map> pidChildrenMap = new HashMap<>(); Map idPathMap = new HashMap<>(); - Map idModuleMap = scenarioModules.stream().collect(Collectors.toMap(ApiScenarioModuleDTO::getId, scenarioModuleDTO -> scenarioModuleDTO)); - buildProcessData(nodeTreeByProjectId, pidChildrenMap, idPathMap); - - Map nameMap = data.stream().collect(Collectors.toMap(ApiScenario::getName, apiScenario -> apiScenario)); - + //构建以上两种数据 + String initParentModulePath = "/root"; + Map initParentModulePathMap = new HashMap<>(); + initParentModulePathMap.put("root", initParentModulePath); + buildProcessData(nodeTreeByProjectId, pidChildrenMap, idPathMap, initParentModulePathMap); ApiScenarioModuleDTO chooseModule = null; - if (moduleId != null) { - chooseModule = idModuleMap.get(moduleId); + if (chooseModuleId != null) { + chooseModule = idModuleMap.get(chooseModuleId); } + + String updateVersionId = getUpdateVersionId(request, fullCoverage); + + List optionData = new ArrayList<>(); + + //覆盖模式留重复的最后一个,不覆盖留第一个 + LinkedHashMap> nameModuleMapList = data.stream().collect(Collectors.groupingBy(t -> t.getName() + (t.getModulePath() == null ? "" : t.getModulePath()), LinkedHashMap::new, Collectors.toList())); + removeRepeat(fullCoverage, optionData, nameModuleMapList); + + //处理模块 + setModule(optionData, moduleMap, pidChildrenMap, idPathMap, idModuleMap, chooseModule); + + //系统内重复的数据 List repeatApiScenarioWithBLOBs; - if (chooseModule != null) { - repeatApiScenarioWithBLOBs = extApiScenarioMapper.selectRepeatByBLOBsSameUrl(data, chooseModule.getId()); + repeatApiScenarioWithBLOBs = extApiScenarioMapper.selectRepeatByBLOBsSameUrl(data, projectId, chooseModule.getId(), updateVersionId); } else { - repeatApiScenarioWithBLOBs = extApiScenarioMapper.selectRepeatByBLOBs(data); + repeatApiScenarioWithBLOBs = extApiScenarioMapper.selectRepeatByBLOBs(data, projectId, updateVersionId); } + Map nameModuleMap = optionData.stream().collect(Collectors.toMap(t -> t.getName() + (t.getModulePath() == null ? "" : t.getModulePath()), scenario -> scenario)); + Map repeatDataMap = null; + if (!repeatApiScenarioWithBLOBs.isEmpty()) { + repeatDataMap = repeatApiScenarioWithBLOBs.stream().collect(Collectors.toMap(t -> t.getName() + t.getModulePath(), scenario -> scenario)); + } + //处理数据 if (fullCoverage) { if (fullCoverageApi) { - coverScenarioModule(updateMap, nameMap, repeatApiScenarioWithBLOBs); + startCoverModule(toUpdateList, nameModuleMap, repeatDataMap); } else { - //只覆盖场景 - justCoverScenario(updateMap, nameMap, repeatApiScenarioWithBLOBs); + //覆盖但不覆盖模块 + if (repeatDataMap != null) { + //导入文件没有新增场景无需创建接口模块 + moduleMap = judgeModuleMap(moduleMap, nameModuleMap, repeatDataMap); + startCover(toUpdateList, nameModuleMap, repeatDataMap); + } } } else { //不覆盖 - if (!repeatApiScenarioWithBLOBs.isEmpty()) { - Map collect = repeatApiScenarioWithBLOBs.stream().collect(Collectors.toMap(ApiScenario::getName, scenario -> scenario)); - collect.forEach((k, v) -> { - if (nameMap.get(k) != null) { - nameMap.remove(k); - } - }); - } - setModule(nameMap, map, pidChildrenMap, idPathMap, idModuleMap, chooseModule); + removeRepeat(optionData, nameModuleMap, repeatDataMap); } UpdateScenarioModuleDTO updateScenarioModuleDTO = new UpdateScenarioModuleDTO(); - updateScenarioModuleDTO.setModuleList((List) map.values()); - updateScenarioModuleDTO.setApiScenarioWithBLOBsList((List) nameMap.values()); - + updateScenarioModuleDTO.setModuleList(new ArrayList<>(moduleMap.values())); + updateScenarioModuleDTO.setNeedUpdateList(toUpdateList); + updateScenarioModuleDTO.setApiScenarioWithBLOBsList(optionData); return updateScenarioModuleDTO; } - private void coverScenarioModule(Map updateMap, Map nameMap, List repeatApiScenarioWithBLOBs) { - if (!repeatApiScenarioWithBLOBs.isEmpty()) { - Map collect = repeatApiScenarioWithBLOBs.stream().collect(Collectors.toMap(ApiScenario::getName, apiScenario -> apiScenario)); - collect.forEach((name, scenario) -> { - ApiScenarioWithBLOBs apiScenarioWithBLOBs = nameMap.get(name); + private void removeRepeat(List optionData, Map nameModuleMap, Map repeatDataMap) { + if (repeatDataMap != null) { + repeatDataMap.forEach((k, v) -> { + ApiScenarioWithBLOBs apiScenarioWithBLOBs = nameModuleMap.get(k); if (apiScenarioWithBLOBs != null) { - //Check whether the content has changed, if not, do not change the creatoCover - Boolean toCover = apiAutomationService.checkIsSynchronize(scenario, apiScenarioWithBLOBs); - //需要更新 - if (toCover) { - if (updateMap.get(name) != null) { - apiScenarioWithBLOBs.setId(scenario.getId()); - updateMap.put(name, apiScenarioWithBLOBs); - } - } else { - nameMap.remove(name); - } + optionData.remove(apiScenarioWithBLOBs); } }); } } - private void justCoverScenario(Map updateMap, Map nameMap, List repeatApiScenarioWithBLOBs) { - if (!repeatApiScenarioWithBLOBs.isEmpty()) { - Map collect = repeatApiScenarioWithBLOBs.stream().collect(Collectors.toMap(ApiScenario::getName, apiScenario -> apiScenario)); - collect.forEach((name, scenario) -> { - ApiScenarioWithBLOBs apiScenarioWithBLOBs = nameMap.get(name); + private void startCover(List toUpdateList, Map nameModuleMap, Map repeatDataMap) { + repeatDataMap.forEach((k, v) -> { + ApiScenarioWithBLOBs apiScenarioWithBLOBs = nameModuleMap.get(k); + if (apiScenarioWithBLOBs != null) { + apiScenarioWithBLOBs.setId(v.getId()); + apiScenarioWithBLOBs.setApiScenarioModuleId(v.getApiScenarioModuleId()); + apiScenarioWithBLOBs.setModulePath(v.getModulePath()); + toUpdateList.add(apiScenarioWithBLOBs); + } + }); + } + + private Map judgeModuleMap(Map moduleMap, Map nameModuleMap, Map repeatDataMap) { + if (repeatDataMap.size() >= nameModuleMap.size()) { + moduleMap = new HashMap<>(); + } + return moduleMap; + } + + private void startCoverModule(List toUpdateList, Map nameModuleMap, Map repeatDataMap) { + if (repeatDataMap != null) { + repeatDataMap.forEach((k, v) -> { + ApiScenarioWithBLOBs apiScenarioWithBLOBs = nameModuleMap.get(k); if (apiScenarioWithBLOBs != null) { - //Check whether the content has changed, if not, do not change the creatoCover - Boolean toCover = apiAutomationService.checkIsSynchronize(scenario, apiScenarioWithBLOBs); - //需要更新 - if (toCover) { - if (updateMap.get(name) != null) { - apiScenarioWithBLOBs.setId(scenario.getId()); - updateMap.put(name, apiScenarioWithBLOBs); - } - } - nameMap.remove(name); + apiScenarioWithBLOBs.setId(v.getId()); + toUpdateList.add(apiScenarioWithBLOBs); } }); } } - private void setModule(Map nameMap, Map map, Map> pidChildrenMap, Map idPathMap, Map idModuleMap, ApiScenarioModuleDTO chooseModule) { - nameMap.forEach((k, datum) -> { + private void removeRepeat(Boolean fullCoverage, List optionData, LinkedHashMap> nameModuleMapList) { + if (fullCoverage) { + nameModuleMapList.forEach((k, v) -> { + optionData.add(v.get(v.size() - 1)); + }); + } else { + nameModuleMapList.forEach((k, v) -> { + optionData.add(v.get(0)); + }); + } + } + + private String getUpdateVersionId(ApiTestImportRequest request, Boolean fullCoverage) { + String updateVersionId; + if (!fullCoverage) { + if (request.getVersionId() == null) { + updateVersionId = request.getDefaultVersion(); + } else { + updateVersionId = request.getVersionId(); + } + } else { + if (request.getUpdateVersionId() == null) { + updateVersionId = request.getDefaultVersion(); + } else { + updateVersionId = request.getUpdateVersionId(); + } + } + return updateVersionId; + } + + private void setModule(List data, Map map, Map> pidChildrenMap, Map idPathMap, Map idModuleMap, ApiScenarioModuleDTO chooseModule) { + for (ApiScenarioWithBLOBs datum : data) { StringBuilder path = new StringBuilder(); path.append("/"); String[] tagTree; @@ -589,17 +640,19 @@ public class ApiScenarioModuleService extends NodeTreeService moduleList = pidChildrenMap.get(chooseModuleParentId); + //选中模块的同级模块集合,用于和场景的全路径做对比 + List parentModuleList = pidChildrenMap.get(chooseModuleParentId); String s; if (chooseModuleParentId.equals("root")) { s = "/" + chooseModule.getName(); } else { s = idPathMap.get(chooseModuleParentId); } + //场景的全部路径的集合 tagTree = getTagTree(s + modulePath); ApiScenarioModule chooseModuleOne = JSON.parseObject(JSON.toJSONString(chooseModule), ApiScenarioModule.class); - ApiScenarioModule minModule = getMinModule(tagTree, moduleList, chooseModuleOne, pidChildrenMap, map, idPathMap, idModuleMap); + ApiScenarioModule minModule = getMinModule(tagTree, parentModuleList, chooseModuleOne, pidChildrenMap, map, idPathMap, idModuleMap); String id = minModule.getId(); datum.setApiScenarioModuleId(id); datum.setModulePath(idPathMap.get(id)); @@ -616,8 +669,9 @@ public class ApiScenarioModuleService extends NodeTreeService moduleList = pidChildrenMap.get("root"); - ApiScenarioModule minModule = getMinModule(tagTree, moduleList, null, pidChildrenMap, map, idPathMap, idModuleMap); + //父级同级的模块list + List parentModuleList = pidChildrenMap.get("root"); + ApiScenarioModule minModule = getMinModule(tagTree, parentModuleList, null, pidChildrenMap, map, idPathMap, idModuleMap); String id = minModule.getId(); datum.setApiScenarioModuleId(id); datum.setModulePath(idPathMap.get(id)); @@ -633,7 +687,7 @@ public class ApiScenarioModuleService extends NodeTreeService moduleList, ApiScenarioModule parentModule, Map> pidChildrenMap, Map map, Map idPathMap, Map idModuleMap) { + private ApiScenarioModule getMinModule(String[] tagTree, List parentModuleList, ApiScenarioModule parentModule, Map> pidChildrenMap, Map map, Map idPathMap, Map idModuleMap) { //如果parentModule==null 则证明需要创建根目录同级的模块 ApiScenarioModule returnModule = null; for (int i = 0; i < tagTree.length; i++) { int finalI = i; - List collect = moduleList.stream().filter(t -> t.getName().equals(tagTree[finalI])).collect(Collectors.toList()); + //查找上一级里面是否有当前全路径的第一级,没有则需要创建 + List collect = parentModuleList.stream().filter(t -> t.getName().equals(tagTree[finalI])).collect(Collectors.toList()); if (collect.isEmpty()) { + //如果找不到,而且父级模块也为空,证明当前的父级模块应为root if (parentModule == null) { List moduleList1 = pidChildrenMap.get("root"); ApiScenarioModule apiModule = moduleList1.get(0); @@ -663,16 +719,18 @@ public class ApiScenarioModuleService extends NodeTreeService 0) { - if (!moduleList.isEmpty()) { - String parentId = moduleList.get(0).getParentId(); + //如果已经循环第二次级以上,如果父模块不为空, parentModuleList不为空,tagTree[finalI] 找不到,那就从上一级开始创建 + if (!parentModuleList.isEmpty()) { + String parentId = parentModuleList.get(0).getParentId(); ApiScenarioModuleDTO apiScenarioModuleDTO = idModuleMap.get(parentId); parentModule = JSON.parseObject(JSON.toJSONString(apiScenarioModuleDTO), ApiScenarioModule.class); } } + //开始创建tagTree[finalI]这个模块 return createModule(tagTree, i, parentModule, map, pidChildrenMap, idPathMap); } else { returnModule = collect.get(0); - moduleList = pidChildrenMap.get(collect.get(0).getId()); + parentModuleList = pidChildrenMap.get(collect.get(0).getId()); } } return returnModule; @@ -684,6 +742,8 @@ public class ApiScenarioModuleService extends NodeTreeService nodeTreeByProjectId, Map> pidChildrenMap, Map idPathMap) { + private void buildProcessData(List nodeTreeByProjectId, Map> pidChildrenMap, Map idPathMap, Map parentModulePathMap) { List childrenList = new ArrayList<>(); int i = 0; List moduleList = new ArrayList<>(); for (ApiScenarioModuleDTO scenarioModuleDTO : nodeTreeByProjectId) { - if (scenarioModuleDTO.getPath() != null) { - scenarioModuleDTO.setPath(scenarioModuleDTO.getPath() + "/" + scenarioModuleDTO.getName()); + if (StringUtils.isBlank(scenarioModuleDTO.getParentId())) { + scenarioModuleDTO.setParentId("root"); + } + String parentModulePath = parentModulePathMap.get(scenarioModuleDTO.getParentId()); + if (parentModulePath != null) { + scenarioModuleDTO.setPath(parentModulePath + "/" + scenarioModuleDTO.getName()); } else { scenarioModuleDTO.setPath("/" + scenarioModuleDTO.getName()); } idPathMap.put(scenarioModuleDTO.getId(), scenarioModuleDTO.getPath()); - if (StringUtils.isBlank(scenarioModuleDTO.getParentId())) { - scenarioModuleDTO.setParentId("root"); - } + ApiScenarioModule scenarioModule = buildModule(moduleList, scenarioModuleDTO); if (pidChildrenMap.get(scenarioModuleDTO.getParentId()) != null) { pidChildrenMap.get(scenarioModuleDTO.getParentId()).add(scenarioModule); @@ -747,9 +809,10 @@ public class ApiScenarioModuleService extends NodeTreeService()); } } + parentModulePathMap.put(scenarioModuleDTO.getId(), scenarioModuleDTO.getPath()); } if (i == nodeTreeByProjectId.size() && nodeTreeByProjectId.size() > 0) { - buildProcessData(childrenList, pidChildrenMap, idPathMap); + buildProcessData(childrenList, pidChildrenMap, idPathMap, parentModulePathMap); } } diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.java index 1344d42329..b9b31ea3f4 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.java @@ -93,9 +93,9 @@ public interface ExtApiDefinitionMapper { int toBeUpdateApi(@Param("ids") List ids, @Param("toBeUpdate") Boolean toBeUpdate); - List selectRepeatByBLOBs(@Param("blobs") List blobs); + List selectRepeatByBLOBs(@Param("blobs") List blobs, @Param("projectId") String projectId, @Param("versionId") String versionId); - List selectRepeatByBLOBsSameUrl(@Param("blobs") List blobs, @Param("moduleId") String moduleId); + List selectRepeatByBLOBsSameUrl(@Param("blobs") List blobs, @Param("projectId") String projectId, @Param("moduleId") String moduleId, @Param("versionId") String versionId); } diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml index c7f13912e5..a99eecf7d9 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml @@ -1010,13 +1010,17 @@ @@ -1030,11 +1034,7 @@ and api_definition.path = #{blob.path} - - and api_definition.project_id = #{blob.projectId} - - diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.java index e821fb67da..b81e3a1f37 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.java @@ -91,9 +91,9 @@ public interface ExtApiScenarioMapper { List selectByStatusIsNotTrash(); - List selectRepeatByBLOBs(@Param("blobs") List blobs); + List selectRepeatByBLOBs(@Param("blobs") List blobs, @Param("projectId") String projectId, @Param("versionId") String versionId); - List selectRepeatByBLOBsSameUrl(@Param("blobs") List blobs, @Param("moduleId") String moduleId); + List selectRepeatByBLOBsSameUrl(@Param("blobs") List blobs, @Param("projectId") String projectId, @Param("moduleId") String moduleId, @Param("versionId") String versionId); } diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml index 5591e846e0..a790e4e46e 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml @@ -774,7 +774,9 @@ @@ -793,9 +797,6 @@ and api_scenario.name = #{blob.name} - - and api_scenario.project_id = #{blob.projectId} -