张世豪
5 小时以前 d22349714c8d199c02f336f90fba841ef8f5cd39
src/chuankou/Sendmsg.java
@@ -1,21 +1,156 @@
package chuankou;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.SwingWorker;
import chushihua.lunxun;
import dialog.Charulog;
import dialog.Dingshidialog;
import dialog.Errlog;
import publicway.OpenDoor;
import xitongshezhi.SystemDebugDialog;
/**
 * 串口消息发送工具类
 * 提供高性能的串口消息发送功能,适合高频调用
 * 优化内存使用,避免长时间运行内存泄漏
 */
public class Sendmsg {
    // 静态串口服务实例
    private static volatile SerialPortService serialService = null;
    private static volatile boolean isPortOpen = false;
    private static final AtomicBoolean isPortOpen = new AtomicBoolean(false);
    
    // 改为非final,支持动态控制
    private static boolean DEBUG_MODE = false;
    private static volatile boolean DEBUG_MODE = false;
    
    // 日期格式化
    private static final SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss.SSS");
    // 使用ThreadLocal保证SimpleDateFormat线程安全
    private static final ThreadLocal<SimpleDateFormat> TIME_FORMATTER =
        ThreadLocal.withInitial(() -> new SimpleDateFormat("HH:mm:ss.SSS"));
    // 缓存字符串构建器,减少对象创建
    private static final ThreadLocal<StringBuilder> STRING_BUILDER_CACHE =
        ThreadLocal.withInitial(() -> new StringBuilder(128));
    // 记录活跃的SwingWorker,便于管理
    private static final ConcurrentHashMap<String, SwingWorker<?, ?>> ACTIVE_WORKERS =
        new ConcurrentHashMap<>();
    /**发卡服务器控制打开某个柜门调用指令
     * @param int slotId柜门编号1-60
     * @param int type 1是服务器发卡,2是管理员发卡*/
    public static boolean opendoorzhiling(int slotId,int type) {
        lunxun.setSendChaxunzhiling(false);//暂停查询指令
        try {
            // 调用OpenDoor生成开门指令
            String command = OpenDoor.openOneDoor(slotId, type);
            boolean sendResult = Sendmsg.sendMessage(command);
            StringBuilder mesBuilder = STRING_BUILDER_CACHE.get();
            mesBuilder.setLength(0); // 清空重用
            mesBuilder.append(command).append(";type").append(type).append("控制打开").append(slotId).append("柜门");
            String mes = mesBuilder.toString();
            Charulog.logOperation(mes);
            if (lunxun.DEBUG_ENABLED) {
                SystemDebugDialog.appendAsciiData(mes);
            }
            return sendResult;
        } finally {
            // 确保恢复查询指令
            lunxun.setSendChaxunzhiling(true);
        }
    }
    /**
     * 打开全部卡槽的公用静态方法
     * @param type 操作类型:1-服务器发卡,2-管理员发卡
     */
    public static void openAllSlots(int type) {
        lunxun.setSendChaxunzhiling(false);//暂停查询指令
        String workerKey = "openAllSlots_" + System.currentTimeMillis();
        // 使用SwingWorker在后台执行,避免阻塞UI
        SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
            @Override
            protected Void doInBackground() throws Exception {
                // 遍历所有卡槽(1-60)
                for (int slotId = 1; slotId <= 60 && !isCancelled(); slotId++) {
                    try {
                        // 生成开门指令
                        String command = OpenDoor.openOneDoor(slotId, type);
                        // 发送串口指令
                        boolean sent = Sendmsg.sendMessage(command);
                        if (!sent) {
                            Errlog.logOperation("发送指令到卡槽 " + slotId + " 失败");
                        }
                        // 间隔100ms,但检查是否被取消
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        break; // 被中断时退出循环
                    } catch (Exception e) {
                        Errlog.logOperation("处理卡槽 " + slotId + " 时发生错误: " + e.getMessage());
                        // 继续处理下一个卡槽,不中断循环
                    }
                }
                return null;
            }
            @Override
            protected void done() {
                try {
                    // 清理worker引用
                    ACTIVE_WORKERS.remove(workerKey);
                    // 可选:完成后可以添加回调处理
                    if (!isCancelled()) {
                        StringBuilder messageBuilder = STRING_BUILDER_CACHE.get();
                        messageBuilder.setLength(0);
                        String types = "管理员";
                        if(type == 1) {
                            types = "服务器指令";
                        }
                        messageBuilder.append(types).append("已将全部卡槽已经打开请取卡");
                        String message = messageBuilder.toString();
                        Dingshidialog.showTimedDialog(null, 5, message);
                        Charulog.logOperation(message);
                    }
                } finally {
                    // 确保恢复查询指令
                    lunxun.setSendChaxunzhiling(true);
                }
            }
        };
        // 记录worker便于管理
        ACTIVE_WORKERS.put(workerKey, worker);
        worker.execute();
    }
    /**
     * 取消所有正在执行的任务
     */
    public static void cancelAllTasks() {
        ACTIVE_WORKERS.forEach((key, worker) -> {
            if (!worker.isDone()) {
                worker.cancel(true);
            }
        });
        ACTIVE_WORKERS.clear();
    }
    
    /**
     * 设置串口服务实例
@@ -24,7 +159,7 @@
     */
    public static void setSerialService(SerialPortService service, boolean open) {
        serialService = service;
        isPortOpen = open;
        isPortOpen.set(open);
    }
    
    /**
@@ -38,13 +173,13 @@
     * 发送消息到串口(带重试机制)
     */
    public static boolean sendMessage(String message) {
        if (!isPortOpen || serialService == null) {
            System.err.println("[" + getCurrentTime() + "] 串口未打开,无法发送数据");
        if (!isPortOpen.get() || serialService == null) {
            Errlog.logOperation("[" + getCurrentTime() + "] 串口未打开,无法发送数据");
            return false;
        }
        
        if (message == null || message.trim().isEmpty()) {
            System.err.println("[" + getCurrentTime() + "] 发送数据为空");
            Errlog.logOperation("[" + getCurrentTime() + "] 发送数据为空");
            return false;
        }
        
@@ -56,7 +191,7 @@
            try {
                byte[] data = hexStringToByteArray(text);
                if (data == null) {
                    System.err.println("[" + getCurrentTime() + "] HEX转换失败,数据: " + text);
                    Errlog.logOperation("[" + getCurrentTime() + "] HEX转换失败,数据: " + text);
                    return false;
                }
                
@@ -70,7 +205,7 @@
                } else {
                    retryCount++;
                    if (retryCount <= MAX_RETRY) {
                        System.err.println("[" + getCurrentTime() + "] 发送失败,正在重试 (" + retryCount + "/" + MAX_RETRY + ")");
                        Errlog.logOperation("[" + getCurrentTime() + "] 发送失败,正在重试 (" + retryCount + "/" + MAX_RETRY + ")");
                        try {
                            Thread.sleep(50); // 重试前等待
                        } catch (InterruptedException e) {
@@ -78,17 +213,21 @@
                            break;
                        }
                    } else {
                        System.err.println("[" + getCurrentTime() + "] 串口发送失败,指令: " + text.toUpperCase());
                        System.err.println("[" + getCurrentTime() + "] 串口状态 - 打开: " + isPortOpen + ", 服务: " + (serialService != null));
                        if (serialService != null) {
                            System.err.println("[" + getCurrentTime() + "] 串口服务状态 - 是否打开: " + serialService.isOpen());
                        if (DEBUG_MODE) {
                            Errlog.logOperation("[" + getCurrentTime() + "] 串口发送失败,指令: " + text.toUpperCase());
                            Errlog.logOperation("[" + getCurrentTime() + "] 串口状态 - 打开: " + isPortOpen.get() + ", 服务: " + (serialService != null));
                            if (serialService != null) {
                                Errlog.logOperation("[" + getCurrentTime() + "] 串口服务状态 - 是否打开: " + serialService.isOpen());
                            }
                        }
                        return false;
                    }
                }
            } catch (Exception e) {
                System.err.println("[" + getCurrentTime() + "] 发送异常,指令: " + text.toUpperCase());
                e.printStackTrace();
                Errlog.logOperation("[" + getCurrentTime() + "] 发送异常,指令: " + text.toUpperCase());
                if (DEBUG_MODE) {
                    e.printStackTrace();
                }
                return false;
            }
        }
@@ -101,9 +240,9 @@
     * @return 串口打开状态
     */
    public static boolean isPortOpen() {
        boolean open = isPortOpen && serialService != null;
        boolean open = isPortOpen.get() && serialService != null;
        if (!open && DEBUG_MODE) {
            System.err.println("[" + getCurrentTime() + "] 串口状态检查: 未打开");
            Errlog.logOperation("[" + getCurrentTime() + "] 串口状态检查: 未打开");
        }
        return open;
    }
@@ -148,7 +287,8 @@
            return "";
        }
        
        StringBuilder sb = new StringBuilder();
        StringBuilder sb = STRING_BUILDER_CACHE.get();
        sb.setLength(0);
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
@@ -160,7 +300,7 @@
     * @return 时间字符串
     */
    private static String getCurrentTime() {
        return timeFormat.format(new Date());
        return TIME_FORMATTER.get().format(new Date());
    }
    
    /**
@@ -186,4 +326,26 @@
        DEBUG_MODE = debug;
        System.out.println("[" + getCurrentTime() + "] Sendmsg调试模式: " + (debug ? "启用" : "禁用"));
    }
    /**
     * 清理资源,防止内存泄漏
     */
    public static void cleanup() {
        cancelAllTasks();
        // 清理ThreadLocal资源
        TIME_FORMATTER.remove();
        STRING_BUILDER_CACHE.remove();
        if (DEBUG_MODE) {
            System.out.println("[" + getCurrentTime() + "] Sendmsg资源清理完成");
        }
    }
    /**
     * 获取活跃任务数量
     */
    public static int getActiveTaskCount() {
        return ACTIVE_WORKERS.size();
    }
}