You've already forked FrameTour-BE
feat(printer): 实现打印机任务WebSocket实时推送功能
- 新增PrinterTaskPushService接口及实现,负责任务推送逻辑 - 在PrinterServiceImpl中集成WebSocket推送,在任务创建和审核通过时主动推送 - 新增WebSocket配置类和处理器,支持打印机通过WebSocket连接接收任务 - 实现连接管理器,维护打印机在线状态并支持心跳保活 - 添加相关模型类如WsMessage、WsMessageType等,规范通信协议 - 在PrinterMapper中增加查询待处理任务列表的方法 - 完善异常处理和日志记录,确保推送可靠性
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
package com.ycwl.basic.service.printer;
|
||||
|
||||
import com.ycwl.basic.model.printer.resp.PrintTaskResp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 打印机任务推送服务
|
||||
*/
|
||||
public interface PrinterTaskPushService {
|
||||
|
||||
/**
|
||||
* 推送任务到打印机
|
||||
*
|
||||
* @param printerId 打印机ID
|
||||
* @param taskId 任务ID
|
||||
* @return 是否推送成功
|
||||
*/
|
||||
boolean pushTaskToPrinter(Integer printerId, Integer taskId);
|
||||
|
||||
/**
|
||||
* 获取打印机的待处理任务列表
|
||||
*
|
||||
* @param printerId 打印机ID
|
||||
* @return 待处理任务列表
|
||||
*/
|
||||
List<PrintTaskResp> getPendingTasksByPrinterId(Integer printerId);
|
||||
}
|
||||
@@ -67,6 +67,7 @@ import com.ycwl.basic.repository.ScenicRepository;
|
||||
import com.ycwl.basic.service.mobile.WxPayService;
|
||||
import com.ycwl.basic.service.pc.FaceService;
|
||||
import com.ycwl.basic.service.printer.PrinterService;
|
||||
import com.ycwl.basic.service.printer.PrinterTaskPushService;
|
||||
import com.ycwl.basic.storage.StorageFactory;
|
||||
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
@@ -140,6 +141,8 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
private FaceService faceService;
|
||||
@Autowired
|
||||
private DeviceRepository deviceRepository;
|
||||
@Autowired
|
||||
private PrinterTaskPushService taskPushService;
|
||||
|
||||
// 用于优先打印的线程池,核心线程数根据实际情况调整
|
||||
private final ExecutorService preferPrintExecutor = Executors.newFixedThreadPool(
|
||||
@@ -961,6 +964,17 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
task.setCreateTime(new Date());
|
||||
task.setUpdateTime(new Date());
|
||||
printTaskMapper.insertTask(task);
|
||||
|
||||
// ========== WebSocket 推送任务 ==========
|
||||
// 只推送立即可处理的任务(status=0),待审核任务(status=4)等审核通过后再推送
|
||||
if (initialStatus == TASK_STATUS_PENDING) {
|
||||
try {
|
||||
taskPushService.pushTaskToPrinter(printer.getId(), task.getId());
|
||||
} catch (Exception e) {
|
||||
log.error("推送任务失败: printerId={}, taskId={}", printer.getId(), task.getId(), e);
|
||||
// 推送失败不影响任务创建,任务会通过 HTTP 轮询获取
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1001,7 +1015,21 @@ public class PrinterServiceImpl implements PrinterService {
|
||||
return 0;
|
||||
}
|
||||
// 将状态从4(待审核)改为0(待处理)
|
||||
return printTaskMapper.batchUpdateStatus(taskIds, TASK_STATUS_PENDING);
|
||||
int count = printTaskMapper.batchUpdateStatus(taskIds, TASK_STATUS_PENDING);
|
||||
|
||||
// ========== WebSocket 推送审核通过的任务 ==========
|
||||
for (Integer taskId : taskIds) {
|
||||
try {
|
||||
PrintTaskEntity task = printTaskMapper.selectById(taskId);
|
||||
if (task != null && task.getPrinterId() != null) {
|
||||
taskPushService.pushTaskToPrinter(task.getPrinterId(), taskId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("推送审核任务失败: taskId={}", taskId, e);
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.ycwl.basic.service.printer.impl;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ycwl.basic.mapper.PrinterMapper;
|
||||
import com.ycwl.basic.model.pc.printer.entity.PrintTaskEntity;
|
||||
import com.ycwl.basic.model.printer.resp.PrintTaskResp;
|
||||
import com.ycwl.basic.service.printer.PrinterTaskPushService;
|
||||
import com.ycwl.basic.websocket.manager.PrinterConnectionManager;
|
||||
import com.ycwl.basic.websocket.model.WsMessage;
|
||||
import com.ycwl.basic.websocket.model.WsMessageType;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 打印机任务推送服务实现
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class PrinterTaskPushServiceImpl implements PrinterTaskPushService {
|
||||
|
||||
private static final int TASK_STATUS_PENDING = 0;
|
||||
private static final int TASK_STATUS_PROCESSING = 3;
|
||||
|
||||
@Autowired
|
||||
private PrinterMapper printerMapper;
|
||||
|
||||
@Autowired
|
||||
private PrinterConnectionManager connectionManager;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Override
|
||||
public boolean pushTaskToPrinter(Integer printerId, Integer taskId) {
|
||||
try {
|
||||
// 1. 检查打印机是否在线
|
||||
if (!connectionManager.isOnline(printerId)) {
|
||||
log.debug("打印机不在线,跳过推送: printerId={}, taskId={}", printerId, taskId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 获取 WebSocket 连接
|
||||
WebSocketSession session = connectionManager.getSession(printerId);
|
||||
if (session == null || !session.isOpen()) {
|
||||
log.warn("打印机连接不可用: printerId={}, taskId={}", printerId, taskId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3. 执行 CAS 操作,确保任务只被推送一次
|
||||
int updatedRows = printerMapper.compareAndSetTaskStatus(
|
||||
taskId, TASK_STATUS_PENDING, TASK_STATUS_PROCESSING
|
||||
);
|
||||
|
||||
if (updatedRows != 1) {
|
||||
log.debug("任务已被获取,跳过推送: printerId={}, taskId={}", printerId, taskId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. 查询任务详情
|
||||
PrintTaskEntity taskEntity = printerMapper.getTaskById(taskId);
|
||||
if (taskEntity == null) {
|
||||
log.error("任务不存在: taskId={}", taskId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 5. 转换为 PrintTaskResp
|
||||
PrintTaskResp task = new PrintTaskResp();
|
||||
BeanUtils.copyProperties(taskEntity, task);
|
||||
task.setStatus(TASK_STATUS_PROCESSING);
|
||||
|
||||
// 6. 通过 WebSocket 推送任务
|
||||
WsMessage<PrintTaskResp> message = WsMessage.create(WsMessageType.TASK_PUSH, task);
|
||||
String json = objectMapper.writeValueAsString(message);
|
||||
session.sendMessage(new TextMessage(json));
|
||||
|
||||
log.info("任务推送成功: printerId={}, taskId={}", printerId, taskId);
|
||||
return true;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("任务推送失败: printerId={}, taskId={}", printerId, taskId, e);
|
||||
// 推送失败时,恢复任务状态为待处理
|
||||
try {
|
||||
printerMapper.compareAndSetTaskStatus(
|
||||
taskId, TASK_STATUS_PROCESSING, TASK_STATUS_PENDING
|
||||
);
|
||||
} catch (Exception ex) {
|
||||
log.error("恢复任务状态失败: taskId={}", taskId, ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PrintTaskResp> getPendingTasksByPrinterId(Integer printerId) {
|
||||
// 直接查询该打印机所有待处理任务 (status=0),最多返回 100 个
|
||||
List<PrintTaskResp> tasks = printerMapper.listPendingTasksByPrinterId(printerId);
|
||||
|
||||
if (tasks.size() >= 100) {
|
||||
log.warn("待处理任务过多,已达上限: printerId={}, count={}", printerId, tasks.size());
|
||||
}
|
||||
|
||||
return tasks;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user