From 1cc2326c6fdd1bbf9c36b7a6d21c29778b499ce6 Mon Sep 17 00:00:00 2001 From: song-cc-rock Date: Tue, 25 Apr 2023 12:00:13 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E6=B5=8B=E8=AF=95=E8=B7=9F=E8=B8=AA):=20?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E7=BC=BA=E9=99=B7=E5=BC=82=E6=AD=A5=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E6=97=A0=E6=B3=95=E8=8E=B7=E5=8F=96=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E5=A4=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/IssuesController.java | 7 +- .../io/metersphere/service/IssuesService.java | 107 ++++++------------ .../service/IssuesSyncService.java | 85 ++++++++++++++ .../frontend/src/business/issue/IssueList.vue | 55 ++++----- 4 files changed, 152 insertions(+), 102 deletions(-) create mode 100644 test-track/backend/src/main/java/io/metersphere/service/IssuesSyncService.java diff --git a/test-track/backend/src/main/java/io/metersphere/controller/IssuesController.java b/test-track/backend/src/main/java/io/metersphere/controller/IssuesController.java index 5af2b9a1cc..b5bb8f803e 100644 --- a/test-track/backend/src/main/java/io/metersphere/controller/IssuesController.java +++ b/test-track/backend/src/main/java/io/metersphere/controller/IssuesController.java @@ -26,6 +26,7 @@ import io.metersphere.request.testcase.AuthUserIssueRequest; import io.metersphere.request.testcase.IssuesCountRequest; import io.metersphere.service.BaseCheckPermissionService; import io.metersphere.service.IssuesService; +import io.metersphere.service.IssuesSyncService; import io.metersphere.service.PlatformPluginService; import io.metersphere.xpack.track.dto.*; import io.metersphere.xpack.track.dto.request.IssuesRequest; @@ -47,6 +48,8 @@ public class IssuesController { @Resource private IssuesService issuesService; @Resource + private IssuesSyncService issuesSyncService; + @Resource private BaseCheckPermissionService baseCheckPermissionService; @Resource private PlatformPluginService platformPluginService; @@ -159,12 +162,12 @@ public class IssuesController { @GetMapping("/sync/{projectId}") public void syncThirdPartyIssues(@PathVariable String projectId) { - issuesService.syncThirdPartyIssues(projectId); + issuesSyncService.syncIssues(projectId); } @PostMapping("/sync/all") public void syncThirdPartyAllIssues(@RequestBody IssueSyncRequest request) { - issuesService.syncThirdPartyAllIssues(request); + issuesSyncService.syncAllIssues(request); } @GetMapping("/sync/check/{projectId}") diff --git a/test-track/backend/src/main/java/io/metersphere/service/IssuesService.java b/test-track/backend/src/main/java/io/metersphere/service/IssuesService.java index 31c418b4f4..43353363ca 100644 --- a/test-track/backend/src/main/java/io/metersphere/service/IssuesService.java +++ b/test-track/backend/src/main/java/io/metersphere/service/IssuesService.java @@ -72,6 +72,7 @@ import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionUtils; import org.springframework.context.annotation.Lazy; import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @@ -95,6 +96,9 @@ public class IssuesService { @Resource private TrackProjectService trackProjectService; @Resource + @Lazy + private IssuesSyncService issuesSyncService; + @Resource private BaseUserService baseUserService; @Resource private BaseProjectService baseProjectService; @@ -146,9 +150,6 @@ public class IssuesService { private UserService userService; @Resource private BasePluginService basePluginService; - @Resource - @Lazy - private IssuesService issuesService; private static final String SYNC_THIRD_PARTY_ISSUES_KEY = "ISSUE:SYNC"; private static final String SYNC_THIRD_PARTY_ISSUES_ERROR_KEY = "ISSUE:SYNC:ERROR"; @@ -877,8 +878,7 @@ public class IssuesService { List projectIds = trackProjectService.getThirdPartProjectIds(); projectIds.forEach(id -> { try { - // 使用代理对象调用,防止事务注解失效 - issuesService.syncThirdPartyIssues(id); + issuesSyncService.syncIssues(id); } catch (Exception e) { LogUtil.error(e.getMessage(), e); } @@ -941,47 +941,29 @@ public class IssuesService { stringRedisTemplate.delete(SYNC_THIRD_PARTY_ISSUES_ERROR_KEY + ":" + projectId); } + @Async @Transactional(propagation = Propagation.REQUIRES_NEW) - public void syncThirdPartyIssues(String projectId) { - if (StringUtils.isNotBlank(projectId)) { - String syncValue = getSyncKey(projectId); - if (StringUtils.isEmpty(syncValue)) { - setSyncKey(projectId); - Project project = baseProjectService.getProjectById(projectId); - List issues = extIssuesMapper.getIssueForSync(projectId, project.getPlatform()); - - if (CollectionUtils.isEmpty(issues)) { - deleteSyncKey(projectId); - } else { - new Thread(() -> { - IssuesRequest issuesRequest = new IssuesRequest(); - issuesRequest.setProjectId(projectId); - issuesRequest.setWorkspaceId(project.getWorkspaceId()); - try { - issuesRequest.setDefaultCustomFields(getDefaultCustomField(project)); - if (PlatformPluginService.isPluginPlatform(project.getPlatform())) { - // 分批处理 - SubListUtil.dealForSubList(issues, 500, (subIssue) -> - syncPluginThirdPartyIssues(subIssue, project, issuesRequest.getDefaultCustomFields())); - } else { - IssuesPlatform platform = IssueFactory.createPlatform(project.getPlatform(), issuesRequest); - syncThirdPartyIssues(platform::syncIssues, project, issues); - } - } catch (Exception e) { - LogUtil.error(e); - // 同步缺陷异常, 当前同步错误信息 -> Redis(check接口获取) - setSyncErrorMsg(projectId, e.getMessage()); - } finally { - // 异常或正常结束都得删除当前项目执行同步的Key - deleteSyncKey(projectId); - } - }).start(); - } + public void syncThirdPartyIssues(List issues, IssuesRequest issuesRequest, Project project) { + try { + if (PlatformPluginService.isPluginPlatform(project.getPlatform())) { + // 分批处理 + SubListUtil.dealForSubList(issues, 500, (subIssue) -> + syncPluginThirdPartyIssues(subIssue, project, issuesRequest.getDefaultCustomFields())); + } else { + IssuesPlatform platform = IssueFactory.createPlatform(project.getPlatform(), issuesRequest); + syncThirdPartyIssues(platform::syncIssues, project, issues); } + } catch (Exception e) { + LogUtil.error(e); + // 同步缺陷异常, 当前同步错误信息 -> Redis(check接口获取) + setSyncErrorMsg(project.getId(), e.getMessage()); + } finally { + // 异常或正常结束都得删除当前项目执行同步的Key + deleteSyncKey(project.getId()); } } - private String getDefaultCustomField(Project project) { + public String getDefaultCustomField(Project project) { if (isThirdPartTemplate(project)) { return null; } @@ -1938,35 +1920,21 @@ public class IssuesService { && platformPluginService.isThirdPartTemplateSupport(project.getPlatform()); } - public void syncThirdPartyAllIssues(IssueSyncRequest syncRequest) { - syncRequest.setProjectId(syncRequest.getProjectId()); - XpackIssueService xpackIssueService = CommonBeanFactory.getBean(XpackIssueService.class); - if (StringUtils.isNotBlank(syncRequest.getProjectId())) { - // 获取当前项目执行同步缺陷Key - String syncValue = getSyncKey(syncRequest.getProjectId()); - if (StringUtils.isEmpty(syncValue)) { - // 同步Key不存在, 设置保证唯一性, 并开始同步 - setSyncKey(syncRequest.getProjectId()); - new Thread(() -> { - try { - Project project = baseProjectService.getProjectById(syncRequest.getProjectId()); - if (!isThirdPartTemplate(project)) { - syncRequest.setDefaultCustomFields(getDefaultCustomFields(syncRequest.getProjectId())); - } - xpackIssueService.syncThirdPartyIssues(project, syncRequest); - if (platformPluginService.isPluginPlatform(project.getPlatform())) { - syncAllPluginIssueAttachment(project, syncRequest); - } - } catch (Exception e) { - LogUtil.error(e); - // 同步缺陷异常, 当前同步错误信息 -> Redis(check接口获取) - setSyncErrorMsg(syncRequest.getProjectId(), e.getMessage()); - } finally { - // 异常或正常结束都得删除当前项目执行同步的Key - deleteSyncKey(syncRequest.getProjectId()); - } - }).start(); + @Async + public void syncThirdPartyAllIssues(IssueSyncRequest syncRequest, Project project) { + try { + XpackIssueService xpackIssueService = CommonBeanFactory.getBean(XpackIssueService.class); + xpackIssueService.syncThirdPartyIssues(project, syncRequest); + if (platformPluginService.isPluginPlatform(project.getPlatform())) { + syncAllPluginIssueAttachment(project, syncRequest); } + } catch (Exception e) { + LogUtil.error(e); + // 同步缺陷异常, 当前同步错误信息 -> Redis(check接口获取) + setSyncErrorMsg(syncRequest.getProjectId(), e.getMessage()); + } finally { + // 异常或正常结束都得删除当前项目执行同步的Key + deleteSyncKey(syncRequest.getProjectId()); } } @@ -1977,7 +1945,6 @@ public class IssuesService { Platform platform = platformPluginService.getPlatform(project.getPlatform(), project.getWorkspaceId()); SyncAllIssuesRequest syncAllIssuesRequest = new SyncAllIssuesRequest(); BeanUtils.copyBean(syncAllIssuesRequest, issueSyncRequest); - syncAllIssuesRequest.setDefaultCustomFields(getDefaultCustomField(project)); syncAllIssuesRequest.setProjectConfig(PlatformPluginService.getCompatibleProjectConfig(project)); syncAllIssuesRequest.setHandleSyncFunc(issueSyncRequest.getHandleSyncFunc()); platform.syncAllIssues(syncAllIssuesRequest); diff --git a/test-track/backend/src/main/java/io/metersphere/service/IssuesSyncService.java b/test-track/backend/src/main/java/io/metersphere/service/IssuesSyncService.java new file mode 100644 index 0000000000..52f883a58d --- /dev/null +++ b/test-track/backend/src/main/java/io/metersphere/service/IssuesSyncService.java @@ -0,0 +1,85 @@ +package io.metersphere.service; + +import io.metersphere.base.domain.Project; +import io.metersphere.base.mapper.ext.ExtIssuesMapper; +import io.metersphere.commons.exception.MSException; +import io.metersphere.xpack.track.dto.IssueSyncRequest; +import io.metersphere.xpack.track.dto.IssuesDao; +import io.metersphere.xpack.track.dto.request.IssuesRequest; +import jakarta.annotation.Resource; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * @author song-cc-rock + */ +@Service +@Transactional(rollbackFor = Exception.class) +public class IssuesSyncService { + + @Resource + private IssuesService issuesService; + @Resource + private BaseProjectService baseProjectService; + @Resource + private ExtIssuesMapper extIssuesMapper; + + /** + * xpack用户 + * @param syncRequest 同步参数 + */ + public void syncAllIssues(IssueSyncRequest syncRequest) { + try { + if (StringUtils.isNotBlank(syncRequest.getProjectId())) { + // 获取当前项目执行同步缺陷Key + String syncValue = issuesService.getSyncKey(syncRequest.getProjectId()); + if (StringUtils.isEmpty(syncValue)) { + // 同步Key不存在, 设置保证唯一性, 并开始同步 + issuesService.setSyncKey(syncRequest.getProjectId()); + Project project = baseProjectService.getProjectById(syncRequest.getProjectId()); + if (!issuesService.isThirdPartTemplate(project)) { + syncRequest.setDefaultCustomFields(issuesService.getDefaultCustomFields(syncRequest.getProjectId())); + } + issuesService.syncThirdPartyAllIssues(syncRequest, project); + } + } + } catch (Exception e) { + issuesService.deleteSyncKey(syncRequest.getProjectId()); + MSException.throwException(e); + } + } + + /** + * 非xpack用户 + * @param projectId 项目ID + */ + public void syncIssues(String projectId) { + try { + if (StringUtils.isNotBlank(projectId)) { + String syncValue = issuesService.getSyncKey(projectId); + if (StringUtils.isEmpty(syncValue)) { + issuesService.setSyncKey(projectId); + Project project = baseProjectService.getProjectById(projectId); + List issues = extIssuesMapper.getIssueForSync(projectId, project.getPlatform()); + + if (CollectionUtils.isEmpty(issues)) { + issuesService.deleteSyncKey(projectId); + } else { + IssuesRequest issuesRequest = new IssuesRequest(); + issuesRequest.setProjectId(projectId); + issuesRequest.setWorkspaceId(project.getWorkspaceId()); + issuesRequest.setDefaultCustomFields(issuesService.getDefaultCustomField(project)); + issuesService.syncThirdPartyIssues(issues, issuesRequest, project); + } + } + } + } catch (Exception e) { + issuesService.deleteSyncKey(projectId); + MSException.throwException(e); + } + } +} diff --git a/test-track/frontend/src/business/issue/IssueList.vue b/test-track/frontend/src/business/issue/IssueList.vue index bf4ce439aa..d47fbf961b 100644 --- a/test-track/frontend/src/business/issue/IssueList.vue +++ b/test-track/frontend/src/business/issue/IssueList.vue @@ -598,43 +598,38 @@ export default { "createTime": data.createTime.getTime(), "pre": data.preValue } - syncAllIssues(param) + syncIssues() .then(() => { - checkSyncIssues(this.loading, false, (errorData) => { - this.loading = false; - this.syncDisable = false; - if (errorData.syncResult && errorData.syncResult !== '') { - this.$error(errorData.syncResult, false); - } else { - this.$success(this.$t('test_track.issue.sync_complete'), false); - this.getIssues(); - } - }); - }) - .catch(() => { - this.loading = false; - this.syncDisable = false; - }); + this.repeatCheckSyncRes(); + }).catch(() => { + this.resetSyncParam(); + }); }, syncIssues() { this.loading = true; - this.syncDisable = false; + this.syncDisable = true; syncIssues() .then(() => { - checkSyncIssues(this.loading, false, (errorData) => { - this.loading = false; - this.syncDisable = false; - if (errorData.syncResult && errorData.syncResult !== '') { - this.$error(errorData.syncResult, false); - } else { - this.$success(this.$t('test_track.issue.sync_complete'), false); - this.getIssues(); - } - }); + this.repeatCheckSyncRes(); }).catch(() => { - this.loading = false; - this.syncDisable = false; - }); + this.resetSyncParam(); + }); + }, + repeatCheckSyncRes() { + checkSyncIssues(this.loading, false, (errorData) => { + this.loading = false; + this.syncDisable = false; + if (errorData.syncResult && errorData.syncResult !== '') { + this.$error(errorData.syncResult, false); + } else { + this.$success(this.$t('test_track.issue.sync_complete'), false); + this.getIssues(); + } + }); + }, + resetSyncParam() { + this.loading = false; + this.syncDisable = false; }, editParam() { let id = this.$route.query.id;