打印问题

This commit is contained in:
2025-12-30 10:23:04 +08:00
parent 329d9dfb3d
commit 7384b67c50
9 changed files with 415 additions and 301 deletions

View File

@@ -12,7 +12,6 @@ import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import java.util.function.Consumer;
@@ -61,7 +60,7 @@ public class PrintMqListener {
}
Boolean printOrder = jsonObject.getBoolean("printOrder");
funUtil.runFunAndCheckKey(() -> {
printerHandler.handler(orderId, printOrder != null && !printOrder ? PrinterHandler.PrintTypeEnum.ONE : PrinterHandler.PrintTypeEnum.ONE_AND_ORDER, null);
printerHandler.handler(orderId, printOrder != null && !printOrder ? PrinterHandler.PrintTypeEnum.ONE : PrinterHandler.PrintTypeEnum.ONE_AND_ORDER);
return null;
}, RedisCst.getLockKey("orderPrint", orderId));
});
@@ -72,7 +71,7 @@ public class PrintMqListener {
*/
@RabbitListener(queues = {"${spring.profiles.active}-" + RabbitConstants.Queue.ORDER_HANDOVER_PRINT_QUEUE})
public void handoverPrint(String id) {
invokeFun("handoverPrint", "java.order", id, (data) -> printerHandler.handler(data, PrinterHandler.PrintTypeEnum.HANDOVER, null));
invokeFun("handoverPrint", "java.order", id, (data) -> printerHandler.handler(data, PrinterHandler.PrintTypeEnum.HANDOVER));
}
/**
@@ -80,6 +79,6 @@ public class PrintMqListener {
*/
@RabbitListener(queues = {"${spring.profiles.active}-" + RabbitConstants.Queue.CALL_TABLE_PRINT_QUEUE})
public void callTablePrint(String id) {
invokeFun("handoverPrint", "java.order", id, (data) -> printerHandler.handler(data, PrinterHandler.PrintTypeEnum.CALL, null));
invokeFun("handoverPrint", "java.order", id, (data) -> printerHandler.handler(data, PrinterHandler.PrintTypeEnum.CALL));
}
}

View File

@@ -24,9 +24,5 @@ public class OrderInfoPrintDTO implements Serializable {
*/
@NotNull(message = "打印类型不为空")
private Integer type;
/**
* 打印机id
*/
private Long machineId;
}

View File

@@ -11,6 +11,6 @@ import com.czg.order.entity.PrintMachineLog;
* @since 2025-03-11
*/
public interface PrintMachineLogService extends IService<PrintMachineLog> {
void save(PrintMachine config, String bizType, String printContent, Object respJson);
void save(PrintMachine config, String bizType, String printContent, String respJson);
}

View File

@@ -1,17 +1,18 @@
package com.czg.service.order.print;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.UnicodeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.czg.account.dto.HandoverRecordDTO;
import com.czg.account.entity.HandoverRecord;
import com.czg.account.entity.PrintMachine;
import com.czg.account.entity.ShopInfo;
import com.czg.account.service.ShopInfoService;
import com.czg.order.entity.OrderDetail;
import com.czg.order.entity.OrderInfo;
import com.czg.service.order.enums.OrderStatusEnums;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.http.HttpEntity;
@@ -20,12 +21,13 @@ import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Administrator
@@ -33,11 +35,6 @@ import java.util.List;
@Component
@Slf4j
public class FeiPrinter extends PrinterHandler implements PrinterImpl {
@Resource
private RestTemplate restTemplate;
@Resource
private ShopInfoService shopInfoService;
// API 地址
private static final String URL = "http://api.feieyun.cn/Api/Open/";
@@ -72,10 +69,8 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl {
String remark = orderDetail.getRemark();
String content = buildDishPrintData(false, getPickupNum(orderInfo), orderInfo.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
orderDetail.getProductName(), orderDetail.getSkuName(), orderDetail.getNum(), remark, orderDetail.getProGroupInfo(), orderDetail.getId(), orderDetail.isUrgent());
Object o = sendPrintRequest(machine.getAddress(), content, null, "1");
String o = sendPrintRequest(machine.getAddress(), content, null, "1");
printMachineLogService.save(machine, "新订单", content, o);
// printMachineLogService.save(machine, "新订单", , );
}
@@ -84,7 +79,7 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl {
String remark = orderDetail.getRemark();
String content = buildDishPrintData(true, getPickupNum(orderInfo), orderInfo.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
orderDetail.getProductName(), orderDetail.getSkuName(), orderDetail.getReturnNum(), remark, orderDetail.getProGroupInfo(), orderDetail.getId(), orderDetail.isUrgent());
Object o = sendPrintRequest(machine.getAddress(), content, null, "1");
String o = sendPrintRequest(machine.getAddress(), content, null, "1");
printMachineLogService.save(machine, "退款单", content, o);
}
@@ -106,8 +101,8 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl {
.setRemark(orderInfo.getRemark())
.setDiscountAmount(orderInfo.getOriginAmount().subtract(orderInfo.getPayAmount()).toPlainString());
String string = buildOrderPrintData(printInfoDTO, detailList);
Object o = sendPrintRequest(machine.getAddress(), string, null, printerNum);
printMachineLogService.save(machine, "退款", string, o);
String o = sendPrintRequest(machine.getAddress(), string, null, printerNum);
printMachineLogService.save(machine, "结算", string, o);
}
@@ -143,7 +138,7 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl {
}
String string = buildOrderPrintData(printInfoDTO, detailList);
Object resp = sendPrintRequest(machine.getAddress(), string, null, printerNum);
String resp = sendPrintRequest(machine.getAddress(), string, null, printerNum);
printMachineLogService.save(machine, "结算单", string, resp);
}
@@ -151,7 +146,7 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl {
protected void callNumPrint(PrintMachine machine, String callNum, String shopName, String tableName, String tableNote, String preNum, String codeUrl, LocalDateTime takeTime, String shopNote) {
String voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一条新的排号记录\"}";
String data = buildCallTicketData(shopName, tableName, callNum, preNum, codeUrl, shopNote, takeTime);
Object resp = sendPrintRequest(machine.getAddress(), data, voiceJson, "1");
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, "1");
printMachineLogService.save(machine, "叫号单", data, resp);
}
@@ -170,7 +165,7 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl {
}
@Override
public <R> R sendPrintRequest(String address, String metaPrintData, String voiceData, String printerNum) {
public String sendPrintRequest(String address, String metaPrintData, String voiceData, String printerNum) {
log.info("飞蛾打印机开始发送打印请求, 设备地址: {}, 元数据: {}", address, metaPrintData);
String time = String.valueOf(System.currentTimeMillis() / 1000);
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
@@ -189,12 +184,68 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl {
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
String result = restTemplate.postForObject(URL, requestEntity, String.class);
log.info("打印结果: {}", result);
return (R) result;
log.info("飞鹅打印结果: {}", result);
return result;
} catch (Exception e) {
log.error("打印请求失败: {}", e.getMessage());
throw new RuntimeException("飞蛾打印请求失败", e);
}
}
/**
* 检查飞鹅打印机 打印任务是否已打印
*
* @param printOrderId 打印订单编号
* @return null-未知错误true-已打印false-未打印
*/
public Boolean checkFPrintStatus(String printOrderId) {
String time = String.valueOf(System.currentTimeMillis() / 1000);
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("user", USER);
paramMap.put("stime", time);
paramMap.put("sig", signature(time));
paramMap.put("apiname", "Open_queryOrderState");
paramMap.put("orderid", printOrderId);
Boolean ret;
try {
String resp = HttpUtil.post(URL, paramMap, 1000 * 5);
//成功 {"msg":"ok","ret":0,"data":true,"serverExecutedTime":4}
//失败 {"msg":"ok","ret":0,"data":false,"serverExecutedTime":4}
JSONObject json = JSONUtil.parseObj(UnicodeUtil.toString(resp));
log.info("飞鹅打印机 打印任务状态响应: {}", json);
ret = json.getBool("data");
} catch (Exception e) {
ret = null;
}
return ret;
}
/**
* 检查飞鹅打印机是否在线
*
* @param sn 设备编号
* @return 在线,工作状态正常。/离线。/未知错误
*/
public String checkOnline(String sn) {
String time = String.valueOf(System.currentTimeMillis() / 1000);
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("user", USER);
paramMap.put("stime", time);
paramMap.put("sig", signature(time));
paramMap.put("apiname", "Open_queryPrinterStatus");
paramMap.put("sn", sn);
String msg;
try {
String resp = HttpUtil.post(URL, paramMap, 1000 * 5);
//成功 开机 {"msg":"ok","ret":0,"data":"在线,工作状态正常。","serverExecutedTime":4}
//成功 离线 {"msg":"ok","ret":0,"data":"离线。","serverExecutedTime":7}
JSONObject json = JSONUtil.parseObj(UnicodeUtil.toString(resp));
log.info("飞鹅打印机状态响应: {}", json);
msg = json.getStr("data");
} catch (Exception e) {
msg = "未知错误";
}
return msg;
}
}

View File

@@ -34,6 +34,7 @@ import lombok.ToString;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.client.RestTemplate;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@@ -50,6 +51,8 @@ public abstract class PrinterHandler {
protected PrinterHandler nextPrinter;
protected String printerBrand;
@Resource
protected RestTemplate restTemplate;
@Resource
protected OrderDetailService orderDetailService;
@Resource
@@ -81,7 +84,11 @@ public abstract class PrinterHandler {
@Getter
public enum PrintTypeEnum {
HANDOVER("交班", "handover"),
ORDER("订单", "order"), ONE("菜品", "one"), CALL("叫号", "call"), ONE_AND_ORDER("菜品和结算单同时打印", "oneAndOrder"), PRE_ORDER("预结算单", "preOrder");
ORDER("订单", "order"),
ONE("菜品", "one"),
CALL("叫号", "call"),
ONE_AND_ORDER("菜品和结算单同时打印", "oneAndOrder"),
PRE_ORDER("预结算单", "preOrder");
private final String name;
private final String code;
@@ -145,10 +152,9 @@ public abstract class PrinterHandler {
* @param printType 打印类型JSON数组 refund-确认退款单 handover-交班单 queue-排队取号
* @return 打印机列表
*/
private List<PrintMachine> getPrintMachine(Long shopId, String subType, String printMethod, String printType, Long machineId) {
private List<PrintMachine> getPrintMachine(Long shopId, String subType, String printMethod, String printType) {
QueryWrapper wrapper = new QueryWrapper()
.eq(PrintMachine::getStatus, 1)
.eq(PrintMachine::getId, machineId)
.eq(PrintMachine::getShopId, shopId)
.eq(PrintMachine::getSubType, subType)
.eq(PrintMachine::getConnectionType, "网络");
@@ -171,10 +177,6 @@ public abstract class PrinterHandler {
wrapper.like(PrintMachine::getPrintType, printType);
}
List<PrintMachine> list = printMachineService.list(wrapper);
// for (PrintMachine item : list) {
// //实际打印以传递的参数为准
// item.setPrintMethod(printMethod);
// }
if (list.isEmpty()) {
log.error("店铺未配置打印机店铺id: {}", shopId);
return list;
@@ -190,7 +192,7 @@ public abstract class PrinterHandler {
* @param data 传递的数据
* @param printTypeEnum order returnOrder preOrder one call handover
*/
public void handler(String data, PrintTypeEnum printTypeEnum, Long machineId) {
public void handler(String data, PrintTypeEnum printTypeEnum) {
Long shopId;
String printMethod = "";
String printType = "";
@@ -261,7 +263,7 @@ public abstract class PrinterHandler {
}
Object finalObj = obj;
getPrintMachine(shopId, "cash", printMethod, printType, machineId).forEach(machine -> {
getPrintMachine(shopId, "cash", printMethod, printType).forEach(machine -> {
handleRequest(machine, finalObj, printTypeEnum);
// printPlaceTicket(isReturn, machine, orderInfo, shopInfo);
});
@@ -447,17 +449,7 @@ public abstract class PrinterHandler {
log.info("台位费商品,不打印");
return;
}
// ProdSku sku = prodSkuService.getById(item.getSkuId());
// if (isTemporary == 0 && sku == null) {
// log.error("商品不存在, id: {}", item.getSkuId());
// return;
// } else if (isTemporary == 1) {
// sku = new ProdSku();
// }
// String remark = StrUtil.isNotBlank(sku.getSpecInfo()) ? sku.getSpecInfo() : "";
// item.setRemark(remark);
if (item.getReturnNum().compareTo(BigDecimal.ZERO) > 0) {
returnDishesPrint(orderInfo, item, machine);
}
@@ -468,7 +460,8 @@ public abstract class PrinterHandler {
// 保存已打印信息
OrderDetail orderDetail = detailMap.get(item.getId());
redisService.set(RedisCst.getPrintOrderDetailKey(orderInfo.getId(), item.getId()), JSONObject.toJSONString(new PrintDetailInfo().setPrint(item.getIsPrint() == 1).setDetailId(item.getId())
redisService.set(RedisCst.getPrintOrderDetailKey(orderInfo.getId(), item.getId()),
JSONObject.toJSONString(new PrintDetailInfo().setPrint(item.getIsPrint() == 1).setDetailId(item.getId())
.setPrintNum(orderDetail.getNum()).setPrintReturnNum(orderDetail.getReturnNum())), 3600 * 24);
});

View File

@@ -9,7 +9,6 @@ import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.czg.account.dto.HandoverRecordDTO;
import com.czg.account.entity.HandoverRecord;
import com.czg.order.entity.OrderDetail;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -69,10 +68,9 @@ public interface PrinterImpl {
* @param metaPrintData 打印元数据
* @param voiceData 语音信息
* @param printNum 打印联数
* @param <R> 返回数据类型
* @return 打印结果
*/
<R> R sendPrintRequest(String address, String metaPrintData, String voiceData, String printNum);
String sendPrintRequest(String address, String metaPrintData, String voiceData, String printNum);
/**
* 获取当前打印机标签信息
@@ -560,12 +558,6 @@ public interface PrinterImpl {
return str;
}
public static void main(String[] args) {
System.out.println("水煮肉片".length());
System.out.println(StrUtil.repeat(' ', 8));
System.out.println(StrUtil.fillAfter("水煮肉片", ' ', 21));
}
/**
* 获取填充字符串, 并且换行
*

View File

@@ -4,11 +4,10 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import com.czg.account.dto.HandoverRecordDTO;
import com.czg.account.entity.HandoverRecord;
import com.czg.account.entity.PrintMachine;
import com.czg.account.entity.ShopInfo;
import com.czg.account.service.ShopInfoService;
import com.czg.order.entity.OrderDetail;
import com.czg.order.entity.OrderInfo;
import com.czg.service.order.enums.OrderStatusEnums;
@@ -20,9 +19,7 @@ import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
@@ -45,12 +42,6 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
//APPSECRET
private static final String APP_SECRET = "2022bsjZF544GAH";
@Resource
private ShopInfoService shopInfoService;
@Resource
private RestTemplate restTemplate;
public YxyPrinter() {
super("云想印");
}
@@ -75,7 +66,7 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
@Override
public <R> R sendPrintRequest(String address, String metaPrintData, String voiceData, String printNum) {
public String sendPrintRequest(String address, String metaPrintData, String voiceData, String printNum) {
log.info("开始请求云享印,请求数据:{}, {}", voiceData, metaPrintData);
//设备名称
//行为方式 1:只打印数据 2:只播放信息 3:打印数据并播放信息
@@ -87,10 +78,9 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
String time = String.valueOf(System.currentTimeMillis());
String uuid = UUID.randomUUID().toString();
Map<String, String> param = getToken(time, uuid);
//参数
MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>();
multiValueMap.add("token", param.get("TOKEN"));
multiValueMap.add("token", getToken(time, uuid));
multiValueMap.add("devName", address);
multiValueMap.add("actWay", 3);
multiValueMap.add("cn", printNum);
@@ -108,7 +98,7 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
httpEntity, String.class);
log.info("请求云享印成功,响应数据: {}", httpResponse);
return (R) httpResponse;
return httpResponse;
}
@Override
@@ -116,9 +106,7 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
String buildDishPrintData = buildDishPrintData(false, getPickupNum(orderInfo), DateUtil.format(orderDetail.getCreateTime(), "yyyy-MM-dd HH:mm:ss"), orderDetail.getProductName(), orderDetail.getSkuName(),
orderDetail.getNum(), orderDetail.getRemark(), orderDetail.getProGroupInfo(), orderDetail.getId(), orderDetail.isUrgent());
String voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
// String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
Object resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, "1");
// sendPrintRequest(voiceJson, 3, 1, machine.getAddress(), data);
String resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, "1");
printMachineLogService.save(machine, "新订单", buildDishPrintData, resp);
}
@@ -127,9 +115,8 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
protected void returnDishesPrint(OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine) {
String buildDishPrintData = buildDishPrintData(true, getPickupNum(orderInfo), DateUtil.format(orderDetail.getCreateTime(), "yyyy-MM-dd HH:mm:ss"), orderDetail.getProductName(), orderDetail.getSkuName(),
orderDetail.getReturnNum(), orderDetail.getRemark(), orderDetail.getProGroupInfo(), orderDetail.getId(), orderDetail.isUrgent());
// String voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
Object resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, "1");
String resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, "1");
printMachineLogService.save(machine, "退款单", buildDishPrintData, resp);
}
@@ -141,18 +128,17 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
.setOrderNo(orderInfo.getOrderNo()).setTradeDate(DateUtil.format(orderInfo.getCreateTime(), "yyyy-MM-dd HH:mm:ss")).setOperator("【POS-1】001").setPayAmount(orderInfo.getPayAmount().toPlainString())
.setOriginalAmount(orderInfo.getOriginAmount().toPlainString()).setReturn(isReturn(orderInfo))
.setBalance(balance).setPayType((ObjectUtil.isEmpty(orderInfo.getPayType()) || ObjectUtil.isNull(orderInfo.getPayType()) ? "" : orderInfo.getPayType())).setIntegral("0")
.setOutNumber(orderInfo.getTakeCode()).setPrintTitle("结算")
.setOutNumber(orderInfo.getTakeCode()).setPrintTitle("退款")
.setRemark(orderInfo.getRemark()).setDiscountAmount(orderInfo.getOriginAmount().subtract(orderInfo.getPayAmount()).toPlainString());
String data = buildOrderPrintData(printInfoDTO, detailList);
String voiceJson = "{\"PbizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
// String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
String printerNum = "1";
if (StrUtil.isNotBlank(machine.getPrintQty())) {
printerNum = machine.getPrintQty().split("\\^")[1];
}
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, printerNum);
printMachineLogService.save(machine, "新订", data, resp);
printMachineLogService.save(machine, "退款", data, resp);
}
@@ -183,23 +169,28 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
String data = buildOrderPrintData(printInfoDTO, detailList);
String voiceJson = "{\"PbizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
// String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
String printerNum = "1";
if (StrUtil.isNotBlank(machine.getPrintQty())) {
printerNum = machine.getPrintQty().split("\\^")[1];
}
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, printerNum);
// printMachineLogService.save(machine, printType, data, resp);
printMachineLogService.save(machine, "新订单", data, resp);
printMachineLogService.save(machine, "结算单", data, resp);
}
/**
* 叫号单打印
*/
@Override
protected void callNumPrint(PrintMachine machine, String callNum, String shopName, String tableName, String tableNote, String preNum, String codeUrl, LocalDateTime takeTime, String shopNote) {
String resp = buildCallTicketData(shopName, tableName, callNum, preNum, codeUrl, shopNote, takeTime);
sendPrintRequest(machine.getAddress(), resp, null, "1");
}
/**
* 交班单打印
*/
@Override
protected void handoverPrint(PrintMachine machine, HandoverRecordDTO record) {
String string = buildHandoverData(record);
@@ -214,9 +205,9 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
* @param requestId 请求ID自定义
* @return token信息
*/
private static Map<String, String> getToken(String timestamp, String requestId) {
private static String getToken(String timestamp, String requestId) {
StringBuilder token = new StringBuilder();
StringBuilder encode = new StringBuilder();
// StringBuilder encode = new StringBuilder();
SortedMap<String, Object> map = new TreeMap<>();
map.put("appId", APP_ID);
map.put("timestamp", timestamp);
@@ -226,13 +217,38 @@ public class YxyPrinter extends PrinterHandler implements PrinterImpl {
String key = next.getKey();
Object value = next.getValue();
token.append(key).append(value);
encode.append(key).append("=").append(value).append("&");
// encode.append(key).append("=").append(value).append("&");
}
Map<String, String> finalMap = new HashMap<>();
finalMap.put("ENCODE", encode.toString());
finalMap.put("TOKEN", SecureUtil.md5(token + APP_SECRET).toUpperCase());
return finalMap;
// Map<String, String> finalMap = new HashMap<>();
// finalMap.put("ENCODE", encode.toString());
// finalMap.put("TOKEN", SecureUtil.md5(token + APP_SECRET).toUpperCase());
// return finalMap;
return SecureUtil.md5(token + APP_SECRET).toUpperCase();
}
/**
* 检查打印状态
*
* @param devName 设备名称,(唯一) 对应配置表中的address字段即IP地址/打印机编号)
* @param taskId 打印任务id用于复查打印状态云想印=orderId
*/
public String checkPrintStatus(String devName, String taskId) {
String time = String.valueOf(System.currentTimeMillis());
String uuid = UUID.randomUUID().toString();
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("devName", devName);
paramMap.put("orderId", taskId);
paramMap.put("token", getToken(time, uuid));
paramMap.put("appId", APP_ID);
paramMap.put("timestamp", time);
paramMap.put("requestId", uuid);
paramMap.put("userCode", USER_CODE);
String s = HttpUtil.get("https://ioe.car900.com/v1/openApi/dev/findOrder.json", paramMap, 1000 * 5);
log.info("云想印打印机:{},任务:{}状态:{}", devName, taskId, s);
return s;
}
}

View File

@@ -1523,13 +1523,13 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
switch (orderInfoPrintDTO.getType()) {
case 0:
printerHandler.handler(orderInfo.getId().toString(), PrinterHandler.PrintTypeEnum.ONE_AND_ORDER, orderInfoPrintDTO.getMachineId());
printerHandler.handler(orderInfo.getId().toString(), PrinterHandler.PrintTypeEnum.ONE_AND_ORDER);
break;
case 1:
printerHandler.handler(orderInfo.getId().toString(), PrinterHandler.PrintTypeEnum.PRE_ORDER, orderInfoPrintDTO.getMachineId());
printerHandler.handler(orderInfo.getId().toString(), PrinterHandler.PrintTypeEnum.PRE_ORDER);
break;
case 2:
printerHandler.handler(orderInfo.getId().toString(), PrinterHandler.PrintTypeEnum.ORDER, orderInfoPrintDTO.getMachineId());
printerHandler.handler(orderInfo.getId().toString(), PrinterHandler.PrintTypeEnum.ORDER);
break;
}
return true;

View File

@@ -2,28 +2,31 @@ package com.czg.service.order.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.UnicodeUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.czg.account.entity.PrintMachine;
import com.czg.market.service.OrderInfoService;
import com.czg.order.entity.PrintMachineLog;
import com.czg.order.service.PrintMachineLogService;
import com.czg.service.order.mapper.PrintMachineLogMapper;
import com.czg.service.order.print.FeiPrinter;
import com.czg.service.order.print.YxyPrinter;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
/**
* 店铺小票打印记录ServiceImpl
@@ -35,135 +38,22 @@ import java.util.*;
@Service
@RequiredArgsConstructor
public class PrintMachineLogServiceImpl extends ServiceImpl<PrintMachineLogMapper, PrintMachineLog> implements PrintMachineLogService {
//请求地址
private static final String URL_STR = "https://ioe.car900.com/v1/openApi/dev/customPrint.json";
//APPID
private static final String APP_ID = "ZF544";
//USERCODE
private static final String USER_CODE = "ZF544";
//APPSECRET
private static final String APP_SECRET = "2022bsjZF544GAH";
public static final String URL = "http://api.feieyun.cn/Api/Open/";//不需要修改
public static final String USER = "chaozhanggui2022@163.com";//*必填*:账号名
public static final String UKEY = "UfWkhXxSkeSSscsU";//*必填*: 飞鹅云后台注册账号后生成的UKEY 【备注这不是填打印机的KEY】
public static final String SN = "960238952";//*必填*打印机编号必须要在管理后台里添加打印机或调用API接口添加之后才能调用API
@Resource
private OrderInfoService orderInfoService;
@Lazy
@Resource
private YxyPrinter yxyPrinter;
@Lazy
@Resource
private FeiPrinter feiPrinter;
/**
* 获取TOKEN值
*
* @param timestamp 时间戳13位
* @param requestId 请求ID自定义
* @return
*/
private static Map<String, String> getToken(String timestamp, String requestId) {
StringBuilder token = new StringBuilder();
StringBuilder encode = new StringBuilder();
SortedMap<String, Object> map = new TreeMap<>();
map.put("appId", APP_ID);
map.put("timestamp", timestamp);
map.put("requestId", requestId);
map.put("userCode", USER_CODE);
for (Map.Entry<String, Object> next : map.entrySet()) {
String key = next.getKey();
Object value = next.getValue();
token.append(key).append(value);
encode.append(key).append("=").append(value).append("&");
}
System.out.println("token" + token);
Map<String, String> finalMap = new HashMap<>();
finalMap.put("ENCODE", encode.toString());
finalMap.put("TOKEN", SecureUtil.md5(token + APP_SECRET).toUpperCase());
return finalMap;
}
/**
* 检查打印状态
*
* @param devName 设备名称,(唯一) 对应配置表中的address字段即IP地址/打印机编号)
* @param taskId 打印任务id用于复查打印状态云想印=orderId
* @return
*/
public static String checkPrintStatus(String devName, String taskId) {
String time = String.valueOf(System.currentTimeMillis());
String uuid = UUID.randomUUID().toString();
Map<String, String> param = getToken(time, uuid);
String token = param.get("TOKEN");
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("devName", devName);
paramMap.put("orderId", taskId);
paramMap.put("token", token);
paramMap.put("appId", APP_ID);
paramMap.put("timestamp", time);
paramMap.put("requestId", uuid);
paramMap.put("userCode", USER_CODE);
return HttpUtil.get("https://ioe.car900.com/v1/openApi/dev/findOrder.json", paramMap, 1000 * 5);
}
private static String signature(String USER, String UKEY, String STIME) {
return DigestUtils.sha1Hex(USER + UKEY + STIME);
}
/**
* 检查飞鹅打印机打印任务是否已打印
*
* @param printOrderId 打印订单编号
* @return null-未知错误true-已打印false-未打印
*/
public static Boolean checkFPrintStatus(String printOrderId) {
String STIME = String.valueOf(System.currentTimeMillis() / 1000);
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("user", USER);
paramMap.put("stime", STIME);
paramMap.put("sig", signature(USER, UKEY, STIME));
paramMap.put("apiname", "Open_queryOrderState");
paramMap.put("orderid", printOrderId);
Boolean ret;
try {
String resp = HttpUtil.post(URL, paramMap, 1000 * 5);
//成功 {"msg":"ok","ret":0,"data":true,"serverExecutedTime":4}
//失败 {"msg":"ok","ret":0,"data":false,"serverExecutedTime":4}
JSONObject json = JSONUtil.parseObj(UnicodeUtil.toString(resp));
ret = json.getBool("data");
} catch (Exception e) {
ret = null;
}
return ret;
}
/**
* 检查飞鹅打印机是否在线
*
* @param sn 设备编号
* @return 在线,工作状态正常。/离线。/未知错误
*/
public static String checkOnline(String sn) {
String STIME = String.valueOf(System.currentTimeMillis() / 1000);
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("user", USER);
paramMap.put("stime", STIME);
paramMap.put("sig", signature(USER, UKEY, STIME));
paramMap.put("apiname", "Open_queryPrinterStatus");
paramMap.put("sn", sn);
String msg;
try {
String resp = HttpUtil.post(URL, paramMap, 1000 * 5);
//成功 开机 {"msg":"ok","ret":0,"data":"在线,工作状态正常。","serverExecutedTime":4}
//成功 离线 {"msg":"ok","ret":0,"data":"离线。","serverExecutedTime":7}
JSONObject json = JSONUtil.parseObj(UnicodeUtil.toString(resp));
msg = json.getStr("data");
} catch (Exception e) {
msg = "未知错误";
}
return msg;
}
Map<Integer, String> yxxStatusMap = Map.of(
0, "离线(设备上线后自动补打)",
1, "在线",
2, "获取失败",
3, "未激活",
4, "设备已禁用");
/**
* 保存打印记录
@@ -175,7 +65,7 @@ public class PrintMachineLogServiceImpl extends ServiceImpl<PrintMachineLogMappe
*/
@Async
@Override
public void save(PrintMachine config, String bizType, String printContent, Object respJson) {
public void save(PrintMachine config, String bizType, String printContent, String respJson) {
if (config == null) {
return;
}
@@ -184,51 +74,41 @@ public class PrintMachineLogServiceImpl extends ServiceImpl<PrintMachineLogMappe
int failFlag = 0;
String respCode = "0";
String respMsg = "打印中";
Map<Integer, String> yxxStatusMap = MapUtil.builder(0, "离线(设备上线后自动补打)").put(1, "在线").put(2, "获取失败").put(3, "未激活").put(4, "设备已禁用").build();
JSONObject resp = JSONObject.parseObject(respJson);
// 云想印
if ("云想印".equals(config.getContentType())) {
cn.hutool.json.JSONObject resp = JSONUtil.parseObj(respJson);
int code = resp.getInt("code");
cn.hutool.json.JSONObject data = resp.getJSONObject("data").getJSONObject("data");
int code = resp.getIntValue("code");
JSONObject respData = resp.getJSONObject("data");
JSONObject data = respData.getJSONObject("data");
//设备状态0: 离线, 1: 在线, 2: 获取失败, 3:未激活, 4:设备已禁用
int status = data.getInt("status");
int status = data.getIntValue("status");
if (code != 0) {
failFlag = 1;
respCode = code + "";
respMsg = resp.getStr("msg");
respMsg = resp.getString("msg");
} else if (status != 1) {
failFlag = 1;
respCode = code + "";
respMsg = status + "_" + yxxStatusMap.get(status);
}
if (code == 0) {
String taskId = resp.getJSONObject("data").getStr("orderId");
entity.setTaskId(taskId);
entity.setTaskId(respData.getString("orderId"));
}
// 飞鹅云打印机暂时没有适配先return不做打印记录
} else if ("飞鹅".equals(config.getContentType())) {
cn.hutool.json.JSONObject resp = JSONUtil.parseObj(respJson);
int ret = resp.getInt("ret");
int ret = resp.getIntValue("ret");
if (ret != 0) {
failFlag = 1;
respCode = ret + "";
respMsg = resp.getStr("msg");
respMsg = resp.getString("msg");
} else {
String printOrderId = resp.getStr("data");
entity.setTaskId(printOrderId);
entity.setTaskId(resp.getString("data"));
}
} else {
// 其他打印机暂时没有适配先return不做打印记录
return;
}
entity.setBizType(bizType);
// entity.setCreateUserId(config.getCurrentUserId());
// entity.setCreateUserName(config.getCurrentUserName());
// if (StrUtil.isNotBlank(config.getCurrentUserNickName())) {
// entity.setCreateUserName(StrUtil.concat(true, config.getCurrentUserNickName(), " | ", config.getCurrentUserName()));
// }
entity.setPrintContent(printContent);
entity.setCreateTime(DateUtil.date().toLocalDateTime());
if (failFlag == 0) {
@@ -238,64 +118,251 @@ public class PrintMachineLogServiceImpl extends ServiceImpl<PrintMachineLogMappe
entity.setRespCode(respCode);
entity.setRespMsg(respMsg);
super.save(entity);
ThreadUtil.execAsync(() -> checkPrintStatus(config, entity));
}
// 云想印
/**
* 类级别成员变量基于虚拟线程的固定大小5定时线程池
* // Java 21+ 虚拟线程工厂,支持命名
*/
private final ScheduledExecutorService virtualThreadScheduler = Executors.newScheduledThreadPool(
5,
Thread.ofVirtual().name("print-query-vt-", 0).factory()
);
/**
* 打印机状态查询(解决 retryFuture 爆红问题 + 虚拟线程 + 轮询重试)
*
* @param config 打印机配置
* @param entity 打印日志实体
*/
public void checkPrintStatus(PrintMachine config, PrintMachineLog entity) {
// 最大重试次数
int maxRetryTimes = 5;
AtomicInteger executedTimes = new AtomicInteger(0);
// 原子引用包装ScheduledFuture用于后续取消轮询
AtomicReference<ScheduledFuture<?>> retryFutureRef = new AtomicReference<>();
// 核心查询任务(修正后,逻辑内聚)
Runnable printQueryTask = () -> {
int currentTimes = executedTimes.incrementAndGet();
boolean isPrintSuccess = false;
boolean isLastTask = false;
try {
// 1. 云想印打印机状态查询
if ("云想印".equals(config.getContentType())) {
// 延迟3ms复查打印状态 (用户可以根据设备信息查询到当前设备的在线情况该接口只能提供参考设备的离线状态是在设备离线3分钟后才会生效)
ThreadUtil.safeSleep(1000 * 5);
String jsonStr = checkPrintStatus(config.getAddress(), entity.getTaskId());
cn.hutool.json.JSONObject resp = JSONUtil.parseObj(jsonStr);
int code = resp.getInt("code");
String jsonStr = yxyPrinter.checkPrintStatus(config.getAddress(), entity.getTaskId());
log.info("云想印打印状态查询结果(第{}次,虚拟线程:{}{}",
currentTimes, Thread.currentThread().getName(), jsonStr);
JSONObject resp = JSONObject.parseObject(jsonStr);
int code = resp.getIntValue("code");
if (code == 0) {
cn.hutool.json.JSONObject data = resp.getJSONObject("data");
boolean status = data.containsKey("status");
if (!status) {
return;
}
boolean success = data.getBool("status", false);
if (entity.getFailFlag() == 0 && success) {
entity.setFailFlag(0);
entity.setRespMsg("打印成功");
entity.setPrintTime(entity.getCreateTime());
} else if (entity.getFailFlag() == 1 && success) {
entity.setFailFlag(0);
entity.setPrintTime(DateUtil.date().toLocalDateTime());
entity.setRespMsg("打印成功");
// 如果设备在线 and 休眠5秒后查询结果是未打印即视为设备已离线云端3分钟后才会同步到离线信息
} else if (entity.getFailFlag() == 0 && !success) {
entity.setFailFlag(1);
entity.setPrintTime(null);
entity.setRespMsg("0_离线(设备上线后自动补打)");
} else {
entity.setFailFlag(1);
entity.setPrintTime(null);
entity.setRespMsg(StrUtil.concat(true, "打印失败,", "_", entity.getRespMsg()));
JSONObject data = resp.getJSONObject("data");
if (data.containsKey("status")) {
isPrintSuccess = data.getBooleanValue("status", false);
updatePrintLogEntity(entity, isPrintSuccess);
}
}
// 飞鹅云打印机
} else if ("飞鹅".equals(config.getContentType())) {
ThreadUtil.safeSleep(1000 * 5);
Boolean success = checkFPrintStatus(entity.getTaskId());
}
// 2. 飞鹅云打印机状态查询
else if ("飞鹅".equals(config.getContentType())) {
Boolean success = feiPrinter.checkFPrintStatus(entity.getTaskId());
if (success == null) {
entity.setFailFlag(1);
entity.setRespMsg("打印失败,未知错误");
entity.setPrintTime(null);
} else if (success) {
entity.setFailFlag(0);
entity.setPrintTime(DateUtil.date().toLocalDateTime());
entity.setRespMsg("打印成功");
isPrintSuccess = true;
updatePrintLogEntity(entity, true);
} else {
String msg = checkOnline(entity.getAddress());
String msg = feiPrinter.checkOnline(entity.getAddress());
if (msg.indexOf("在线,工作状态正常") > 0) {
entity.setFailFlag(0);
entity.setPrintTime(DateUtil.date().toLocalDateTime());
entity.setRespMsg("打印成功");
isPrintSuccess = true;
updatePrintLogEntity(entity, true);
} else {
isPrintSuccess = false;
entity.setFailFlag(1);
entity.setPrintTime(null);
entity.setRespMsg(StrUtil.concat(true, "打印失败,", "_", msg));
}
}
}else {
log.info("打印类型为其他类型,终止打印状态查询轮询任务");
ScheduledFuture<?> future = retryFutureRef.get();
if (future != null && !future.isCancelled()) {
boolean cancelSuccess = future.cancel(false); // 取消后续轮询(不中断当前任务)
log.info("其他打印类型,取消轮询任务:{}", cancelSuccess ? "成功" : "失败");
}
}
// 3. 打印成功:取消后续轮询任务
if (isPrintSuccess) {
isLastTask = true;
ScheduledFuture<?> future = retryFutureRef.get();
if (future != null && !future.isCancelled()) {
future.cancel(false); // 不中断当前任务,仅取消后续任务
}
return;
}
// 4. 达到最大重试次数:取消后续轮询任务
if (currentTimes >= maxRetryTimes) {
isLastTask = true;
ScheduledFuture<?> future = retryFutureRef.get();
if (future != null && !future.isCancelled()) {
future.cancel(false);
}
}
} catch (Exception e) {
log.error("第{}次打印机状态查询异常(虚拟线程:{}",
currentTimes, Thread.currentThread().getName(), e);
// 异常时达到最大重试次数,同样取消任务
if (currentTimes >= maxRetryTimes) {
ScheduledFuture<?> future = retryFutureRef.get();
if (future != null && !future.isCancelled()) {
boolean cancelSuccess = future.cancel(false);
log.info("查询异常且达到最大重试次数,取消轮询任务:{}", cancelSuccess ? "成功" : "失败");
}
}
} finally {
//仅当是最后一次任务时,才执行更新操作
if (isLastTask) {
super.updateById(entity);
}
}
};
// 修正统一使用scheduleAtFixedRate避免任务重复执行
// 首次延迟10秒执行后续每隔30秒执行一次符合原逻辑的首次查询延迟后续轮询间隔
ScheduledFuture<?> retryFuture = virtualThreadScheduler.scheduleAtFixedRate(
printQueryTask,
10,
30,
TimeUnit.SECONDS
);
// 修正先赋值AtomicReference再让任务可能执行避免线程安全隐患
retryFutureRef.set(retryFuture);
// 修正:关闭钩子仅注册一次(通过静态代码块或类初始化时注册,避免重复注册)
registerShutdownHookOnce();
}
/**
* 统一更新打印日志实体
*
* @param entity 打印日志实体
* @param isPrintSuccess 是否打印成功
*/
private void updatePrintLogEntity(PrintMachineLog entity, boolean isPrintSuccess) {
if (isPrintSuccess) {
entity.setFailFlag(0);
entity.setRespMsg("打印成功");
entity.setPrintTime(entity.getFailFlag() == 0 ? entity.getCreateTime() : DateUtil.date().toLocalDateTime());
} else {
entity.setFailFlag(1);
entity.setPrintTime(null);
if (entity.getFailFlag() == 0) {
entity.setRespMsg("0_离线(设备上线后自动补打)");
} else {
entity.setRespMsg(StrUtil.concat(true, "打印失败,", "_", entity.getRespMsg()));
}
}
}
// public void checkPrintStatus(PrintMachine config, PrintMachineLog entity) {
// // 云想印
// if ("云想印".equals(config.getContentType())) {
// String jsonStr = yxyPrinter.checkPrintStatus(config.getAddress(), entity.getTaskId());
// log.info("云想印打印状态查询结果:{}", jsonStr);
// JSONObject resp = JSONObject.parseObject(jsonStr);
// int code = resp.getIntValue("code");
// if (code == 0) {
// JSONObject data = resp.getJSONObject("data");
// boolean status = data.containsKey("status");
// if (!status) {
// return;
// }
// boolean success = data.getBooleanValue("status", false);
// if (entity.getFailFlag() == 0 && success) {
// entity.setFailFlag(0);
// entity.setRespMsg("打印成功");
// entity.setPrintTime(entity.getCreateTime());
// } else if (entity.getFailFlag() == 1 && success) {
// entity.setFailFlag(0);
// entity.setPrintTime(DateUtil.date().toLocalDateTime());
// entity.setRespMsg("打印成功");
// // 如果设备在线 and 休眠5秒后查询结果是未打印即视为设备已离线云端3分钟后才会同步到离线信息
// } else if (entity.getFailFlag() == 0 && !success) {
// entity.setFailFlag(1);
// entity.setPrintTime(null);
// entity.setRespMsg("0_离线(设备上线后自动补打)");
// } else {
// entity.setFailFlag(1);
// entity.setPrintTime(null);
// entity.setRespMsg(StrUtil.concat(true, "打印失败,", "_", entity.getRespMsg()));
// }
// }
// // 飞鹅云打印机
// } else if ("飞鹅".equals(config.getContentType())) {
// Boolean success = feiPrinter.checkFPrintStatus(entity.getTaskId());
// if (success == null) {
// entity.setFailFlag(1);
// entity.setRespMsg("打印失败,未知错误");
// } else if (success) {
// entity.setFailFlag(0);
// entity.setPrintTime(DateUtil.date().toLocalDateTime());
// entity.setRespMsg("打印成功");
// } else {
// String msg = feiPrinter.checkOnline(entity.getAddress());
// if (msg.indexOf("在线,工作状态正常") > 0) {
// entity.setFailFlag(0);
// entity.setPrintTime(DateUtil.date().toLocalDateTime());
// entity.setRespMsg("打印成功");
// } else {
// entity.setFailFlag(1);
// entity.setPrintTime(null);
// entity.setRespMsg(StrUtil.concat(true, "打印失败,", "_", msg));
// }
// }
// }
// super.updateById(entity);
// }
// 静态标识,确保关闭钩子仅注册一次
private static volatile boolean shutdownHookRegistered = false;
// 锁对象,保证线程安全
private static final Object HOOK_LOCK = new Object();
/**
* 统一注册JVM关闭钩子仅执行一次
*/
private void registerShutdownHookOnce() {
if (!shutdownHookRegistered) {
synchronized (HOOK_LOCK) {
// 双重校验锁,避免多线程下重复注册
if (!shutdownHookRegistered) {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
if (virtualThreadScheduler != null && !virtualThreadScheduler.isShutdown()) {
virtualThreadScheduler.shutdown();
try {
if (!virtualThreadScheduler.awaitTermination(10, TimeUnit.SECONDS)) {
log.warn("虚拟线程调度器10秒内未关闭强制关闭...");
virtualThreadScheduler.shutdownNow();
}
} catch (InterruptedException e) {
log.error("等待虚拟线程调度器终止时被中断,强制关闭", e);
virtualThreadScheduler.shutdownNow();
Thread.currentThread().interrupt(); // 保留中断状态
}
}
}, "PrinterScheduler-ShutdownHook"));
shutdownHookRegistered = true;
}
}
}
}
}