fix: 修复异步导入方法的阻塞调用问题
## 问题描述
Controller层使用了future.get()阻塞调用,导致异步导入失去意义
## 修复内容
1. 修改ICcdiEmployeeService接口:将返回类型从CompletableFuture<ImportResultVO>改为String
2. 修改CcdiEmployeeServiceImpl:importEmployeeAsync方法立即返回taskId
3. 修改CcdiEmployeeController:移除future.get()调用,直接使用返回的taskId
4. 移除不需要的CompletableFuture导入
## 技术细节
- Service方法保持@Async注解,在独立线程池中执行
- Controller立即返回taskId给前端,不等待导入完成
- 前端可通过/importStatus/{taskId}接口查询导入进度
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,7 +28,6 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 员工信息Controller
|
* 员工信息Controller
|
||||||
@@ -137,11 +136,14 @@ public class CcdiEmployeeController extends BaseController {
|
|||||||
return error("至少需要一条数据");
|
return error("至少需要一条数据");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 异步导入
|
// 异步导入,立即返回taskId
|
||||||
CompletableFuture<ImportResultVO> future = employeeService.importEmployeeAsync(list, updateSupport);
|
String taskId = employeeService.importEmployeeAsync(list, updateSupport);
|
||||||
|
|
||||||
// 立即返回taskId
|
// 构建返回结果
|
||||||
ImportResultVO result = future.get();
|
ImportResultVO result = new ImportResultVO();
|
||||||
|
result.setTaskId(taskId);
|
||||||
|
result.setStatus("PROCESSING");
|
||||||
|
result.setMessage("导入任务已提交,正在后台处理");
|
||||||
|
|
||||||
return success("导入任务已提交,正在后台处理", result);
|
return success("导入任务已提交,正在后台处理", result);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import com.ruoyi.ccdi.domain.vo.ImportResultVO;
|
|||||||
import com.ruoyi.ccdi.domain.vo.ImportStatusVO;
|
import com.ruoyi.ccdi.domain.vo.ImportStatusVO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 员工信息 服务层
|
* 员工信息 服务层
|
||||||
@@ -92,9 +91,9 @@ public interface ICcdiEmployeeService {
|
|||||||
*
|
*
|
||||||
* @param excelList Excel数据列表
|
* @param excelList Excel数据列表
|
||||||
* @param isUpdateSupport 是否更新已存在的数据
|
* @param isUpdateSupport 是否更新已存在的数据
|
||||||
* @return CompletableFuture包含导入结果
|
* @return 任务ID
|
||||||
*/
|
*/
|
||||||
CompletableFuture<ImportResultVO> importEmployeeAsync(List<CcdiEmployeeExcel> excelList, Boolean isUpdateSupport);
|
String importEmployeeAsync(List<CcdiEmployeeExcel> excelList, Boolean isUpdateSupport);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询导入状态
|
* 查询导入状态
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -232,12 +231,12 @@ public class CcdiEmployeeServiceImpl implements ICcdiEmployeeService {
|
|||||||
*
|
*
|
||||||
* @param excelList Excel数据列表
|
* @param excelList Excel数据列表
|
||||||
* @param isUpdateSupport 是否更新已存在的数据
|
* @param isUpdateSupport 是否更新已存在的数据
|
||||||
* @return CompletableFuture包含导入结果
|
* @return 任务ID
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Async("importExecutor")
|
@Async("importExecutor")
|
||||||
@Transactional
|
@Transactional
|
||||||
public CompletableFuture<ImportResultVO> importEmployeeAsync(List<CcdiEmployeeExcel> excelList, Boolean isUpdateSupport) {
|
public String importEmployeeAsync(List<CcdiEmployeeExcel> excelList, Boolean isUpdateSupport) {
|
||||||
String taskId = UUID.randomUUID().toString();
|
String taskId = UUID.randomUUID().toString();
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
@@ -264,12 +263,6 @@ public class CcdiEmployeeServiceImpl implements ICcdiEmployeeService {
|
|||||||
String finalStatus = result.getFailureCount() == 0 ? "SUCCESS" : "PARTIAL_SUCCESS";
|
String finalStatus = result.getFailureCount() == 0 ? "SUCCESS" : "PARTIAL_SUCCESS";
|
||||||
updateImportStatus(taskId, finalStatus, result, startTime);
|
updateImportStatus(taskId, finalStatus, result, startTime);
|
||||||
|
|
||||||
ImportResultVO resultVO = new ImportResultVO();
|
|
||||||
resultVO.setTaskId(taskId);
|
|
||||||
resultVO.setStatus(finalStatus);
|
|
||||||
resultVO.setMessage("导入任务已提交");
|
|
||||||
|
|
||||||
return CompletableFuture.completedFuture(resultVO);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// 处理异常
|
// 处理异常
|
||||||
Map<String, Object> errorData = new HashMap<>();
|
Map<String, Object> errorData = new HashMap<>();
|
||||||
@@ -277,14 +270,10 @@ public class CcdiEmployeeServiceImpl implements ICcdiEmployeeService {
|
|||||||
errorData.put("message", "导入失败: " + e.getMessage());
|
errorData.put("message", "导入失败: " + e.getMessage());
|
||||||
errorData.put("endTime", System.currentTimeMillis());
|
errorData.put("endTime", System.currentTimeMillis());
|
||||||
redisTemplate.opsForHash().putAll(statusKey, errorData);
|
redisTemplate.opsForHash().putAll(statusKey, errorData);
|
||||||
|
|
||||||
ImportResultVO resultVO = new ImportResultVO();
|
|
||||||
resultVO.setTaskId(taskId);
|
|
||||||
resultVO.setStatus("FAILED");
|
|
||||||
resultVO.setMessage("导入失败: " + e.getMessage());
|
|
||||||
|
|
||||||
return CompletableFuture.completedFuture(resultVO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 立即返回taskId,让调用者可以查询状态
|
||||||
|
return taskId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user