- 新增异步任务线程池配置,支持项目初始化异步执行 - 定义异步任务状态枚举,统一管理任务生命周期状态 - 实现通用SSE通道管理器,支持用户绑定及多业务消息推送 - 创建统一SSE消息结构,支持多业务类型及事件分类 - 提供基础SSE连接管理接口,支持连接建立、状态查询及关闭 - 提供项目初始化异步任务服务接口及实现,支持进度回调和任务取消 - 添加项目初始化异步预览任务接口,支持异步提交、状态查询、结果获取及取消 - 新增项目初始化任务SSE接口,实现任务异步提交与实时进度推送 - 设计前端SSE集成文档,详细说明SSE连接、消息格式和对接步骤 - 添加Spring工具类,方便非Spring管理类获取Bean实例 - 优化项目控制器,整合异步任务相关API接口支持异步项目初始化工作流
119 lines
4.7 KiB
Java
119 lines
4.7 KiB
Java
package cn.yinlihupo.controller.project;
|
||
|
||
import cn.yinlihupo.common.core.BaseResponse;
|
||
import cn.yinlihupo.common.enums.AsyncTaskStatus;
|
||
import cn.yinlihupo.common.sse.SseChannelManager;
|
||
import cn.yinlihupo.common.sse.SseMessage;
|
||
import cn.yinlihupo.common.util.ResultUtils;
|
||
import cn.yinlihupo.service.project.ProjectInitAsyncService;
|
||
import lombok.RequiredArgsConstructor;
|
||
import lombok.extern.slf4j.Slf4j;
|
||
import org.springframework.web.bind.annotation.PostMapping;
|
||
import org.springframework.web.bind.annotation.RequestMapping;
|
||
import org.springframework.web.bind.annotation.RequestParam;
|
||
import org.springframework.web.bind.annotation.RestController;
|
||
import org.springframework.web.multipart.MultipartFile;
|
||
|
||
import java.util.HashMap;
|
||
import java.util.Map;
|
||
|
||
/**
|
||
* 项目初始化 SSE 控制器
|
||
* 使用通用 SSE 通道管理器,通过 userId 绑定,type 字段区分业务
|
||
*/
|
||
@Slf4j
|
||
@RestController
|
||
@RequestMapping("/api/v1/project-init")
|
||
@RequiredArgsConstructor
|
||
public class ProjectInitSseController {
|
||
|
||
private final ProjectInitAsyncService projectInitAsyncService;
|
||
private final SseChannelManager sseChannelManager;
|
||
|
||
/**
|
||
* 消息类型常量
|
||
*/
|
||
private static final String MESSAGE_TYPE = "project-init";
|
||
|
||
/**
|
||
* 通过 SSE 提交项目初始化任务
|
||
* 使用通用 SSE 通道,通过 userId 推送进度
|
||
*
|
||
* @param userId 用户ID
|
||
* @param file 项目资料文件
|
||
* @return 提交结果
|
||
*/
|
||
@PostMapping("/sse/submit-task")
|
||
public BaseResponse<Map<String, Object>> submitTaskWithSse(@RequestParam("userId") String userId,
|
||
@RequestParam("file") MultipartFile file) {
|
||
log.info("用户通过SSE提交任务, userId: {}, 文件名: {}", userId, file.getOriginalFilename());
|
||
|
||
if (file.isEmpty()) {
|
||
return ResultUtils.error("上传文件不能为空");
|
||
}
|
||
|
||
// 检查用户是否在线
|
||
if (!sseChannelManager.isOnline(userId)) {
|
||
return ResultUtils.error("用户未建立SSE连接,请先调用 /api/v1/sse/connect/" + userId);
|
||
}
|
||
|
||
try {
|
||
// 提交异步任务,带进度回调
|
||
String taskId = projectInitAsyncService.submitPreviewTask(file, taskVO -> {
|
||
// 构建消息并推送
|
||
SseMessage message = SseMessage.of(MESSAGE_TYPE, "progress", userId, taskVO);
|
||
sseChannelManager.send(userId, message);
|
||
|
||
// 任务完成或失败,推送完成事件
|
||
if (isTaskFinished(taskVO.getStatus())) {
|
||
SseMessage completeMessage = SseMessage.of(MESSAGE_TYPE, "complete", userId, taskVO);
|
||
sseChannelManager.send(userId, completeMessage);
|
||
}
|
||
});
|
||
|
||
// 推送任务提交成功事件
|
||
Map<String, Object> submittedData = new HashMap<>();
|
||
submittedData.put("taskId", taskId);
|
||
submittedData.put("message", "任务已提交");
|
||
|
||
SseMessage submittedMessage = SseMessage.of(MESSAGE_TYPE, "submitted", userId, submittedData);
|
||
sseChannelManager.send(userId, submittedMessage);
|
||
|
||
log.info("任务提交成功并通过SSE推送, userId: {}, taskId: {}", userId, taskId);
|
||
|
||
Map<String, Object> result = new HashMap<>();
|
||
result.put("taskId", taskId);
|
||
result.put("message", "任务已提交,进度将通过SSE推送");
|
||
return ResultUtils.success("提交成功", result);
|
||
|
||
} catch (Exception e) {
|
||
log.error("提交任务失败, userId: {}, error: {}", userId, e.getMessage(), e);
|
||
|
||
// 推送错误事件
|
||
Map<String, Object> errorData = new HashMap<>();
|
||
errorData.put("error", e.getMessage());
|
||
SseMessage errorMessage = SseMessage.of(MESSAGE_TYPE, "error", userId, errorData);
|
||
sseChannelManager.send(userId, errorMessage);
|
||
|
||
return ResultUtils.error("提交失败: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
// ==================== 工具方法 ====================
|
||
|
||
private boolean isTaskFinished(String status) {
|
||
return AsyncTaskStatus.COMPLETED.getCode().equals(status) ||
|
||
AsyncTaskStatus.FAILED.getCode().equals(status) ||
|
||
AsyncTaskStatus.CANCELLED.getCode().equals(status);
|
||
}
|
||
|
||
private void sendErrorAndClose(String userId, String errorMessage) {
|
||
Map<String, Object> errorData = new HashMap<>();
|
||
errorData.put("error", errorMessage);
|
||
|
||
SseMessage errorMessage_obj = SseMessage.of(MESSAGE_TYPE, "error", userId, errorData);
|
||
sseChannelManager.send(userId, errorMessage_obj);
|
||
sseChannelManager.closeChannel(userId);
|
||
}
|
||
}
|