You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

171 lines
5.9 KiB

  1. package com.gaotao.modules.base.task;
  2. import com.gaotao.modules.base.entity.PrintTask;
  3. import com.gaotao.modules.base.service.PrintTaskService;
  4. import com.google.gson.Gson;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.beans.factory.annotation.Value;
  8. import org.springframework.scheduling.annotation.Scheduled;
  9. import org.springframework.stereotype.Component;
  10. import java.io.OutputStream;
  11. import java.net.Socket;
  12. import java.util.List;
  13. import java.util.Map;
  14. /**
  15. * 打印任务定时调度器
  16. *
  17. * <p><b>功能说明</b></p>
  18. * <ul>
  19. * <li>每秒扫描一次打印任务队列</li>
  20. * <li>按FIFO顺序created_date取出PENDING状态的任务</li>
  21. * <li>执行打印任务并更新状态</li>
  22. * <li>失败任务记录错误信息</li>
  23. * </ul>
  24. *
  25. * <p><b>并发控制</b></p>
  26. * <ul>
  27. * <li>使用数据库乐观锁markAsProcessing时检查状态</li>
  28. * <li>确保同一任务不会被重复执行</li>
  29. * </ul>
  30. */
  31. @Slf4j
  32. @Component
  33. public class PrintTaskScheduler {
  34. @Autowired
  35. private PrintTaskService printTaskService;
  36. private static final Gson gson = new Gson();
  37. @Value("${dashboard.push.enabled:true}")
  38. private boolean dashboardPushEnabled;
  39. // 每秒执行一次
  40. @Scheduled(fixedDelay = 500)
  41. public void processPrintTasks() {
  42. try {
  43. // 1. 获取待执行的任务(每次处理10个)
  44. List<PrintTask> pendingTasks = printTaskService.getPendingTasks(10);
  45. if (pendingTasks.isEmpty()) {
  46. return; // 没有待处理任务
  47. }
  48. log.info("【打印队列】发现 {} 个待执行任务", pendingTasks.size());
  49. // 2. 按FIFO顺序逐个执行
  50. for (PrintTask task : pendingTasks) {
  51. processTask(task);
  52. }
  53. } catch (Exception e) {
  54. log.error("打印任务调度器执行异常: {}", e.getMessage(), e);
  55. }
  56. }
  57. /**
  58. * 处理单个打印任务
  59. */
  60. private void processTask(PrintTask task) {
  61. Long taskId = task.getId();
  62. String printerIp = task.getPrinterIp();
  63. try {
  64. // 1. 标记为执行中(乐观锁,防止并发重复执行)
  65. boolean marked = printTaskService.markAsProcessing(taskId);
  66. if (!marked) {
  67. log.debug("任务 {} 已被其他线程处理,跳过", taskId);
  68. return;
  69. }
  70. log.info("【打印队列】开始执行任务 taskId={}, 打印机={}, 份数={}",
  71. taskId, printerIp, task.getCopies());
  72. // 2. 解析标签数据
  73. Map<String, Object> labelData = null;
  74. if (task.getLabelData() != null && !task.getLabelData().trim().isEmpty()) {
  75. labelData = gson.fromJson(task.getLabelData(), Map.class);
  76. }
  77. // 3. 执行打印
  78. boolean success = executePrint(
  79. printerIp,
  80. task.getZplCode(),
  81. task.getCopies(),
  82. task.getRfidFlag(),
  83. labelData
  84. );
  85. // 4. 更新任务状态
  86. if (success) {
  87. printTaskService.markAsSuccess(taskId);
  88. log.info("【打印队列】✓ 任务完成 taskId={}, 打印机={}", taskId, printerIp);
  89. } else {
  90. printTaskService.markAsFailed(taskId, "打印失败,未返回成功标识");
  91. log.error("【打印队列】✗ 任务失败 taskId={}, 打印机={}", taskId, printerIp);
  92. }
  93. } catch (Exception e) {
  94. log.error("【打印队列】✗ 任务执行异常 taskId={}, 错误: {}", taskId, e.getMessage(), e);
  95. printTaskService.markAsFailed(taskId, "执行异常: " + e.getMessage());
  96. }
  97. }
  98. /**
  99. * 执行打印发送ZPL到打印机
  100. * 注意ZPL代码已在入队时组装好包括RFID指令这里只需要直接发送
  101. *
  102. * @param printerIp 打印机IP
  103. * @param zplCode ZPL代码已包含RFID指令
  104. * @param copies 打印份数
  105. * @param rfidFlag RFID标识用于日志
  106. * @param labelData 标签数据未使用保留以备后续扩展
  107. * @return 是否成功
  108. */
  109. private boolean executePrint(String printerIp, String zplCode, Integer copies,
  110. String rfidFlag, Map<String, Object> labelData) {
  111. Socket socket = null;
  112. try {
  113. // 1. 连接打印机
  114. socket = new Socket(printerIp, 9100);
  115. socket.setSoTimeout(10000); // 10秒超时
  116. OutputStream os = socket.getOutputStream();
  117. int actualCopies = copies != null && copies > 0 ? copies : 1;
  118. // 2. 直接发送ZPL代码(已在入队时组装好,包括RFID指令)
  119. log.debug("开始发送ZPL到打印机 {}, 份数: {}, RFID: {}", printerIp, actualCopies, rfidFlag);
  120. for (int i = 0; i < actualCopies; i++) {
  121. os.write(zplCode.getBytes("UTF-8"));
  122. os.flush();
  123. // RFID标签需要等待处理时间
  124. if ("Y".equals(rfidFlag)) {
  125. Thread.sleep(1000); // RFID标签等待1秒
  126. log.debug("RFID标签打印完成 {} / {}", i + 1, actualCopies);
  127. }
  128. }
  129. log.debug("✓ ZPL已发送到打印机 {}, 份数: {}", printerIp, actualCopies);
  130. return true;
  131. } catch (Exception e) {
  132. log.error("发送ZPL到打印机失败: printerIp={}, error={}", printerIp, e.getMessage(), e);
  133. return false;
  134. } finally {
  135. if (socket != null) {
  136. try {
  137. socket.close();
  138. } catch (Exception e) {
  139. log.warn("关闭socket失败: {}", e.getMessage());
  140. }
  141. }
  142. }
  143. }
  144. }