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
171 lines
5.9 KiB
package com.gaotao.modules.base.task;
|
|
|
|
import com.gaotao.modules.base.entity.PrintTask;
|
|
import com.gaotao.modules.base.service.PrintTaskService;
|
|
import com.google.gson.Gson;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
import org.springframework.scheduling.annotation.Scheduled;
|
|
import org.springframework.stereotype.Component;
|
|
|
|
import java.io.OutputStream;
|
|
import java.net.Socket;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
/**
|
|
* 打印任务定时调度器
|
|
*
|
|
* <p><b>功能说明:</b></p>
|
|
* <ul>
|
|
* <li>每秒扫描一次打印任务队列</li>
|
|
* <li>按FIFO顺序(created_date)取出PENDING状态的任务</li>
|
|
* <li>执行打印任务并更新状态</li>
|
|
* <li>失败任务记录错误信息</li>
|
|
* </ul>
|
|
*
|
|
* <p><b>并发控制:</b></p>
|
|
* <ul>
|
|
* <li>使用数据库乐观锁(markAsProcessing时检查状态)</li>
|
|
* <li>确保同一任务不会被重复执行</li>
|
|
* </ul>
|
|
*/
|
|
@Slf4j
|
|
@Component
|
|
public class PrintTaskScheduler {
|
|
|
|
@Autowired
|
|
private PrintTaskService printTaskService;
|
|
|
|
private static final Gson gson = new Gson();
|
|
|
|
@Value("${dashboard.push.enabled:true}")
|
|
private boolean dashboardPushEnabled;
|
|
|
|
// 每秒执行一次
|
|
@Scheduled(fixedDelay = 500)
|
|
public void processPrintTasks() {
|
|
try {
|
|
// 1. 获取待执行的任务(每次处理10个)
|
|
List<PrintTask> pendingTasks = printTaskService.getPendingTasks(10);
|
|
|
|
if (pendingTasks.isEmpty()) {
|
|
return; // 没有待处理任务
|
|
}
|
|
|
|
log.info("【打印队列】发现 {} 个待执行任务", pendingTasks.size());
|
|
|
|
// 2. 按FIFO顺序逐个执行
|
|
for (PrintTask task : pendingTasks) {
|
|
processTask(task);
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
log.error("打印任务调度器执行异常: {}", e.getMessage(), e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 处理单个打印任务
|
|
*/
|
|
private void processTask(PrintTask task) {
|
|
Long taskId = task.getId();
|
|
String printerIp = task.getPrinterIp();
|
|
|
|
try {
|
|
// 1. 标记为执行中(乐观锁,防止并发重复执行)
|
|
boolean marked = printTaskService.markAsProcessing(taskId);
|
|
if (!marked) {
|
|
log.debug("任务 {} 已被其他线程处理,跳过", taskId);
|
|
return;
|
|
}
|
|
|
|
log.info("【打印队列】开始执行任务 taskId={}, 打印机={}, 份数={}",
|
|
taskId, printerIp, task.getCopies());
|
|
|
|
// 2. 解析标签数据
|
|
Map<String, Object> labelData = null;
|
|
if (task.getLabelData() != null && !task.getLabelData().trim().isEmpty()) {
|
|
labelData = gson.fromJson(task.getLabelData(), Map.class);
|
|
}
|
|
|
|
// 3. 执行打印
|
|
boolean success = executePrint(
|
|
printerIp,
|
|
task.getZplCode(),
|
|
task.getCopies(),
|
|
task.getRfidFlag(),
|
|
labelData
|
|
);
|
|
|
|
// 4. 更新任务状态
|
|
if (success) {
|
|
printTaskService.markAsSuccess(taskId);
|
|
log.info("【打印队列】✓ 任务完成 taskId={}, 打印机={}", taskId, printerIp);
|
|
} else {
|
|
printTaskService.markAsFailed(taskId, "打印失败,未返回成功标识");
|
|
log.error("【打印队列】✗ 任务失败 taskId={}, 打印机={}", taskId, printerIp);
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
log.error("【打印队列】✗ 任务执行异常 taskId={}, 错误: {}", taskId, e.getMessage(), e);
|
|
printTaskService.markAsFailed(taskId, "执行异常: " + e.getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 执行打印(发送ZPL到打印机)
|
|
* 注意:ZPL代码已在入队时组装好(包括RFID指令),这里只需要直接发送
|
|
*
|
|
* @param printerIp 打印机IP
|
|
* @param zplCode ZPL代码(已包含RFID指令)
|
|
* @param copies 打印份数
|
|
* @param rfidFlag RFID标识(用于日志)
|
|
* @param labelData 标签数据(未使用,保留以备后续扩展)
|
|
* @return 是否成功
|
|
*/
|
|
private boolean executePrint(String printerIp, String zplCode, Integer copies,
|
|
String rfidFlag, Map<String, Object> labelData) {
|
|
Socket socket = null;
|
|
try {
|
|
// 1. 连接打印机
|
|
socket = new Socket(printerIp, 9100);
|
|
socket.setSoTimeout(10000); // 10秒超时
|
|
|
|
OutputStream os = socket.getOutputStream();
|
|
|
|
int actualCopies = copies != null && copies > 0 ? copies : 1;
|
|
|
|
// 2. 直接发送ZPL代码(已在入队时组装好,包括RFID指令)
|
|
log.debug("开始发送ZPL到打印机 {}, 份数: {}, RFID: {}", printerIp, actualCopies, rfidFlag);
|
|
|
|
for (int i = 0; i < actualCopies; i++) {
|
|
os.write(zplCode.getBytes("UTF-8"));
|
|
os.flush();
|
|
|
|
// RFID标签需要等待处理时间
|
|
if ("Y".equals(rfidFlag)) {
|
|
Thread.sleep(1000); // RFID标签等待1秒
|
|
log.debug("RFID标签打印完成 {} / {}", i + 1, actualCopies);
|
|
}
|
|
}
|
|
|
|
log.debug("✓ ZPL已发送到打印机 {}, 份数: {}", printerIp, actualCopies);
|
|
return true;
|
|
|
|
} catch (Exception e) {
|
|
log.error("发送ZPL到打印机失败: printerIp={}, error={}", printerIp, e.getMessage(), e);
|
|
return false;
|
|
} finally {
|
|
if (socket != null) {
|
|
try {
|
|
socket.close();
|
|
} catch (Exception e) {
|
|
log.warn("关闭socket失败: {}", e.getMessage());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|