实现历史项目导入任务提交流程

This commit is contained in:
wkc
2026-03-29 09:49:44 +08:00
parent eb0d896114
commit b098d4eed1
7 changed files with 180 additions and 3 deletions

View File

@@ -4,10 +4,13 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.ccdi.project.domain.CcdiProject;
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectQueryDTO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectHistoryListItemVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 项目Mapper接口
*
@@ -24,6 +27,14 @@ public interface CcdiProjectMapper extends BaseMapper<CcdiProject> {
*/
Page<CcdiProjectVO> selectProjectPage(Page<CcdiProjectVO> page, @Param("queryDTO") CcdiProjectQueryDTO queryDTO);
/**
* 查询历史项目列表
*
* @param queryDTO 查询条件
* @return 历史项目列表
*/
List<CcdiProjectHistoryListItemVO> selectHistoryProjects(@Param("queryDTO") CcdiProjectQueryDTO queryDTO);
/**
* 更新项目风险人数
*

View File

@@ -0,0 +1,22 @@
package com.ruoyi.ccdi.project.service;
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectImportHistoryDTO;
/**
* 历史项目导入服务
*
* @author ruoyi
*/
public interface ICcdiProjectHistoryImportService {
/**
* 提交历史项目导入任务
*
* @param targetProjectId 目标项目ID
* @param targetLsfxProjectId 目标流水分析项目ID
* @param dto 导入参数
* @param operator 操作人
*/
void submitImport(Long targetProjectId, Integer targetLsfxProjectId,
CcdiProjectImportHistoryDTO dto, String operator);
}

View File

@@ -0,0 +1,27 @@
package com.ruoyi.ccdi.project.service.impl;
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectImportHistoryDTO;
import com.ruoyi.ccdi.project.service.ICcdiProjectHistoryImportService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
/**
* 历史项目导入服务实现
*
* @author ruoyi
*/
@Slf4j
@Service
public class CcdiProjectHistoryImportServiceImpl implements ICcdiProjectHistoryImportService {
@Override
public void submitImport(Long targetProjectId, Integer targetLsfxProjectId,
CcdiProjectImportHistoryDTO dto, String operator) {
CompletableFuture.runAsync(() -> log.info(
"【项目历史导入】任务已提交: projectId={}, lsfxProjectId={}, sourceProjectIds={}, operator={}",
targetProjectId, targetLsfxProjectId, dto.getSourceProjectIds(), operator
));
}
}

View File

@@ -11,6 +11,7 @@ import com.ruoyi.ccdi.project.domain.vo.CcdiProjectHistoryListItemVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectStatusCountsVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectVO;
import com.ruoyi.ccdi.project.mapper.CcdiProjectMapper;
import com.ruoyi.ccdi.project.service.ICcdiProjectHistoryImportService;
import com.ruoyi.ccdi.project.service.ICcdiProjectService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.lsfx.client.LsfxAnalysisClient;
@@ -21,9 +22,10 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.StringUtils;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;
@@ -43,6 +45,9 @@ public class CcdiProjectServiceImpl implements ICcdiProjectService {
@Resource
private LsfxAnalysisClient lsfxAnalysisClient;
@Resource
private ICcdiProjectHistoryImportService historyImportService;
@Override
@Transactional(rollbackFor = Exception.class)
public CcdiProjectVO createProject(CcdiProjectSaveDTO dto) {
@@ -120,16 +125,24 @@ public class CcdiProjectServiceImpl implements ICcdiProjectService {
@Override
public List<CcdiProjectHistoryListItemVO> listHistoryProjects(CcdiProjectQueryDTO queryDTO) {
return Collections.emptyList();
return projectMapper.selectHistoryProjects(queryDTO);
}
@Override
@Transactional(rollbackFor = Exception.class)
public CcdiProjectVO importFromHistory(CcdiProjectImportHistoryDTO dto, String operator) {
CcdiProjectSaveDTO saveDTO = new CcdiProjectSaveDTO();
saveDTO.setProjectName(dto.getProjectName());
saveDTO.setDescription(dto.getDescription());
saveDTO.setConfigType("default");
return createProject(saveDTO);
CcdiProjectVO project = createProject(saveDTO);
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCommit() {
historyImportService.submitImport(project.getProjectId(), project.getLsfxProjectId(), dto, operator);
}
});
return project;
}
@Override

View File

@@ -19,6 +19,15 @@
<result property="createByName" column="create_by_name"/>
</resultMap>
<resultMap id="ProjectHistoryListItemResultMap" type="com.ruoyi.ccdi.project.domain.vo.CcdiProjectHistoryListItemVO">
<id property="projectId" column="project_id"/>
<result property="projectName" column="project_name"/>
<result property="description" column="description"/>
<result property="status" column="status"/>
<result property="isArchived" column="is_archived"/>
<result property="createTime" column="create_time"/>
</resultMap>
<!-- 分页查询项目列表 -->
<select id="selectProjectPage" resultMap="ProjectVOResultMap">
SELECT
@@ -41,6 +50,24 @@
ORDER BY p.update_time DESC
</select>
<select id="selectHistoryProjects" resultMap="ProjectHistoryListItemResultMap">
SELECT
p.project_id,
p.project_name,
p.description,
p.status,
p.is_archived,
p.create_time
FROM ccdi_project p
<where>
p.status in ('1', '2')
<if test="queryDTO.projectName != null and queryDTO.projectName != ''">
AND p.project_name LIKE CONCAT('%', #{queryDTO.projectName}, '%')
</if>
</where>
ORDER BY p.update_time DESC
</select>
<update id="updateRiskCountsByProjectId">
update ccdi_project
set high_risk_count = #{highRiskCount},

View File

@@ -4,9 +4,14 @@ import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.read.ListAppender;
import com.ruoyi.ccdi.project.domain.CcdiProject;
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectImportHistoryDTO;
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectQueryDTO;
import com.ruoyi.ccdi.project.domain.dto.CcdiProjectSaveDTO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectHistoryListItemVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectStatusCountsVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectVO;
import com.ruoyi.ccdi.project.mapper.CcdiProjectMapper;
import com.ruoyi.ccdi.project.service.ICcdiProjectHistoryImportService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.lsfx.client.LsfxAnalysisClient;
import com.ruoyi.lsfx.domain.response.GetTokenResponse;
@@ -16,13 +21,19 @@ import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -38,6 +49,9 @@ class CcdiProjectServiceImplTest {
@Mock
private LsfxAnalysisClient lsfxAnalysisClient;
@Mock
private ICcdiProjectHistoryImportService historyImportService;
@Test
void shouldCountTaggingProjectsSeparately() {
when(projectMapper.selectCount(any())).thenReturn(10L, 3L, 4L, 2L, 1L);
@@ -106,6 +120,61 @@ class CcdiProjectServiceImplTest {
() -> service.ensureProjectNotArchived(42L, "已归档项目暂不允许修改参数"));
}
@Test
void shouldOnlyReturnCompletedAndArchivedHistoryProjects() {
CcdiProjectQueryDTO queryDTO = new CcdiProjectQueryDTO();
queryDTO.setProjectName("历史");
CcdiProjectHistoryListItemVO completed = new CcdiProjectHistoryListItemVO();
completed.setProjectId(1L);
completed.setStatus("1");
CcdiProjectHistoryListItemVO archived = new CcdiProjectHistoryListItemVO();
archived.setProjectId(2L);
archived.setStatus("2");
when(projectMapper.selectHistoryProjects(queryDTO)).thenReturn(List.of(completed, archived));
List<CcdiProjectHistoryListItemVO> result = service.listHistoryProjects(queryDTO);
assertEquals(2, result.size());
assertEquals(List.of(completed, archived), result);
verify(projectMapper).selectHistoryProjects(queryDTO);
}
@Test
void shouldCreateProjectThenSubmitHistoryImportAfterCommit() {
CcdiProjectImportHistoryDTO dto = new CcdiProjectImportHistoryDTO();
dto.setProjectName("新项目");
dto.setDescription("从历史导入");
dto.setSourceProjectIds(List.of(11L, 12L));
dto.setStartDate("2026-01-01");
dto.setEndDate("2026-01-31");
when(lsfxAnalysisClient.getToken(any())).thenReturn(buildTokenResponse(3001));
doAnswer(invocation -> {
CcdiProject project = invocation.getArgument(0);
project.setProjectId(90L);
return 1;
}).when(projectMapper).insert(any(CcdiProject.class));
TransactionSynchronizationManager.initSynchronization();
try {
CcdiProjectVO project = service.importFromHistory(dto, "tester");
assertNotNull(project);
assertEquals(90L, project.getProjectId());
assertEquals(1, TransactionSynchronizationManager.getSynchronizations().size());
verify(historyImportService, never()).submitImport(any(), any(), any(), anyString());
TransactionSynchronizationManager.getSynchronizations().forEach(sync -> sync.afterCommit());
verify(historyImportService).submitImport(90L, 3001, dto, "tester");
} finally {
TransactionSynchronizationManager.clearSynchronization();
}
}
@Test
void shouldLogProjectInitialStatusWhenProjectIsCreated() {
CcdiProjectSaveDTO dto = new CcdiProjectSaveDTO();