chen.llin
昨天 6b53373bf1cc50b18b0a5d17d8e7e25118068640
rfid调试正常代码
10个文件已添加
6个文件已修改
2947 ■■■■■ 已修改文件
pom.xml 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/rfid/uhf288/Device.java 266 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/rfid/uhf288/RFIDTemplate.java 505 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/controller/RFIDController.java 270 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/ServerBootstrap.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/cache/OutputQueue.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/enums/SlaveType.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/model/RFIDSlave.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/thread/RFIDThread.java 322 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/rfid/RFIDTemplate.java 506 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/service/RFIDAutoConnectService.java 557 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/service/RFIDService.java 393 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-dev.yml 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-prod.yml 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/lib/UHFReader288.dll 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/lib/com_rfid_uhf288_Device.dll 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -195,6 +195,24 @@
    <build>
        <finalName>wcs</finalName>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <excludes>
                    <exclude>**/com_rfid_uhf288_Device.dll</exclude>
                    <exclude>**/UHFReader288.dll</exclude>
                </excludes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>false</filtering>
                <includes>
                    <include>**/com_rfid_uhf288_Device.dll</include>
                    <include>**/UHFReader288.dll</include>
                </includes>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
src/main/java/com/rfid/uhf288/Device.java
New file
@@ -0,0 +1,266 @@
package com.rfid.uhf288;
import java.io.File;
/**
 * RFID UHF288设备JNI接口
 * 对应DLL: com_rfid_uhf288_Device.dll
 *
 * 参考demo项目的加载方式:在static代码块中加载DLL
 * 注意:DLL可能不支持多线程并发访问,需要同步保护
 */
public class Device {
    // DLL加载状态标志
    private static volatile boolean libraryLoaded = false;
    // DLL加载锁,确保只加载一次
    private static final Object loadLock = new Object();
    /**
     * 静态代码块:加载DLL库
     * 参考demo项目的方式,优先使用绝对路径加载,如果失败则尝试从系统PATH加载
     */
    static {
        loadLibrary();
    }
    /**
     * 加载DLL库
     * 优先使用绝对路径直接加载,如果失败则尝试从系统PATH加载(参考demo项目的方式)
     * 使用同步锁确保线程安全,避免多线程同时加载导致冲突
     */
    private static void loadLibrary() {
        // 如果已经加载,直接返回
        if (libraryLoaded) {
            return;
        }
        // 同步加载,确保只加载一次
        synchronized (loadLock) {
            // 双重检查,避免重复加载
            if (libraryLoaded) {
                return;
            }
            String mainDllName = "com_rfid_uhf288_Device.dll";
            String depDllName = "UHFReader288.dll"; // 依赖的DLL
            // 方法1: 使用绝对路径直接加载DLL
            try {
            // 使用真实路径加载DLL
            String projectBaseDir = "D:\\work\\work-zy\\zy-wcs";
            String mainDllPath = projectBaseDir + "\\src\\main\\resources\\lib\\" + mainDllName;
            String depDllPath = projectBaseDir + "\\src\\main\\resources\\lib\\" + depDllName;
            File mainDllFile = new File(mainDllPath);
            File depDllFile = new File(depDllPath);
            if (mainDllFile.exists() && mainDllFile.canRead()) {
                // 先尝试加载依赖DLL(如果存在)
                if (depDllFile.exists() && depDllFile.canRead()) {
                    try {
                        System.load(depDllPath);
                        System.out.println("成功加载依赖DLL: " + depDllName + " (路径: " + depDllPath + ")");
                    } catch (UnsatisfiedLinkError e) {
                        // 依赖DLL可能已经加载过,或者加载失败
                        // 如果错误信息不是"已加载",则打印警告
                        if (e.getMessage() == null || !e.getMessage().contains("already loaded")) {
                            System.err.println("警告: 依赖DLL加载失败(继续尝试加载主DLL): " + depDllName);
                            System.err.println("错误信息: " + e.getMessage());
                        }
                    }
                }
                // 加载主DLL
                System.load(mainDllPath);
                System.out.println("成功从绝对路径加载DLL: " + mainDllName + " (路径: " + mainDllPath + ")");
                System.out.println("DLL文件大小: " + mainDllFile.length() + " 字节");
                libraryLoaded = true;
                return;
            } else {
                System.err.println("DLL文件不存在或不可读: " + mainDllPath);
            }
        } catch (UnsatisfiedLinkError e) {
            // 如果是依赖库错误,提供更详细的错误信息
            if (e.getMessage() != null && e.getMessage().contains("dependent libraries")) {
                System.err.println("DLL依赖库加载失败: " + e.getMessage());
                System.err.println("请确保所有依赖DLL文件都在同一目录中");
            }
            System.err.println("从绝对路径加载DLL失败: " + e.getMessage());
            e.printStackTrace();
        } catch (Exception e) {
            System.err.println("从绝对路径加载DLL失败: " + e.getMessage());
            e.printStackTrace();
        }
        /* 方法2(已注释): 尝试从resources目录提取到临时目录加载
        try {
            // 创建专门的临时目录来存放所有DLL(只创建一次)
            if (tempLibDir == null) {
                tempLibDir = createTempLibDirectory();
            }
            if (tempLibDir != null && tempLibDir.exists()) {
                // 先提取所有DLL到同一目录
                File depDll = extractDllToDir("/lib/" + depDllName, depDllName, tempLibDir);
                File mainDll = extractDllToDir("/lib/" + mainDllName, mainDllName, tempLibDir);
                if (mainDll != null && mainDll.exists()) {
                    // 先尝试加载依赖DLL(如果存在)
                    if (depDll != null && depDll.exists()) {
                        try {
                            System.load(depDll.getAbsolutePath());
                            System.out.println("成功加载依赖DLL: " + depDllName + " (路径: " + depDll.getAbsolutePath() + ")");
                        } catch (UnsatisfiedLinkError e) {
                            if (e.getMessage() == null || !e.getMessage().contains("already loaded")) {
                                System.err.println("警告: 依赖DLL加载失败(继续尝试加载主DLL): " + depDllName);
                                System.err.println("错误信息: " + e.getMessage());
                            }
                        }
                    }
                    System.load(mainDll.getAbsolutePath());
                    System.out.println("成功从resources目录加载DLL: " + mainDllName + " (路径: " + mainDll.getAbsolutePath() + ")");
                    return;
                }
            }
        } catch (Exception e) {
            System.err.println("从resources目录加载DLL失败: " + e.getMessage());
            e.printStackTrace();
        }
        */
            // 方法3: 尝试从系统PATH或java.library.path加载(参考demo项目的方式)
            try {
                System.loadLibrary("com_rfid_uhf288_Device");
                System.out.println("成功从系统PATH加载DLL: " + mainDllName);
                System.out.println("注意:如果后续native方法调用失败,请检查DLL版本是否匹配");
                libraryLoaded = true;
                return;
            } catch (UnsatisfiedLinkError e) {
                System.err.println("无法从系统PATH加载RFID设备DLL库: " + mainDllName);
                System.err.println("错误信息: " + e.getMessage());
                System.err.println("请确保DLL文件在系统PATH或项目lib目录中");
                e.printStackTrace();
            }
            // 如果所有方法都失败,记录错误
            if (!libraryLoaded) {
                System.err.println("========================================");
                System.err.println("RFID设备DLL加载失败!");
                System.err.println("请检查:");
                System.err.println("1. DLL文件是否存在: D:\\work\\work-zy\\zy-wcs\\src\\main\\resources\\lib\\com_rfid_uhf288_Device.dll");
                System.err.println("2. DLL文件是否完整");
                System.err.println("3. DLL文件是否在系统PATH中");
                System.err.println("4. 从demo项目中复制正确的DLL文件");
                System.err.println("========================================");
            }
        }
    }
    /**
     * @param args
     */
    public native int OpenComPort(int port,byte[]comAddr,byte baud,int[]PortHandle);
    public native int CloseSpecComPort(int PortHandle);
    public native int OpenNetPort(int Port,String IPaddr,byte[]comAddr,int[] PortHandle);
    public native int CloseNetPort(int PortHandle);
    public native int GetReaderInformation(byte[]comAddr,byte[]versionInfo,byte[]readerType,byte[]trType,byte[]dmaxfre,
                                           byte[]dminfre,byte[]powerdBm,byte[]InventoryScanTime,byte[]Ant,byte[]BeepEn,
                                           byte[]OutputRep,byte[]CheckAnt,int PortHandle);
    public native int Inventory_G2(byte[]comAddr,byte QValue,byte Session,byte MaskMem,byte[]MaskAdr,byte MaskLen,
                                   byte[]MaskData,byte MaskFlag,byte AdrTID,byte LenTID,byte TIDFlag,byte Target,
                                   byte InAnt,byte Scantime,byte FastFlag,byte[]pEPCList,byte[] Ant,int[]Totallen,
                                   int[]CardNum,int PortHandle);
    public native int InventoryMix_G2(byte[]comAddr,byte QValue,byte Session,byte MaskMem,byte[]MaskAdr,byte MaskLen,
                                      byte[]MaskData,byte MaskFlag,byte ReadMem,byte[]ReadAdr,byte ReadLen,byte[]Psd,
                                      byte Target,byte InAnt,byte Scantime,byte FastFlag,byte[]pEPCList,byte[] Ant,
                                      int[]Totallen,int[]CardNum,int PortHandle);
    public native int ReadData_G2(byte[]comAddr,byte[] EPC,byte ENum,byte Mem,byte WordPtr,byte Num,byte[]Password,
                                  byte MaskMem,byte[]MaskAdr,byte MaskLen,byte[]MaskData,byte[]Data,int[]Errorcode,
                                  int PortHandle);
    public native int WriteData_G2(byte[]comAddr,byte[] EPC,byte WNum,byte ENum,byte Mem,byte WordPtr,byte[] Wdt,
                                   byte[]Password,byte MaskMem,byte[]MaskAdr,byte MaskLen,byte[]MaskData,int[]Errorcode,
                                   int PortHandle);
    public native int WriteEPC_G2(byte[]comAddr,byte[] Password,byte[] EPC,byte ENum,int[]Errorcode,int PortHandle);
    public native int KillTag_G2(byte[]comAddr,byte[] EPC,byte ENum,byte[] Killpwd,byte MaskMem,byte[]MaskAdr,byte MaskLen,
                                 byte[]MaskData,int[]Errorcode,int PortHandle);
    public native int Lock_G2(byte[]comAddr,byte[] EPC,byte ENum,byte selectid,byte setprotect,byte[] Password,byte MaskMem,
                              byte[]MaskAdr,byte MaskLen, byte[]MaskData,int[]Errorcode,int PortHandle);
    public native int BlockErase_G2(byte[]comAddr,byte[] EPC,byte ENum,byte Mem,byte WordPtr,byte Num,byte[] Password,
                                    byte MaskMem,byte[]MaskAdr,byte MaskLen, byte[]MaskData,int[]Errorcode,int PortHandle);
    public native int SetRegion(byte[]comAddr, byte dmaxfre,byte dminfre,int PortHandle);
    public native int SetAddress(byte[]comAddr, byte ComAdrData,int PortHandle);
    public native int SetInventoryScanTime(byte[]comAddr, byte ScanTime,int PortHandle);
    public native int SetBaudRate(byte[]comAddr, byte baud,int PortHandle);
    public native int SetRfPower(byte[]comAddr, byte PowerDbm,int PortHandle);
    public native int SetWorkMode(byte[]comAddr, byte Read_mode,int PortHandle);
    public native int GetSystemParameter(byte[]comAddr,byte[]Read_mode,byte[]Accuracy,byte[]RepCondition,byte[]RepPauseTime,
                                         byte[]ReadPauseTim,byte[]TagProtocol,byte[]MaskMem,byte[]MaskAdr,byte[]MaskLen,
                                         byte[]MaskData, byte[]TriggerTime,byte[]AdrTID,byte[]LenTID,int PortHandle);
    public native int SetAntennaMultiplexing(byte[]comAddr, byte Ant,int PortHandle);
    public native int SetAntenna(byte[]comAddr, byte SetOnce,byte AntCfg1,byte AntCfg2,int PortHandle);
    public native int WriteRfPower(byte[]comAddr, byte PowerDbm,int PortHandle);
    public native int ReadRfPower(byte[]comAddr, byte[] PowerDbm,int PortHandle);
    public native int RetryTimes(byte[]comAddr, byte[] Times,int PortHandle);
    public native int SetReadMode(byte[]comAddr, byte ReadMode,int PortHandle);
    public native int SetCheckAnt(byte[]comAddr, byte CheckAnt,int PortHandle);
    public native int GetSeriaNo(byte[]comAddr, byte[] SeriaNo,int PortHandle);
    public native int SetBeepNotification(byte[]comAddr, byte BeepEn,int PortHandle);
    public native int SetReal_timeClock(byte[]comAddr, byte[] paramer,int PortHandle);
    public native int GetTime(byte[]comAddr, byte[] paramer,int PortHandle);
    public native int SetDRM(byte[]comAddr, byte DRM,int PortHandle);
    public native int GetDRM(byte[]comAddr, byte[] DRM,int PortHandle);
    public native int GetReaderTemperature(byte[]comAddr, byte[] PlusMinus,byte[]Temperature,int PortHandle);
    public native int MeasureReturnLoss(byte[]comAddr, byte[] TestFreq,byte Ant,byte[]ReturnLoss,int PortHandle);
    public native int SetGPIO(byte[] comAddr, byte OutputPin, int PortHandle);
    public native int GetGPIOStatus(byte[] ComAdr, byte[] OutputPin, int PortHandle);
    public native int ReadActiveModeData(byte[] ScanModeData, int[] ValidDatalength, int PortHandle);
    public native int SetRelay(byte[] comAddr, byte RelayTime, int PortHandle);
    public native int SwitchProtocol(byte[] comAddr, byte[] protocol, int PortHandle);
    public native int Inventory_JB(byte[]comAddr,byte Algo,byte MaskMem,byte[]MaskAdr,byte MaskLen,
                                   byte[]MaskData,byte MaskFlag, byte InAnt,byte Scantime,byte FastFlag,byte[]pEPCList,byte[] Ant,int[]Totallen,
                                   int[]CardNum,int PortHandle);
    public native int InventoryMix_JB(byte[]comAddr,byte Algo,byte MaskMem,byte[]MaskAdr,byte MaskLen,
                                      byte[]MaskData,byte MaskFlag,byte ReadMem,byte[]ReadAdr,byte ReadLen,byte[]Psd,
                                      byte InAnt,byte Scantime,byte FastFlag,byte[]pEPCList,byte[] Ant,
                                      int[]Totallen,int[]CardNum,int PortHandle);
    public native int ReadData_JB(byte[]comAddr,byte[] TagID,byte TNum,byte Mem,int WordPtr,byte WordNum,byte[]Password,
                                  byte MaskMem,byte[]MaskAdr,byte MaskLen,byte[]MaskData,byte[]Data,int[]Errorcode,
                                  int PortHandle);
    public native int WriteData_JB(byte[]comAddr,byte[] TagID,byte WNum,byte TNum,byte Mem,int WordPtr,byte[] Wdt,
                                   byte[]Password,byte MaskMem,byte[]MaskAdr,byte MaskLen,byte[]MaskData,int[]Errorcode,
                                   int PortHandle);
    public native int KillTag_JB(byte[]comAddr,byte[] TagID,byte TNum,byte[] Killpwd,byte MaskMem,byte[]MaskAdr,byte MaskLen,
                                 byte[]MaskData,int[]Errorcode,int PortHandle);
    public native int Lock_JB(byte[]comAddr,byte[] EPC,byte TNum,byte LockMem,byte Cfg,byte Action,byte[] Password,byte MaskMem,
                              byte[]MaskAdr,byte MaskLen, byte[]MaskData,int[]Errorcode,int PortHandle);
    public native int BlockErase_JB(byte[]comAddr,byte[] EPC,byte TNum,byte Mem,int WordPtr,int Num,byte[] Password,
                                    byte MaskMem,byte[]MaskAdr,byte MaskLen, byte[]MaskData,int[]Errorcode,int PortHandle);
    public native int SetCfgParameter(byte[] comAddr, byte opt, byte cfgNum, byte[]data,int len, int FrmHandle);
    public native int GetCfgParameter (byte[] comAddr, byte cfgNum,byte[] data, int[] len, int FrmHandle);
    public native int SetProfile(byte[] comAddr, byte[] Profile, int FrmHandle);
    public native int SetExtProfile(byte[] comAddr,byte Opt, int[] Profile, int FrmHandle);
    public native int GetEx10Version(byte[] comAddr,byte[] Version, byte[] ex10Tpye, int FrmHandle);
    public static void main(String[] args) {
        // TODO Auto-generated method stub
    }
}
src/main/java/com/rfid/uhf288/RFIDTemplate.java
New file
@@ -0,0 +1,505 @@
package com.rfid.uhf288;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
/**
 * RFID设备操作模板 - 模块化设计
 * 参考demo项目,但只包含基本读取功能(类似参考项目zy-wcs-czbrwcs中的功能)
 * Created by chen.lin on 2026/01/10
 *
 * 功能模块:
 * 1. 连接模块 - 串口连接 / 网络连接(独立)
 * 2. 读取模块 - 盘点标签(独立)
 *
 * 使用方式:
 * 1. 创建实例
 * 2. 选择连接方式(串口或网络)
 * 3. 连接成功后,调用读取功能
 * 4. 使用完毕后关闭连接
 */
@Slf4j
public class RFIDTemplate {
    // ==================== 基础组件 ====================
    private Device reader;
    private int portHandle = -1;
    private byte[] comAddr = new byte[1];
    // 连接状态
    private boolean isConnected = false;
    private String connectionType = ""; // "COM" 或 "NET"
    // ==================== 初始化 ====================
    /**
     * 构造函数 - 加载DLL库
     */
    public RFIDTemplate() {
        try {
            reader = new Device();
            comAddr[0] = (byte)255; // 默认地址
            log.info("RFID模板初始化成功");
        } catch (Exception e) {
            log.error("RFID模板初始化失败", e);
        }
    }
    // ==================== 模块1: 连接模块 ====================
    /**
     * 【串口连接】打开串口连接
     *
     * @param port 串口号 (1=COM1, 2=COM2, 3=COM3...)
     * @param baud 波特率 (0=9600, 1=19200, 2=38400, 3=57600, 4=115200, 5=230400, 6=460800, 7=921600)
     * @return true=成功, false=失败
     */
    public boolean connectComPort(int port, byte baud) {
        if (isConnected) {
            log.warn("已存在连接,请先关闭当前连接");
            return false;
        }
        try {
            int[] portHandleArray = new int[1];
            int result = reader.OpenComPort(port, comAddr, baud, portHandleArray);
            if (result == 0) {
                portHandle = portHandleArray[0];
                isConnected = true;
                connectionType = "COM";
                log.info("========== 串口连接成功 ==========");
                log.info("串口号: COM{}", port);
                log.info("端口句柄: {}", portHandle);
            try {
                int checkAntResult = reader.SetCheckAnt(comAddr, (byte)0x01, portHandle);
                if (checkAntResult == 0) {
//                    log.info("天线检测开启成功");
                }
                int antResult = reader.SetAntennaMultiplexing(comAddr, (byte)0x0F, portHandle);
                if (antResult == 0) {
                    log.info("天线多路复用配置成功 - 启用天线1,2,3,4 (0x0F)");
                } else {
                    int antennaResult = reader.SetAntenna(comAddr, (byte)0, (byte)0x0F, (byte)0, portHandle);
                    if (antennaResult == 0) {
                        log.info("天线配置成功 - 启用天线1,2,3,4 (0x0F)");
                    }
                }
            } catch (Exception e) {
                log.warn("配置天线异常: {}", e.getMessage());
            }
                return true;
            } else {
                log.error("串口连接失败,错误码: 0x{} ({})", String.format("%02X", result & 0xFF), getErrorCodeMessage(result));
                return false;
            }
        } catch (UnsatisfiedLinkError e) {
            log.error("RFID设备DLL方法链接失败 - OpenComPort", e);
            log.error("错误信息: {}", e.getMessage());
            log.error("可能原因:1. DLL版本不匹配 2. 方法签名不匹配 3. DLL未正确加载");
            throw e; // 重新抛出异常,让调用者处理
        }
    }
    /**
     * 【串口连接】自动尝试多个波特率连接(推荐)
     *
     * @param port 串口号 (1=COM1, 2=COM2, 3=COM3...)
     * @param preferredBaud 首选波特率 (0-7),-1表示使用默认顺序
     * @return true=成功, false=失败
     */
    public boolean connectComPortAuto(int port, int preferredBaud) {
        if (isConnected) {
            log.warn("已存在连接,请先关闭当前连接");
            return false;
        }
        // 波特率映射
        byte[] baudRates = {(byte)0, (byte)1, (byte)2, (byte)3, (byte)4, (byte)5, (byte)6, (byte)7};
        String[] baudNames = {"9600", "19200", "38400", "57600", "115200", "230400", "460800", "921600"};
        // 默认尝试顺序:57600优先
        byte[] tryBauds = {(byte)3, (byte)4, (byte)2, (byte)1, (byte)0, (byte)5, (byte)6, (byte)7};
        // 如果指定了首选波特率,将其放在最前面
        if (preferredBaud >= 0 && preferredBaud <= 7) {
            byte[] newTryBauds = new byte[tryBauds.length];
            newTryBauds[0] = (byte)preferredBaud;
            int idx = 1;
            for (byte b : tryBauds) {
                if (b != preferredBaud) {
                    newTryBauds[idx++] = b;
                }
            }
            tryBauds = newTryBauds;
        }
        log.info("========== 串口连接 ==========");
        log.info("串口号: COM{}", port);
        log.info("正在尝试连接...");
        for (int i = 0; i < tryBauds.length; i++) {
            byte baud = tryBauds[i];
            String baudName = "";
            for (int j = 0; j < baudRates.length; j++) {
                if (baudRates[j] == baud) {
                    baudName = baudNames[j];
                    break;
                }
            }
            log.info("尝试波特率: {}bps ... ", baudName);
            int[] portHandleArray = new int[1];
            int result = reader.OpenComPort(port, comAddr, baud, portHandleArray);
            if (result == 0) {
                portHandle = portHandleArray[0];
                isConnected = true;
                connectionType = "COM";
                log.info("✓ 成功!");
                log.info("连接成功!波特率: {}bps", baudName);
                log.info("端口句柄: {}", portHandle);
                return true;
            } else {
                log.warn("✗ 失败");
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        log.error("所有波特率尝试均失败!");
        return false;
    }
    /**
     * 【网络连接】打开网络连接
     *
     * @param ipAddr IP地址 (如: 192.168.1.190)
     * @param port 端口号 (默认6000)
     * @return true=成功, false=失败
     */
    public boolean connectNetwork(String ipAddr, int port) {
        if (isConnected) {
            log.warn("已存在连接,请先关闭当前连接");
            return false;
        }
        try {
            int[] portHandleArray = new int[1];
            int result = reader.OpenNetPort(port, ipAddr, comAddr, portHandleArray);
        if (result == 0) {
            portHandle = portHandleArray[0];
            isConnected = true;
            connectionType = "NET";
            log.info("========== 网络连接成功 ==========");
            log.info("IP地址: {}", ipAddr);
            log.info("端口号: {}", port);
            log.info("端口句柄: {}", portHandle);
            try {
                int checkAntResult = reader.SetCheckAnt(comAddr, (byte)0x01, portHandle);
                if (checkAntResult == 0) {
//                    log.info("天线检测开启成功");
                }
                int antResult = reader.SetAntennaMultiplexing(comAddr, (byte)0x0F, portHandle);
                if (antResult == 0) {
                    log.info("天线多路复用配置成功 - 启用天线1,2,3,4 (0x0F)");
                } else {
                    int antennaResult = reader.SetAntenna(comAddr, (byte)0, (byte)0x0F, (byte)0, portHandle);
                    if (antennaResult == 0) {
                        log.info("天线配置成功 - 启用天线1,2,3,4 (0x0F)");
                    }
                }
            } catch (Exception e) {
                log.warn("配置天线异常: {}", e.getMessage());
            }
            return true;
        } else {
            log.error("网络连接失败,错误码: 0x{} ({})", String.format("%02X", result & 0xFF), getErrorCodeMessage(result));
            log.error("请检查IP地址和端口是否正确");
            return false;
        }
        } catch (UnsatisfiedLinkError e) {
            log.error("RFID设备DLL方法链接失败 - OpenNetPort", e);
            log.error("错误信息: {}", e.getMessage());
            log.error("可能原因:1. DLL版本不匹配 2. 方法签名不匹配 3. DLL未正确加载");
            throw e; // 重新抛出异常,让调用者处理
        }
    }
    /**
     * 【网络连接】使用默认端口6000连接
     *
     * @param ipAddr IP地址 (如: 192.168.1.190)
     * @return true=成功, false=失败
     */
    public boolean connectNetwork(String ipAddr) {
        return connectNetwork(ipAddr, 6000);
    }
    /**
     * 【连接管理】关闭连接
     */
    public void disconnect() {
        if (!isConnected) {
            log.warn("当前没有连接");
            return;
        }
        if ("COM".equals(connectionType)) {
            int result = reader.CloseSpecComPort(portHandle);
            if (result == 0) {
                log.info("串口连接已关闭");
            }
        } else if ("NET".equals(connectionType)) {
            int result = reader.CloseNetPort(portHandle);
            if (result == 0) {
                log.info("网络连接已关闭");
            }
        }
        portHandle = -1;
        isConnected = false;
        connectionType = "";
    }
    /**
     * 【连接管理】检查连接状态
     *
     * @return true=已连接, false=未连接
     */
    public boolean isConnected() {
        return isConnected && portHandle >= 0;
    }
    /**
     * 【天线配置】重新配置天线(动态切换天线时使用)
     * 当物理天线插拔后,调用此方法重新配置天线,确保所有插上的天线都能被检测到
     *
     * @return true=成功, false=失败
     */
    public boolean reconfigureAntenna() {
        if (!isConnected()) {
            log.warn("设备未连接,无法配置天线");
            return false;
        }
        boolean configured = false;
        try {
            int checkAntResult = reader.SetCheckAnt(comAddr, (byte)0x01, portHandle);
            if (checkAntResult == 0) {
//                log.info("天线检测开启成功");
                configured = true;
            }
            int antResult = reader.SetAntennaMultiplexing(comAddr, (byte)0x0F, portHandle);
            if (antResult == 0) {
                log.info("天线多路复用配置成功 - 启用天线1,2,3,4 (0x0F)");
                configured = true;
            } else {
                int antennaResult = reader.SetAntenna(comAddr, (byte)0, (byte)0x0F, (byte)0, portHandle);
                if (antennaResult == 0) {
                    log.info("天线配置成功 - 启用天线1,2,3,4 (0x0F)");
                    configured = true;
                }
            }
            return configured;
        } catch (Exception e) {
            log.error("重新配置天线异常: {}", e.getMessage(), e);
            return false;
        }
    }
    /**
     * 【连接管理】获取连接类型
     *
     * @return "COM"=串口, "NET"=网络, ""=未连接
     */
    public String getConnectionType() {
        return connectionType;
    }
    // ==================== 模块2: 读取模块 ====================
    public List<TagInfo> readTags(int qValue, int session, int scanTime) {
        List<TagInfo> tagList = new ArrayList<>();
        if (!isConnected()) {
            return tagList;
        }
        byte maskMem = 2;
        byte[] maskAdr = new byte[2];
        byte maskLen = 0;
        byte[] maskData = new byte[256];
        byte maskFlag = 0;
        byte adrTID = 0;
        byte lenTID = 6;
        byte tidFlag = 0;
        byte target = 0;
        byte fastFlag = 0;
        byte[] pEPCList = new byte[20000];
        byte[] ant = new byte[1];
        int[] totallen = new int[1];
        int[] cardNum = new int[1];
        byte[] antennaValues = {(byte)0x80, (byte)0x81, (byte)0x82, (byte)0x83};
        int[] antennaNumbers = {1, 2, 3, 4};
        for (int antIdx = 0; antIdx < antennaValues.length; antIdx++) {
            byte inAnt = antennaValues[antIdx];
            int expectedAntenna = antennaNumbers[antIdx];
            java.util.Arrays.fill(pEPCList, (byte)0);
            totallen[0] = 0;
            cardNum[0] = 0;
            int result = reader.Inventory_G2(comAddr, (byte)qValue, (byte)session, maskMem, maskAdr, maskLen,
                    maskData, maskFlag, adrTID, lenTID, tidFlag, target, inAnt, (byte)scanTime,
                    fastFlag, pEPCList, ant, totallen, cardNum, portHandle);
            if (cardNum[0] > 0 && totallen[0] > 0) {
                int m = 0;
                for (int index = 0; index < cardNum[0]; index++) {
                    if (m >= totallen[0] || m >= pEPCList.length) break;
                    int epcLen = pEPCList[m++] & 0xFF;
                    if (epcLen <= 0 || epcLen > 32) break;
                    if (m + epcLen > totallen[0] || m + epcLen > pEPCList.length) break;
                    byte[] epcBytes = new byte[epcLen];
                    for (int n = 0; n < epcLen; n++) {
                        epcBytes[n] = pEPCList[m++];
                    }
                    if (m >= totallen[0] || m >= pEPCList.length) break;
                    int rssi = pEPCList[m++] & 0xFF;
                    if (rssi > 127) rssi = rssi - 256;
                    int antennaValue = 0;
                    if (m < totallen[0] && m < pEPCList.length) {
                        antennaValue = pEPCList[m++] & 0xFF;
                    } else {
                        antennaValue = ant[0] & 0xFF;
                    }
                    TagInfo tag = new TagInfo();
                    tag.epc = bytesToHex(epcBytes);
                    tag.rssi = rssi;
                    if (antennaValue >= 0x80 && antennaValue <= 0x83) {
                        tag.antenna = antennaValue - 0x80 + 1;
                    } else if (antennaValue >= 1 && antennaValue <= 4) {
                        tag.antenna = antennaValue;
                    } else {
                        tag.antenna = expectedAntenna;
                    }
                    tag.timestamp = System.currentTimeMillis();
                    tagList.add(tag);
                }
            } else {
                if (result != 0) {
                    int errorCode = result & 0xFF;
                    if (errorCode == 0xFB) {
                        continue;
                    }
                    if (errorCode == 0x01) {
                        continue;
                    }
                    if (errorCode == 0xF8) {
//                        log.warn("天线{}盘点失败,错误码: 0x{} ({})", expectedAntenna, String.format("%02X", errorCode), getErrorCodeMessage(result));
                    } else {
//                        log.debug("天线{}盘点失败,错误码: 0x{} ({})", expectedAntenna, String.format("%02X", errorCode), getErrorCodeMessage(result));
                    }
                }
            }
        }
        return tagList;
    }
    public List<TagInfo> readTags() {
        return readTags(4, 0, 10);
    }
    // ==================== 工具方法 ====================
    private String bytesToHex(byte[] bytes) {
        if (bytes == null) return "";
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X", b & 0xFF));
        }
        return sb.toString();
    }
    private String getErrorCodeMessage(int errorCode) {
        switch (errorCode & 0xFF) {
            case 0x00: return "无错误,API调用成功";
            case 0x01: return "询查时间结束前返回";
            case 0x02: return "指定的询查时间溢出";
            case 0x03: return "存储器超限或不被支持的PC值";
            case 0x04: return "存储器锁定";
            case 0x05: return "访问密码错误";
            case 0x09: return "销毁密码错误";
            case 0x0A: return "销毁密码不能为全0";
            case 0x0B: return "电子标签不支持该命令或电源不足";
            case 0x0C: return "对该命令,访问密码不能为0";
            case 0x0D: return "电子标签已经被设置了读保护,不能再次设置";
            case 0x0E: return "电子标签没有被设置读保护,不需要解锁";
            case 0x0F: return "非特定错误,标签不支持特定错误代码";
            case 0x10: return "有字节空间被锁定,写入失败";
            case 0x11: return "不能锁定";
            case 0x12: return "已经锁定,不能再次锁定";
            case 0x13: return "参数保存失败,但设置的值在读写模块断电前有效";
            case 0x14: return "无法调整";
            case 0x15: return "询查时间结束前返回";
            case 0x17: return "本条消息之后,还有消息";
            case 0x18: return "读写模块存储空间已满";
            case 0x19: return "电子不支持该命令或者访问密码不能为0";
            case 0x30: return "通讯错误";
            case 0x33: return "通讯繁忙,设备正在执行其他命令";
            case 0x35: return "端口已打开";
            case 0x37: return "无效句柄";
            case 0xF8: return "天线检测错误";
            case 0xF9: return "命令执行出错";
            case 0xFA: return "有电子标签,但通信不畅,无法操作";
            case 0xFB: return "无电子标签可操作";
            case 0xFC: return "电子标签返回错误代码";
            case 0xFD: return "命令长度错误";
            case 0xFE: return "不合法的命令";
            case 0xFF: return "参数错误";
            default: return "未知错误码";
        }
    }
    // ==================== 标签信息类 ====================
    /**
     * 标签信息类
     */
    public static class TagInfo {
        public String epc;          // EPC(十六进制字符串)
        public int rssi;            // RSSI(dBm)
        public int antenna;         // 天线号
        public long timestamp;      // 时间戳
        @Override
        public String toString() {
            return String.format("EPC: %s, RSSI: %ddBm, 天线: %d", epc, rssi, antenna);
        }
    }
}
src/main/java/com/zy/controller/RFIDController.java
New file
@@ -0,0 +1,270 @@
package com.zy.controller;
import com.core.common.R;
import com.zy.service.RFIDService;
import com.zy.service.RFIDAutoConnectService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
 * RFID设备HTTP API接口
 * 提供RFID设备连接、检测等功能
 * Created on 2026/01/10
 */
@Slf4j
@RestController
@RequestMapping("/api/rfid")
public class RFIDController {
    @Autowired
    private RFIDService rfidService;
    @Autowired
    private RFIDAutoConnectService rfidAutoConnectService;
    /**
     * 网络连接RFID设备
     *
     * POST /api/rfid/connect/network
     * Body: {"ip": "10.10.10.210", "port": 27011}
     *
     * @param params 连接参数
     * @return 连接结果
     */
    @PostMapping("/connect/network")
    public R connectNetwork(@RequestBody Map<String, Object> params) {
        String ip = (String) params.get("ip");
        Integer port = params.get("port") != null ?
                Integer.valueOf(params.get("port").toString()) : null;
        if (ip == null || ip.isEmpty()) {
            return R.error("IP地址不能为空");
        }
        Map<String, Object> result = rfidService.connectNetwork(ip, port);
        return result.get("success").equals(true) ? R.ok(result) : R.error(result.get("message").toString());
    }
    /**
     * 串口连接RFID设备
     *
     * POST /api/rfid/connect/comport
     * Body: {"port": 3, "baud": 3}
     *
     * @param params 连接参数
     * @return 连接结果
     */
    @PostMapping("/connect/comport")
    public R connectComPort(@RequestBody Map<String, Object> params) {
        Integer port = params.get("port") != null ?
                Integer.valueOf(params.get("port").toString()) : null;
        Integer baud = params.get("baud") != null ?
                Integer.valueOf(params.get("baud").toString()) : null;
        Map<String, Object> result = rfidService.connectComPort(port, baud);
        return result.get("success").equals(true) ? R.ok(result) : R.error(result.get("message").toString());
    }
    /**
     * 检测RFID标签(单次检测)
     *
     * GET /api/rfid/detect
     * GET /api/rfid/detect?scanTime=5
     *
     * @param scanTime 扫描时间(单位: 100ms,默认5)
     * @return 检测结果
     */
    @GetMapping("/detect")
    public R detectTags(@RequestParam(required = false) Integer scanTime) {
        Map<String, Object> result = rfidService.detectTags(scanTime);
        return R.ok(result);
    }
    /**
     * 检测RFID标签(POST方式,可传递更多参数)
     *
     * POST /api/rfid/detect
     * Body: {"scanTime": 5}
     *
     * @param params 检测参数
     * @return 检测结果
     */
    @PostMapping("/detect")
    public R detectTagsPost(@RequestBody(required = false) Map<String, Object> params) {
        Integer scanTime = null;
        if (params != null && params.get("scanTime") != null) {
            scanTime = Integer.valueOf(params.get("scanTime").toString());
        }
        Map<String, Object> result = rfidService.detectTags(scanTime);
        return R.ok(result);
    }
    /**
     * 断开RFID设备连接
     *
     * POST /api/rfid/disconnect
     *
     * @return 断开结果
     */
    @PostMapping("/disconnect")
    public R disconnect() {
        Map<String, Object> result = rfidService.disconnect();
        return result.get("success").equals(true) ? R.ok(result) : R.error(result.get("message").toString());
    }
    /**
     * 获取连接状态
     *
     * GET /api/rfid/status
     *
     * @return 连接状态
     */
    @GetMapping("/status")
    public R getStatus() {
        Map<String, Object> result = rfidService.getConnectionStatus();
        return R.ok(result);
    }
    /**
     * 诊断DLL加载状态
     *
     * GET /api/rfid/diagnose
     *
     * @return 诊断信息
     */
    @GetMapping("/diagnose")
    public R diagnose() {
        Map<String, Object> result = rfidService.diagnoseDll();
        return R.ok(result);
    }
    /**
     * 获取所有RFID自动连接设备状态
     *
     * GET /api/rfid/auto-connect/status
     *
     * @return 所有设备状态
     */
    @GetMapping("/auto-connect/status")
    public R getAutoConnectStatus() {
        return R.ok(rfidAutoConnectService.getAllDeviceStatus());
    }
    /**
     * 获取指定RFID自动连接设备状态
     *
     * GET /api/rfid/auto-connect/status/{deviceId}
     *
     * @param deviceId 设备ID
     * @return 设备状态
     */
    @GetMapping("/auto-connect/status/{deviceId}")
    public R getAutoConnectDeviceStatus(@PathVariable Integer deviceId) {
        Map<String, Object> result = rfidAutoConnectService.getDeviceStatus(deviceId);
        return R.ok(result);
    }
    /**
     * 手动启动指定RFID设备自动连接
     *
     * POST /api/rfid/auto-connect/start/{deviceId}
     *
     * @param deviceId 设备ID
     * @return 启动结果
     */
    @PostMapping("/auto-connect/start/{deviceId}")
    public R startAutoConnect(@PathVariable Integer deviceId) {
        boolean success = rfidAutoConnectService.startDevice(deviceId);
        if (success) {
            return R.ok("RFID设备[" + deviceId + "]自动连接已启动");
        } else {
            return R.error("RFID设备[" + deviceId + "]启动失败,请检查配置或设备是否已在运行");
        }
    }
    /**
     * 手动停止指定RFID设备自动连接
     *
     * POST /api/rfid/auto-connect/stop/{deviceId}
     *
     * @param deviceId 设备ID
     * @return 停止结果
     */
    @PostMapping("/auto-connect/stop/{deviceId}")
    public R stopAutoConnect(@PathVariable Integer deviceId) {
        boolean success = rfidAutoConnectService.stopDevice(deviceId);
        if (success) {
            return R.ok("RFID设备[" + deviceId + "]自动连接已停止");
        } else {
            return R.error("RFID设备[" + deviceId + "]停止失败,设备可能未启用自动连接");
        }
    }
    /**
     * 手动停止所有RFID设备自动连接
     *
     * POST /api/rfid/auto-connect/stop-all
     *
     * @return 停止结果
     */
    @PostMapping("/auto-connect/stop-all")
    public R stopAllAutoConnect() {
        rfidAutoConnectService.stopAll();
        return R.ok("所有RFID设备自动连接已停止");
    }
    /**
     * 重新配置指定RFID设备的天线(用于天线插拔后重新配置)
     *
     * POST /api/rfid/reconfigure-antenna/{deviceId}
     *
     * @param deviceId 设备ID
     * @return 配置结果
     */
    @PostMapping("/reconfigure-antenna/{deviceId}")
    public R reconfigureAntenna(@PathVariable Integer deviceId) {
        Map<String, Object> deviceStatus = rfidAutoConnectService.getDeviceStatus(deviceId);
        if (!Boolean.TRUE.equals(deviceStatus.get("exists"))) {
            return R.error("RFID设备[" + deviceId + "]未启用自动连接或不存在");
        }
        if (!Boolean.TRUE.equals(deviceStatus.get("templateConnected"))) {
            return R.error("RFID设备[" + deviceId + "]未连接,无法配置天线");
        }
        // 获取设备管理器并重新配置天线
        boolean success = rfidAutoConnectService.reconfigureAntenna(deviceId);
        if (success) {
            return R.ok("RFID设备[" + deviceId + "]天线重新配置成功");
        } else {
            return R.error("RFID设备[" + deviceId + "]天线重新配置失败,请查看日志");
        }
    }
    @GetMapping("/tags")
    public R getTags(@RequestParam(required = false) Integer deviceId,
                     @RequestParam(required = false) String ip,
                     @RequestParam(required = false) Integer antenna) {
        if (deviceId == null && (ip == null || ip.isEmpty())) {
            return R.error("请提供设备ID或IP地址");
        }
        List<Map<String, Object>> tags = rfidAutoConnectService.getDeviceTags(deviceId, ip, antenna);
        return R.ok(tags);
    }
    @GetMapping("/query-tags")
    public R queryTags(@RequestParam(required = false) Integer deviceId,
                       @RequestParam(required = false) String ip,
                       @RequestParam(required = false) Integer antenna) {
        if (deviceId == null && (ip == null || ip.isEmpty())) {
            return R.error("请提供设备ID或IP地址");
        }
        List<Map<String, Object>> tags = rfidAutoConnectService.queryDeviceTags(deviceId, ip, antenna);
        return R.ok(tags);
    }
}
src/main/java/com/zy/core/ServerBootstrap.java
@@ -6,9 +6,11 @@
import com.zy.core.model.CrnSlave;
import com.zy.core.model.DevpSlave;
import com.zy.core.model.LedSlave;
import com.zy.core.model.RFIDSlave;
import com.zy.core.properties.SlaveProperties;
import com.zy.core.thread.BarcodeThread;
import com.zy.core.thread.LedThread;
import com.zy.core.thread.RFIDThread;
import com.zy.core.thread.SiemensCrnThread;
import com.zy.core.thread.SiemensDevpThread;
import com.zy.utils.News;
@@ -75,6 +77,10 @@
        for (Slave led : slaveProperties.getLed()) {
            MessageQueue.init(SlaveType.Led, led);
        }
        // 初始化RFID读写器mq
        for (Slave rfid : slaveProperties.getRfid()) {
            MessageQueue.init(SlaveType.Rfid, rfid);
        }
        // 初始化磅称mq
//        for (Slave scale : slaveProperties.getScale()) {
//            MessageQueue.init(SlaveType.Scale, scale);
@@ -121,6 +127,19 @@
            new Thread(ledThread).start();
            SlaveConnection.put(SlaveType.Led, led.getId(), ledThread);
        }
        // 初始化RFID读写器线程
        // 注意:如果RFID设备配置了autoConnect=true,将由RFIDAutoConnectService管理,这里跳过
        News.info("初始化RFID读写器线程...................................................");
        for (RFIDSlave rfid : slaveProperties.getRfid()) {
            // 如果启用了自动连接,跳过RFIDThread的创建(由RFIDAutoConnectService管理)
            if (rfid.getAutoConnect() != null && rfid.getAutoConnect()) {
                News.info("RFID设备[{}]已启用自动连接,跳过RFIDThread初始化", rfid.getId());
                continue;
            }
            RFIDThread rfidThread = new RFIDThread(rfid);
            new Thread(rfidThread).start();
            SlaveConnection.put(SlaveType.Rfid, rfid.getId(), rfidThread);
        }
        // 初始化磅秤线程
//        News.info("初始化磅秤线程...................................................");
//        for (Slave scale : slaveProperties.getScale()) {
src/main/java/com/zy/core/cache/OutputQueue.java
@@ -17,4 +17,6 @@
    public static ArrayBlockingQueue<JSONObject> BARCODE = new ArrayBlockingQueue<>(32);
    // rgv输出日志
    public static ArrayBlockingQueue<String> RGV = new ArrayBlockingQueue<>(32);
    // RFID输出日志
    public static ArrayBlockingQueue<JSONObject> RFID = new ArrayBlockingQueue<>(32);
}
src/main/java/com/zy/core/enums/SlaveType.java
@@ -8,7 +8,8 @@
    Led,
    Scale,
    Car,
    Rgv
    Rgv,
    Rfid
    ;
    public static SlaveType findInstance(String s){
src/main/java/com/zy/core/model/RFIDSlave.java
New file
@@ -0,0 +1,20 @@
package com.zy.core.model;
import com.zy.core.Slave;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * RFID设备配置
 * Created on 2026/01/10
 */
@EqualsAndHashCode(callSuper = true)
@Data
public class RFIDSlave extends Slave {
    /**
     * 是否自动连接(true: 系统启动时自动连接,false: 手动连接)
     */
    private Boolean autoConnect = false;
}
src/main/java/com/zy/core/thread/RFIDThread.java
New file
@@ -0,0 +1,322 @@
package com.zy.core.thread;
import com.alibaba.fastjson.JSONObject;
import com.core.common.Cools;
import com.core.common.DateUtils;
import com.zy.core.Slave;
import com.zy.core.ThreadHandler;
import com.zy.core.cache.OutputQueue;
import com.rfid.uhf288.Device;
import com.zy.utils.News;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.text.MessageFormat;
import java.util.Date;
/**
 * RFID读写器线程
 * 基于UHF288设备,支持串口和网络连接
 * Created by chen.lin on 2026/01/10
 */
@Data
@Slf4j
public class RFIDThread implements Runnable, ThreadHandler {
    private Slave slave;
    private StringBuffer rfid = new StringBuffer();
    private String lastRfid = "";
    private Device reader;
    private int portHandle = -1;
    private byte[] comAddr = new byte[1];
    private boolean isConnected = false;
    private String connectionType = ""; // "COM" 或 "NET"
    // 连接参数
    private Integer comPort;      // 串口号(如果使用串口)
    private Byte baudRate;        // 波特率(如果使用串口)
    private String ipAddress;     // IP地址(如果使用网络)
    private Integer netPort;      // 网络端口(如果使用网络)
    public RFIDThread(Slave slave) {
        this.slave = slave;
        try {
            reader = new Device();
            comAddr[0] = (byte)255; // 默认地址0xFF
        } catch (Exception e) {
            log.error("RFID设备初始化失败", e);
        }
    }
    public String getRfid() {
        return rfid.toString();
    }
    public void setRfid(String rfid) {
        this.rfid.delete(0, this.rfid.length());
        this.rfid.append(rfid);
        if(!Cools.isEmpty(rfid) && !lastRfid.equals(rfid)) {
            News.info("RFID"+" - 1"+" - {}号RFID读写器,检索数据:{}", slave.getId(), this.rfid);
            lastRfid = rfid;
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("time", DateUtils.convert(new Date(), DateUtils.yyyyMMddHHmmss_F));
            jsonObject.put("rfid", rfid);
            if (OutputQueue.RFID.size() >= 32) {
                OutputQueue.RFID.poll();
            }
            OutputQueue.RFID.offer(jsonObject);
        }
    }
    @Override
    public boolean connect() {
        if (isConnected) {
            log.warn("RFID设备已连接,无需重复连接");
            return true;
        }
        boolean result = false;
        try {
            // 优先尝试网络连接(如果配置了IP)
            if (!Cools.isEmpty(slave.getIp()) && slave.getPort() != null) {
                result = connectNetwork(slave.getIp(), slave.getPort());
                if (result) {
                    connectionType = "NET";
                    JSONObject connMsg = new JSONObject();
                    connMsg.put("time", DateUtils.convert(new Date(), DateUtils.yyyyMMddHHmmss_F));
                    connMsg.put("message", MessageFormat.format("RFID网络连接成功 ===>> [id:{0}] [ip:{1}] [port:{2}]",
                            slave.getId(), slave.getIp(), slave.getPort()));
                    OutputQueue.RFID.offer(connMsg);
                    log.info("RFID网络连接成功 ===>> [id:{}] [ip:{}] [port:{}]", slave.getId(), slave.getIp(), slave.getPort());
                    return true;
                }
            }
            // 如果网络连接失败,尝试串口连接
            // 注意:串口连接需要额外的配置参数(串口号和波特率)
            // 这里假设可以通过某种方式获取,或者使用默认值
            if (comPort == null) {
                comPort = 3; // 默认COM3
            }
            if (baudRate == null) {
                baudRate = (byte)3; // 默认57600bps
            }
            result = connectComPort(comPort, baudRate);
            if (result) {
                connectionType = "COM";
                JSONObject connMsg = new JSONObject();
                connMsg.put("time", DateUtils.convert(new Date(), DateUtils.yyyyMMddHHmmss_F));
                connMsg.put("message", MessageFormat.format("RFID串口连接成功 ===>> [id:{0}] [port:COM{1}] [baud:{2}]",
                        slave.getId(), comPort, getBaudRateName(baudRate)));
                OutputQueue.RFID.offer(connMsg);
                log.info("RFID串口连接成功 ===>> [id:{}] [port:COM{}] [baud:{}]", slave.getId(), comPort, getBaudRateName(baudRate));
                return true;
            }
        } catch (Exception e) {
            log.error("RFID连接失败", e);
            JSONObject connMsg = new JSONObject();
            connMsg.put("time", DateUtils.convert(new Date(), DateUtils.yyyyMMddHHmmss_F));
            connMsg.put("message", MessageFormat.format("RFID连接失败!!! ===>> [id:{0}] [ip:{1}] [port:{2}]",
                    slave.getId(), slave.getIp(), slave.getPort()));
            OutputQueue.RFID.offer(connMsg);
        }
        return false;
    }
    /**
     * 串口连接
     */
    private boolean connectComPort(int port, byte baud) {
        try {
            int[] portHandleArray = new int[1];
            int result = reader.OpenComPort(port, comAddr, baud, portHandleArray);
            if (result == 0) {
                portHandle = portHandleArray[0];
                isConnected = true;
                return true;
            } else {
                log.error("RFID串口连接失败,错误码: {}", result);
                return false;
            }
        } catch (Exception e) {
            log.error("RFID串口连接异常", e);
            return false;
        }
    }
    /**
     * 网络连接
     */
    private boolean connectNetwork(String ipAddr, int port) {
        try {
            int[] portHandleArray = new int[1];
            int result = reader.OpenNetPort(port, ipAddr, comAddr, portHandleArray);
            if (result == 0) {
                portHandle = portHandleArray[0];
                isConnected = true;
                return true;
            } else {
                log.error("RFID网络连接失败,错误码: {}", result);
                return false;
            }
        } catch (Exception e) {
            log.error("RFID网络连接异常", e);
            return false;
        }
    }
    /**
     * 读取RFID标签
     */
    private void readTags() {
        if (!isConnected || portHandle < 0) {
            return;
        }
        try {
            byte qValue = 4;        // Q值,推荐4
            byte session = 0;      // Session值,推荐0
            byte scanTime = 10;     // 扫描时间,10*100ms=1秒
            byte maskMem = 2;       // EPC区
            byte[] maskAdr = new byte[2];
            byte maskLen = 0;
            byte[] maskData = new byte[256];
            byte maskFlag = 0;      // 不使用掩码
            byte adrTID = 0;
            byte lenTID = 6;
            byte tidFlag = 0;       // 0-读取EPC,1-读取TID
            byte target = 0;
            byte inAnt = (byte)0x81;
            byte fastFlag = 0;
            byte[] pEPCList = new byte[20000];
            byte[] ant = new byte[1];
            int[] totallen = new int[1];
            int[] cardNum = new int[1];
            // 清空数组
            java.util.Arrays.fill(pEPCList, (byte)0);
            totallen[0] = 0;
            cardNum[0] = 0;
            int result = reader.Inventory_G2(comAddr, qValue, session, maskMem, maskAdr, maskLen,
                    maskData, maskFlag, adrTID, lenTID, tidFlag, target, inAnt, scanTime,
                    fastFlag, pEPCList, ant, totallen, cardNum, portHandle);
            // 解析标签数据
            if (cardNum[0] > 0 && totallen[0] > 0) {
                int offset = 0;
                for (int i = 0; i < cardNum[0]; i++) {
                    if (offset + 1 >= totallen[0]) break;
                    byte epcLen = pEPCList[offset];
                    offset++;
                    if (offset + epcLen > totallen[0]) break;
                    byte[] epcBytes = new byte[epcLen];
                    System.arraycopy(pEPCList, offset, epcBytes, 0, epcLen);
                    offset += epcLen;
                    // RSSI和天线信息
                    byte rssi = 0;
                    byte antenna = 0;
                    if (offset < totallen[0]) {
                        rssi = pEPCList[offset];
                        offset++;
                    }
                    if (offset < totallen[0]) {
                        antenna = pEPCList[offset];
                        offset++;
                    }
                    String epcHex = bytesToHex(epcBytes);
                    // 只取EPC的一部分(类似参考项目中的处理方式)
                    if (epcHex.length() >= 24) {
                        epcHex = epcHex.substring(14, 24);
                    }
                    setRfid(epcHex);
                    // 只处理第一个标签
                    break;
                }
            }
        } catch (Exception e) {
            log.error("RFID读取标签异常", e);
        }
    }
    /**
     * 字节数组转十六进制字符串
     */
    private String bytesToHex(byte[] bytes) {
        if (bytes == null) return "";
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X", b & 0xFF));
        }
        return sb.toString();
    }
    /**
     * 获取波特率名称
     */
    private String getBaudRateName(byte baud) {
        String[] names = {"9600", "19200", "38400", "57600", "115200", "230400", "460800", "921600"};
        int index = baud & 0xFF;
        if (index >= 0 && index < names.length) {
            return names[index];
        }
        return String.valueOf(baud);
    }
    @Override
    public void close() {
        if (isConnected && portHandle >= 0) {
            try {
                if ("COM".equals(connectionType)) {
                    reader.CloseSpecComPort(portHandle);
                } else if ("NET".equals(connectionType)) {
                    reader.CloseNetPort(portHandle);
                }
                isConnected = false;
                portHandle = -1;
                connectionType = "";
                log.info("RFID连接已关闭 ===>> [id:{}]", slave.getId());
            } catch (Exception e) {
                log.error("RFID关闭连接异常", e);
            }
        }
    }
    @Override
    public void run() {
        connect();
        while (true) {
            try {
                if (isConnected) {
                    readTags();
                } else {
                    // 如果未连接,尝试重连
                    connect();
                }
                Thread.sleep(300);
            } catch (Exception e) {
                log.error("RFID线程运行异常", e);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }
    }
}
src/main/java/com/zy/rfid/RFIDTemplate.java
New file
@@ -0,0 +1,506 @@
package com.zy.rfid;
import com.rfid.uhf288.Device;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
/**
 * RFID设备操作模板 - 模块化设计
 * 参考demo项目,但只包含基本读取功能(类似参考项目zy-wcs-czbrwcs中的功能)
 * Created by chen.lin on 2026/01/10
 *
 * 功能模块:
 * 1. 连接模块 - 串口连接 / 网络连接(独立)
 * 2. 读取模块 - 盘点标签(独立)
 *
 * 使用方式:
 * 1. 创建实例
 * 2. 选择连接方式(串口或网络)
 * 3. 连接成功后,调用读取功能
 * 4. 使用完毕后关闭连接
 */
@Slf4j
public class RFIDTemplate {
    // ==================== 基础组件 ====================
    private Device reader;
    private int portHandle = -1;
    private byte[] comAddr = new byte[1];
    // 连接状态
    private boolean isConnected = false;
    private String connectionType = ""; // "COM" 或 "NET"
    // ==================== 初始化 ====================
    /**
     * 构造函数 - 加载DLL库
     */
    public RFIDTemplate() {
        try {
            reader = new Device();
            comAddr[0] = (byte)255; // 默认地址
            log.info("RFID模板初始化成功");
        } catch (Exception e) {
            log.error("RFID模板初始化失败", e);
        }
    }
    // ==================== 模块1: 连接模块 ====================
    /**
     * 【串口连接】打开串口连接
     *
     * @param port 串口号 (1=COM1, 2=COM2, 3=COM3...)
     * @param baud 波特率 (0=9600, 1=19200, 2=38400, 3=57600, 4=115200, 5=230400, 6=460800, 7=921600)
     * @return true=成功, false=失败
     */
    public boolean connectComPort(int port, byte baud) {
        if (isConnected) {
            log.warn("已存在连接,请先关闭当前连接");
            return false;
        }
        try {
            int[] portHandleArray = new int[1];
            int result = reader.OpenComPort(port, comAddr, baud, portHandleArray);
            if (result == 0) {
                portHandle = portHandleArray[0];
                isConnected = true;
                connectionType = "COM";
                log.info("========== 串口连接成功 ==========");
                log.info("串口号: COM{}", port);
                log.info("端口句柄: {}", portHandle);
            try {
                int checkAntResult = reader.SetCheckAnt(comAddr, (byte)0x01, portHandle);
                if (checkAntResult == 0) {
//                    log.info("天线检测开启成功");
                }
                int antResult = reader.SetAntennaMultiplexing(comAddr, (byte)0x0F, portHandle);
                if (antResult == 0) {
                    log.info("天线多路复用配置成功 - 启用天线1,2,3,4 (0x0F)");
                } else {
                    int antennaResult = reader.SetAntenna(comAddr, (byte)0, (byte)0x0F, (byte)0, portHandle);
                    if (antennaResult == 0) {
                        log.info("天线配置成功 - 启用天线1,2,3,4 (0x0F)");
                    }
                }
            } catch (Exception e) {
                log.warn("配置天线异常: {}", e.getMessage());
            }
                return true;
            } else {
                log.error("串口连接失败,错误码: 0x{} ({})", String.format("%02X", result & 0xFF), getErrorCodeMessage(result));
                return false;
            }
        } catch (UnsatisfiedLinkError e) {
            log.error("RFID设备DLL方法链接失败 - OpenComPort", e);
            log.error("错误信息: {}", e.getMessage());
            log.error("可能原因:1. DLL版本不匹配 2. 方法签名不匹配 3. DLL未正确加载");
            throw e; // 重新抛出异常,让调用者处理
        }
    }
    /**
     * 【串口连接】自动尝试多个波特率连接(推荐)
     *
     * @param port 串口号 (1=COM1, 2=COM2, 3=COM3...)
     * @param preferredBaud 首选波特率 (0-7),-1表示使用默认顺序
     * @return true=成功, false=失败
     */
    public boolean connectComPortAuto(int port, int preferredBaud) {
        if (isConnected) {
            log.warn("已存在连接,请先关闭当前连接");
            return false;
        }
        // 波特率映射
        byte[] baudRates = {(byte)0, (byte)1, (byte)2, (byte)3, (byte)4, (byte)5, (byte)6, (byte)7};
        String[] baudNames = {"9600", "19200", "38400", "57600", "115200", "230400", "460800", "921600"};
        // 默认尝试顺序:57600优先
        byte[] tryBauds = {(byte)3, (byte)4, (byte)2, (byte)1, (byte)0, (byte)5, (byte)6, (byte)7};
        // 如果指定了首选波特率,将其放在最前面
        if (preferredBaud >= 0 && preferredBaud <= 7) {
            byte[] newTryBauds = new byte[tryBauds.length];
            newTryBauds[0] = (byte)preferredBaud;
            int idx = 1;
            for (byte b : tryBauds) {
                if (b != preferredBaud) {
                    newTryBauds[idx++] = b;
                }
            }
            tryBauds = newTryBauds;
        }
        log.info("========== 串口连接 ==========");
        log.info("串口号: COM{}", port);
        log.info("正在尝试连接...");
        for (int i = 0; i < tryBauds.length; i++) {
            byte baud = tryBauds[i];
            String baudName = "";
            for (int j = 0; j < baudRates.length; j++) {
                if (baudRates[j] == baud) {
                    baudName = baudNames[j];
                    break;
                }
            }
            log.info("尝试波特率: {}bps ... ", baudName);
            int[] portHandleArray = new int[1];
            int result = reader.OpenComPort(port, comAddr, baud, portHandleArray);
            if (result == 0) {
                portHandle = portHandleArray[0];
                isConnected = true;
                connectionType = "COM";
                log.info("✓ 成功!");
                log.info("连接成功!波特率: {}bps", baudName);
                log.info("端口句柄: {}", portHandle);
                return true;
            } else {
                log.warn("✗ 失败");
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        log.error("所有波特率尝试均失败!");
        return false;
    }
    /**
     * 【网络连接】打开网络连接
     *
     * @param ipAddr IP地址 (如: 192.168.1.190)
     * @param port 端口号 (默认6000)
     * @return true=成功, false=失败
     */
    public boolean connectNetwork(String ipAddr, int port) {
        if (isConnected) {
            log.warn("已存在连接,请先关闭当前连接");
            return false;
        }
        try {
            int[] portHandleArray = new int[1];
            int result = reader.OpenNetPort(port, ipAddr, comAddr, portHandleArray);
        if (result == 0) {
            portHandle = portHandleArray[0];
            isConnected = true;
            connectionType = "NET";
            log.info("========== 网络连接成功 ==========");
            log.info("IP地址: {}", ipAddr);
            log.info("端口号: {}", port);
            log.info("端口句柄: {}", portHandle);
            try {
                int checkAntResult = reader.SetCheckAnt(comAddr, (byte)0x01, portHandle);
                if (checkAntResult == 0) {
//                    log.info("天线检测开启成功");
                }
                int antResult = reader.SetAntennaMultiplexing(comAddr, (byte)0x0F, portHandle);
                if (antResult == 0) {
                    log.info("天线多路复用配置成功 - 启用天线1,2,3,4 (0x0F)");
                } else {
                    int antennaResult = reader.SetAntenna(comAddr, (byte)0, (byte)0x0F, (byte)0, portHandle);
                    if (antennaResult == 0) {
                        log.info("天线配置成功 - 启用天线1,2,3,4 (0x0F)");
                    }
                }
            } catch (Exception e) {
                log.warn("配置天线异常: {}", e.getMessage());
            }
            return true;
        } else {
            log.error("网络连接失败,错误码: 0x{} ({})", String.format("%02X", result & 0xFF), getErrorCodeMessage(result));
            log.error("请检查IP地址和端口是否正确");
            return false;
        }
        } catch (UnsatisfiedLinkError e) {
            log.error("RFID设备DLL方法链接失败 - OpenNetPort", e);
            log.error("错误信息: {}", e.getMessage());
            log.error("可能原因:1. DLL版本不匹配 2. 方法签名不匹配 3. DLL未正确加载");
            throw e; // 重新抛出异常,让调用者处理
        }
    }
    /**
     * 【网络连接】使用默认端口6000连接
     *
     * @param ipAddr IP地址 (如: 192.168.1.190)
     * @return true=成功, false=失败
     */
    public boolean connectNetwork(String ipAddr) {
        return connectNetwork(ipAddr, 6000);
    }
    /**
     * 【连接管理】关闭连接
     */
    public void disconnect() {
        if (!isConnected) {
            log.warn("当前没有连接");
            return;
        }
        if ("COM".equals(connectionType)) {
            int result = reader.CloseSpecComPort(portHandle);
            if (result == 0) {
                log.info("串口连接已关闭");
            }
        } else if ("NET".equals(connectionType)) {
            int result = reader.CloseNetPort(portHandle);
            if (result == 0) {
                log.info("网络连接已关闭");
            }
        }
        portHandle = -1;
        isConnected = false;
        connectionType = "";
    }
    /**
     * 【连接管理】检查连接状态
     *
     * @return true=已连接, false=未连接
     */
    public boolean isConnected() {
        return isConnected && portHandle >= 0;
    }
    /**
     * 【天线配置】重新配置天线(动态切换天线时使用)
     * 当物理天线插拔后,调用此方法重新配置天线,确保所有插上的天线都能被检测到
     *
     * @return true=成功, false=失败
     */
    public boolean reconfigureAntenna() {
        if (!isConnected()) {
            log.warn("设备未连接,无法配置天线");
            return false;
        }
        boolean configured = false;
        try {
            int checkAntResult = reader.SetCheckAnt(comAddr, (byte)0x01, portHandle);
            if (checkAntResult == 0) {
//                log.info("天线检测开启成功");
                configured = true;
            }
            int antResult = reader.SetAntennaMultiplexing(comAddr, (byte)0x0F, portHandle);
            if (antResult == 0) {
                log.info("天线多路复用配置成功 - 启用天线1,2,3,4 (0x0F)");
                configured = true;
            } else {
                int antennaResult = reader.SetAntenna(comAddr, (byte)0, (byte)0x0F, (byte)0, portHandle);
                if (antennaResult == 0) {
                    log.info("天线配置成功 - 启用天线1,2,3,4 (0x0F)");
                    configured = true;
                }
            }
            return configured;
        } catch (Exception e) {
            log.error("重新配置天线异常: {}", e.getMessage(), e);
            return false;
        }
    }
    /**
     * 【连接管理】获取连接类型
     *
     * @return "COM"=串口, "NET"=网络, ""=未连接
     */
    public String getConnectionType() {
        return connectionType;
    }
    // ==================== 模块2: 读取模块 ====================
    public List<TagInfo> readTags(int qValue, int session, int scanTime) {
        List<TagInfo> tagList = new ArrayList<>();
        if (!isConnected()) {
            return tagList;
        }
        byte maskMem = 2;
        byte[] maskAdr = new byte[2];
        byte maskLen = 0;
        byte[] maskData = new byte[256];
        byte maskFlag = 0;
        byte adrTID = 0;
        byte lenTID = 6;
        byte tidFlag = 0;
        byte target = 0;
        byte fastFlag = 0;
        byte[] pEPCList = new byte[20000];
        byte[] ant = new byte[1];
        int[] totallen = new int[1];
        int[] cardNum = new int[1];
        byte[] antennaValues = {(byte)0x80, (byte)0x81, (byte)0x82, (byte)0x83};
        int[] antennaNumbers = {1, 2, 3, 4};
        for (int antIdx = 0; antIdx < antennaValues.length; antIdx++) {
            byte inAnt = antennaValues[antIdx];
            int expectedAntenna = antennaNumbers[antIdx];
            java.util.Arrays.fill(pEPCList, (byte)0);
            totallen[0] = 0;
            cardNum[0] = 0;
            int result = reader.Inventory_G2(comAddr, (byte)qValue, (byte)session, maskMem, maskAdr, maskLen,
                    maskData, maskFlag, adrTID, lenTID, tidFlag, target, inAnt, (byte)scanTime,
                    fastFlag, pEPCList, ant, totallen, cardNum, portHandle);
            if (cardNum[0] > 0 && totallen[0] > 0) {
                int m = 0;
                for (int index = 0; index < cardNum[0]; index++) {
                    if (m >= totallen[0] || m >= pEPCList.length) break;
                    int epcLen = pEPCList[m++] & 0xFF;
                    if (epcLen <= 0 || epcLen > 32) break;
                    if (m + epcLen > totallen[0] || m + epcLen > pEPCList.length) break;
                    byte[] epcBytes = new byte[epcLen];
                    for (int n = 0; n < epcLen; n++) {
                        epcBytes[n] = pEPCList[m++];
                    }
                    if (m >= totallen[0] || m >= pEPCList.length) break;
                    int rssi = pEPCList[m++] & 0xFF;
                    if (rssi > 127) rssi = rssi - 256;
                    int antennaValue = 0;
                    if (m < totallen[0] && m < pEPCList.length) {
                        antennaValue = pEPCList[m++] & 0xFF;
                    } else {
                        antennaValue = ant[0] & 0xFF;
                    }
                    TagInfo tag = new TagInfo();
                    tag.epc = bytesToHex(epcBytes);
                    tag.rssi = rssi;
                    if (antennaValue >= 0x80 && antennaValue <= 0x83) {
                        tag.antenna = antennaValue - 0x80 + 1;
                    } else if (antennaValue >= 1 && antennaValue <= 4) {
                        tag.antenna = antennaValue;
                    } else {
                        tag.antenna = expectedAntenna;
                    }
                    tag.timestamp = System.currentTimeMillis();
                    tagList.add(tag);
                }
            } else {
                if (result != 0) {
                    int errorCode = result & 0xFF;
                    if (errorCode == 0xFB) {
                        continue;
                    }
                    if (errorCode == 0x01) {
                        continue;
                    }
                    if (errorCode == 0xF8) {
//                        log.warn("天线{}盘点失败,错误码: 0x{} ({})", expectedAntenna, String.format("%02X", errorCode), getErrorCodeMessage(result));
                    } else {
//                        log.debug("天线{}盘点失败,错误码: 0x{} ({})", expectedAntenna, String.format("%02X", errorCode), getErrorCodeMessage(result));
                    }
                }
            }
        }
        return tagList;
    }
    public List<TagInfo> readTags() {
        return readTags(4, 0, 10);
    }
    // ==================== 工具方法 ====================
    private String bytesToHex(byte[] bytes) {
        if (bytes == null) return "";
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X", b & 0xFF));
        }
        return sb.toString();
    }
    private String getErrorCodeMessage(int errorCode) {
        switch (errorCode & 0xFF) {
            case 0x00: return "无错误,API调用成功";
            case 0x01: return "询查时间结束前返回";
            case 0x02: return "指定的询查时间溢出";
            case 0x03: return "存储器超限或不被支持的PC值";
            case 0x04: return "存储器锁定";
            case 0x05: return "访问密码错误";
            case 0x09: return "销毁密码错误";
            case 0x0A: return "销毁密码不能为全0";
            case 0x0B: return "电子标签不支持该命令或电源不足";
            case 0x0C: return "对该命令,访问密码不能为0";
            case 0x0D: return "电子标签已经被设置了读保护,不能再次设置";
            case 0x0E: return "电子标签没有被设置读保护,不需要解锁";
            case 0x0F: return "非特定错误,标签不支持特定错误代码";
            case 0x10: return "有字节空间被锁定,写入失败";
            case 0x11: return "不能锁定";
            case 0x12: return "已经锁定,不能再次锁定";
            case 0x13: return "参数保存失败,但设置的值在读写模块断电前有效";
            case 0x14: return "无法调整";
            case 0x15: return "询查时间结束前返回";
            case 0x17: return "本条消息之后,还有消息";
            case 0x18: return "读写模块存储空间已满";
            case 0x19: return "电子不支持该命令或者访问密码不能为0";
            case 0x30: return "通讯错误";
            case 0x33: return "通讯繁忙,设备正在执行其他命令";
            case 0x35: return "端口已打开";
            case 0x37: return "无效句柄";
            case 0xF8: return "天线检测错误";
            case 0xF9: return "命令执行出错";
            case 0xFA: return "有电子标签,但通信不畅,无法操作";
            case 0xFB: return "无电子标签可操作";
            case 0xFC: return "电子标签返回错误代码";
            case 0xFD: return "命令长度错误";
            case 0xFE: return "不合法的命令";
            case 0xFF: return "参数错误";
            default: return "未知错误码";
        }
    }
    // ==================== 标签信息类 ====================
    /**
     * 标签信息类
     */
    public static class TagInfo {
        public String epc;          // EPC(十六进制字符串)
        public int rssi;            // RSSI(dBm)
        public int antenna;         // 天线号
        public long timestamp;      // 时间戳
        @Override
        public String toString() {
            return String.format("EPC: %s, RSSI: %ddBm, 天线: %d", epc, rssi, antenna);
        }
    }
}
src/main/java/com/zy/service/RFIDAutoConnectService.java
New file
@@ -0,0 +1,557 @@
package com.zy.service;
import com.zy.core.model.RFIDSlave;
import com.zy.core.properties.SlaveProperties;
import com.rfid.uhf288.RFIDTemplate;
import com.rfid.uhf288.RFIDTemplate.TagInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
/**
 * RFID自动连接和监控服务
 * 支持多个RFID设备独立管理,每个设备独立的连接线程和检测线程
 * 每个设备的autoConnect配置独立控制
 *
 * @author Created on 2026/01/10
 */
@Slf4j
@Service
public class RFIDAutoConnectService {
    @Autowired
    private SlaveProperties slaveProperties;
    @Value("${wcs-slave.rfid-config.reconnectInterval:5}")
    private Integer globalReconnectInterval;
    @Value("${wcs-slave.rfid-config.tagScanInterval:500}")
    private Integer globalTagScanInterval;
    @Value("${wcs-slave.rfid-config.tagScanTime:10}")
    private Integer globalTagScanTime;
    // 存储每个设备的连接和线程信息
    private final Map<Integer, DeviceManager> deviceManagers = new ConcurrentHashMap<>();
    /**
     * 设备管理器 - 管理单个RFID设备的连接和检测
     */
    private static class DeviceManager {
        final RFIDSlave config;
        final RFIDTemplate template;
        final AtomicBoolean running = new AtomicBoolean(false);
        final AtomicBoolean connected = new AtomicBoolean(false);
        Thread connectThread;
        Thread scanThread;
        final int reconnectInterval;
        final long tagScanInterval;
        final int tagScanTime;
        int reconfigCounter = 0;
        volatile List<TagInfo> latestTags = new ArrayList<>(); // 最新检测到的标签
        DeviceManager(RFIDSlave config, Integer reconnectInterval, Integer tagScanInterval, Integer tagScanTime) {
            this.config = config;
            this.template = new RFIDTemplate();
            this.reconnectInterval = reconnectInterval != null ? reconnectInterval : 5;
            this.tagScanInterval = tagScanInterval != null ? tagScanInterval : 500;
            this.tagScanTime = tagScanTime != null ? tagScanTime : 10;
        }
        void start() {
            if (running.get()) {
                return;
            }
            running.set(true);
            // 启动连接线程
            // 注意:设置为非守护线程,确保应用运行期间线程一直运行
            connectThread = new Thread(this::connectLoop,
                    String.format("RFID-Connect-%d-%s", config.getId(), config.getIp()));
            connectThread.setDaemon(false); // 改为非守护线程,确保应用运行期间一直运行
            connectThread.start();
            // 启动标签检测线程
            scanThread = new Thread(this::scanLoop,
                    String.format("RFID-Scan-%d-%s", config.getId(), config.getIp()));
            scanThread.setDaemon(false); // 改为非守护线程,确保应用运行期间一直运行
            scanThread.start();
        }
        void stop() {
            running.set(false);
            connected.set(false);
            if (connectThread != null) {
                connectThread.interrupt();
            }
            if (scanThread != null) {
                scanThread.interrupt();
            }
            try {
                if (connectThread != null) {
                    connectThread.join(2000);
                }
                if (scanThread != null) {
                    scanThread.join(2000);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            if (template != null && template.isConnected()) {
                try {
                    template.disconnect();
                } catch (Exception e) {
                    log.error("RFID设备[{}]断开连接异常", config.getId(), e);
                }
            }
        }
        /**
         * 连接循环 - 负责连接和重连
         * 特别处理UnsatisfiedLinkError,确保DLL方法链接失败时也会定期重连
         */
        private void connectLoop() {
            log.info("RFID设备[{}]连接线程启动 - IP: {}, Port: {}",
                    config.getId(), config.getIp(), config.getPort());
            while (running.get()) {
                try {
                    if (!connected.get()) {
                        log.info("========== RFID设备[{}]尝试连接 ==========", config.getId());
                        log.info("IP: {}, Port: {}", config.getIp(), config.getPort());
                        // 尝试连接
                        boolean success = false;
                        try {
                            success = template.connectNetwork(config.getIp(), config.getPort());
                        } catch (UnsatisfiedLinkError e) {
                            // DLL方法链接失败,记录错误但继续重连
                            log.error("RFID设备[{}] DLL方法链接失败 - UnsatisfiedLinkError", config.getId());
                            log.error("错误信息: {}", e.getMessage());
                            log.error("可能原因:1. DLL版本不匹配 2. 方法签名不匹配 3. DLL未正确加载");
                            log.warn("将在{}秒后重试连接", reconnectInterval);
                            success = false;
                        }
                        if (success) {
                            connected.set(true);
                            log.info("✓ RFID设备[{}]连接成功!IP: {}, Port: {}",
                                    config.getId(), config.getIp(), config.getPort());
                        } else {
                            log.warn("✗ RFID设备[{}]连接失败,{}秒后重试",
                                    config.getId(), reconnectInterval);
                            Thread.sleep(reconnectInterval * 1000L);
                        }
                    } else {
                        // 已连接,检查连接状态
                        if (!template.isConnected()) {
                            log.warn("RFID设备[{}]连接已断开,准备重连", config.getId());
                            connected.set(false);
                        } else {
                            // 连接正常,定期重新配置天线(处理天线插拔情况)
                            // 每5次循环(约50秒)重新配置一次天线,确保插拔后能自动检测
                            reconfigCounter++;
                            if (reconfigCounter >= 5) {
                                reconfigCounter = 0;
                                log.debug("RFID设备[{}]定期重新配置天线(处理天线插拔)", config.getId());
                                boolean reconfigured = template.reconfigureAntenna();
                                if (reconfigured) {
//                                    log.info("RFID设备[{}]天线重新配置成功,所有天线已启用", config.getId());
                                }
                            }
                            // 等待一段时间后再次检查
                            Thread.sleep(reconnectInterval * 1000L);
                        }
                    }
                } catch (InterruptedException e) {
                    log.info("RFID设备[{}]连接线程被中断", config.getId());
                    Thread.currentThread().interrupt();
                    break;
                } catch (UnsatisfiedLinkError e) {
                    // DLL方法链接失败,记录错误并继续重连
                    log.error("RFID设备[{}]连接线程 - DLL方法链接失败", config.getId());
                    log.error("错误信息: {}", e.getMessage());
                    log.error("可能原因:1. DLL版本不匹配 2. 方法签名不匹配 3. DLL未正确加载");
                    log.warn("将在{}秒后重试连接", reconnectInterval);
                    connected.set(false);
                    try {
                        Thread.sleep(reconnectInterval * 1000L);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                } catch (Exception e) {
                    log.error("RFID设备[{}]连接线程异常", config.getId(), e);
                    connected.set(false);
                    try {
                        Thread.sleep(reconnectInterval * 1000L);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
            log.info("RFID设备[{}]连接线程已停止", config.getId());
        }
        /**
         * 标签检测循环 - 持续检测并打印标签
         * 特别处理UnsatisfiedLinkError,确保DLL方法链接失败时不影响重连
         */
        private void scanLoop() {
            log.info("RFID设备[{}]标签检测线程启动 - IP: {}", config.getId(), config.getIp());
            while (running.get()) {
                try {
                    if (connected.get() && template.isConnected()) {
                        try {
                            List<TagInfo> tags = template.readTags(4, 0, tagScanTime);
                            latestTags = tags != null ? new ArrayList<>(tags) : new ArrayList<>();
                            if (tags != null && !tags.isEmpty()) {
                                printTags(tags);
                            }
                        } catch (UnsatisfiedLinkError e) {
                            // DLL方法链接失败,标记为未连接,让连接线程重连
                            log.error("RFID设备[{}]标签检测 - DLL方法链接失败", config.getId());
                            log.error("错误信息: {}", e.getMessage());
                            log.warn("连接状态已标记为断开,连接线程将尝试重连");
                            connected.set(false);
                            // 等待一段时间后继续
                            Thread.sleep(reconnectInterval * 1000L);
                            continue;
                        }
                    } else {
                        // 未连接,等待一段时间
                        Thread.sleep(1000);
                    }
                    // 等待指定间隔
                    Thread.sleep(tagScanInterval);
                } catch (InterruptedException e) {
                    log.info("RFID设备[{}]标签检测线程被中断", config.getId());
                    Thread.currentThread().interrupt();
                    break;
                } catch (UnsatisfiedLinkError e) {
                    // DLL方法链接失败,标记为未连接
                    log.error("RFID设备[{}]标签检测线程 - DLL方法链接失败", config.getId());
                    log.error("错误信息: {}", e.getMessage());
                    connected.set(false);
                    try {
                        Thread.sleep(reconnectInterval * 1000L);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                } catch (Exception e) {
                    log.error("RFID设备[{}]标签检测线程异常", config.getId(), e);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
            log.info("RFID设备[{}]标签检测线程已停止", config.getId());
        }
        private void printTags(List<TagInfo> tags) {
            if (tags == null || tags.isEmpty()) {
                return;
            }
            for (TagInfo tag : tags) {
                log.info("RFID设备[{}]检测到标签: EPC={}, RSSI={}dBm, 天线={}",
                        config.getId(), tag.epc, tag.rssi, tag.antenna);
            }
        }
    }
    /**
     * 系统启动时初始化所有配置了autoConnect=true的设备
     */
    @PostConstruct
    public void init() {
        log.info("========== RFID自动连接服务启动 ==========");
        if (slaveProperties.getRfid() == null || slaveProperties.getRfid().isEmpty()) {
            log.info("未配置RFID设备");
            return;
        }
        log.info("RFID全局配置 - 重连间隔: {}秒, 检测间隔: {}毫秒, 扫描时间: {} * 100ms",
                globalReconnectInterval, globalTagScanInterval, globalTagScanTime);
        // 遍历所有RFID设备配置
        for (RFIDSlave rfidConfigItem : slaveProperties.getRfid()) {
            if (rfidConfigItem == null) {
                continue;
            }
            // 检查是否启用自动连接
            Boolean autoConnect = rfidConfigItem.getAutoConnect();
            if (autoConnect == null || !autoConnect) {
                log.info("RFID设备[{}] - IP: {}, Port: {} - 未启用自动连接",
                        rfidConfigItem.getId(), rfidConfigItem.getIp(), rfidConfigItem.getPort());
                continue;
            }
            // 验证配置
            if (rfidConfigItem.getIp() == null || rfidConfigItem.getPort() == null) {
                log.warn("RFID设备[{}]配置不完整,跳过自动连接", rfidConfigItem.getId());
                continue;
            }
            // 创建设备管理器并启动
            DeviceManager manager = new DeviceManager(rfidConfigItem,
                    globalReconnectInterval, globalTagScanInterval, globalTagScanTime);
            deviceManagers.put(rfidConfigItem.getId(), manager);
            manager.start();
            log.info("RFID设备[{}]自动连接已启动 - IP: {}, Port: {}",
                    rfidConfigItem.getId(), rfidConfigItem.getIp(), rfidConfigItem.getPort());
        }
        log.info("RFID自动连接服务已启动,共 {} 个设备启用自动连接", deviceManagers.size());
    }
    /**
     * 手动停止所有RFID设备连接(通过API调用)
     * 注意:移除了@PreDestroy,服务不会自动关闭,只能通过API手动关闭
     */
    public void stopAll() {
        log.info("========== RFID自动连接服务手动关闭 ==========");
        // 停止所有设备管理器
        for (Map.Entry<Integer, DeviceManager> entry : deviceManagers.entrySet()) {
            try {
                log.info("停止RFID设备[{}]自动连接", entry.getKey());
                entry.getValue().stop();
            } catch (Exception e) {
                log.error("停止RFID设备[{}]自动连接异常", entry.getKey(), e);
            }
        }
        deviceManagers.clear();
        log.info("RFID自动连接服务已关闭");
    }
    /**
     * 手动停止指定RFID设备连接(通过API调用)
     */
    public boolean stopDevice(Integer deviceId) {
        DeviceManager manager = deviceManagers.get(deviceId);
        if (manager == null) {
            log.warn("RFID设备[{}]未启用自动连接或不存在", deviceId);
            return false;
        }
        try {
            log.info("手动停止RFID设备[{}]自动连接", deviceId);
            manager.stop();
            deviceManagers.remove(deviceId);
            return true;
        } catch (Exception e) {
            log.error("停止RFID设备[{}]自动连接异常", deviceId, e);
            return false;
        }
    }
    /**
     * 手动启动指定RFID设备连接(通过API调用)
     */
    public boolean startDevice(Integer deviceId) {
        // 检查设备是否已经在运行
        if (deviceManagers.containsKey(deviceId)) {
            DeviceManager manager = deviceManagers.get(deviceId);
            if (manager.running.get()) {
                log.warn("RFID设备[{}]已经在运行", deviceId);
                return false;
            }
        }
        // 查找配置
        RFIDSlave config = null;
        for (RFIDSlave rfidConfigItem : slaveProperties.getRfid()) {
            if (rfidConfigItem != null && rfidConfigItem.getId().equals(deviceId)) {
                config = rfidConfigItem;
                break;
            }
        }
        if (config == null) {
            log.warn("RFID设备[{}]配置不存在", deviceId);
            return false;
        }
        // 验证配置
        if (config.getIp() == null || config.getPort() == null) {
            log.warn("RFID设备[{}]配置不完整", deviceId);
            return false;
        }
        // 创建设备管理器并启动
        DeviceManager manager = new DeviceManager(config,
                globalReconnectInterval, globalTagScanInterval, globalTagScanTime);
        deviceManagers.put(deviceId, manager);
        manager.start();
        log.info("RFID设备[{}]手动启动成功 - IP: {}, Port: {}",
                deviceId, config.getIp(), config.getPort());
        return true;
    }
    /**
     * 获取设备连接状态
     */
    public Map<String, Object> getDeviceStatus(Integer deviceId) {
        Map<String, Object> result = new java.util.HashMap<>();
        DeviceManager manager = deviceManagers.get(deviceId);
        if (manager == null) {
            result.put("exists", false);
            result.put("message", "设备未启用自动连接");
            return result;
        }
        result.put("exists", true);
        result.put("connected", manager.connected.get());
        result.put("running", manager.running.get());
        result.put("ip", manager.config.getIp());
        result.put("port", manager.config.getPort());
        result.put("templateConnected", manager.template.isConnected());
        return result;
    }
    /**
     * 获取所有设备状态
     */
    public List<Map<String, Object>> getAllDeviceStatus() {
        List<Map<String, Object>> result = new ArrayList<>();
        for (Map.Entry<Integer, DeviceManager> entry : deviceManagers.entrySet()) {
            Map<String, Object> status = getDeviceStatus(entry.getKey());
            status.put("deviceId", entry.getKey());
            result.add(status);
        }
        return result;
    }
    /**
     * 重新配置指定设备的天线(用于天线插拔后重新配置)
     */
    public boolean reconfigureAntenna(Integer deviceId) {
        DeviceManager manager = deviceManagers.get(deviceId);
        if (manager == null) {
            log.warn("RFID设备[{}]未启用自动连接或不存在", deviceId);
            return false;
        }
        if (!manager.template.isConnected()) {
            log.warn("RFID设备[{}]未连接,无法配置天线", deviceId);
            return false;
        }
        log.info("手动重新配置RFID设备[{}]天线", deviceId);
        return manager.template.reconfigureAntenna();
    }
    public List<Map<String, Object>> getDeviceTags(Integer deviceId, String ip, Integer antenna) {
        List<Map<String, Object>> result = new ArrayList<>();
        DeviceManager manager = null;
        if (ip != null && !ip.isEmpty()) {
            for (DeviceManager m : deviceManagers.values()) {
                if (ip.equals(m.config.getIp())) {
                    manager = m;
                    break;
                }
            }
        } else if (deviceId != null) {
            manager = deviceManagers.get(deviceId);
        }
        if (manager == null || !manager.connected.get() || !manager.template.isConnected()) {
            return result;
        }
        List<TagInfo> tags = manager.latestTags;
        if (tags == null || tags.isEmpty()) {
            return result;
        }
        for (TagInfo tag : tags) {
            if (antenna != null && tag.antenna != antenna) {
                continue;
            }
            Map<String, Object> tagMap = new java.util.HashMap<>();
            tagMap.put("epc", tag.epc);
            tagMap.put("rssi", tag.rssi);
            tagMap.put("antenna", tag.antenna);
            tagMap.put("timestamp", tag.timestamp);
            tagMap.put("deviceId", manager.config.getId());
            tagMap.put("deviceIp", manager.config.getIp());
            result.add(tagMap);
        }
        return result;
    }
    public List<Map<String, Object>> queryDeviceTags(Integer deviceId, String ip, Integer antenna) {
        List<Map<String, Object>> result = new ArrayList<>();
        DeviceManager manager = null;
        if (ip != null && !ip.isEmpty()) {
            for (DeviceManager m : deviceManagers.values()) {
                if (ip.equals(m.config.getIp())) {
                    manager = m;
                    break;
                }
            }
        } else if (deviceId != null) {
            manager = deviceManagers.get(deviceId);
        }
        if (manager == null || !manager.connected.get() || !manager.template.isConnected()) {
            return result;
        }
        try {
            List<TagInfo> tags = manager.template.readTags(4, 0, manager.tagScanTime);
            if (tags != null && !tags.isEmpty()) {
                for (TagInfo tag : tags) {
                    if (antenna != null && tag.antenna != antenna) {
                        continue;
                    }
                    Map<String, Object> tagMap = new java.util.HashMap<>();
                    tagMap.put("epc", tag.epc);
                    tagMap.put("rssi", tag.rssi);
                    tagMap.put("antenna", tag.antenna);
                    tagMap.put("timestamp", tag.timestamp);
                    tagMap.put("deviceId", manager.config.getId());
                    tagMap.put("deviceIp", manager.config.getIp());
                    result.add(tagMap);
                }
            }
        } catch (Exception e) {
            log.error("查询RFID设备[{}]标签异常", deviceId != null ? deviceId : ip, e);
        }
        return result;
    }
}
src/main/java/com/zy/service/RFIDService.java
New file
@@ -0,0 +1,393 @@
package com.zy.service;
import com.rfid.uhf288.RFIDTemplate;
import com.rfid.uhf288.RFIDTemplate.TagInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * RFID服务类
 * 提供RFID设备检测功能
 * Created on 2026/01/10
 */
@Slf4j
@Service
public class RFIDService {
    private RFIDTemplate rfidTemplate;
    private String connectionType = ""; // "COM" 或 "NET"
    /**
     * 连接RFID设备(网络连接)
     *
     * @param ip IP地址
     * @param port 端口号
     * @return 连接结果
     */
    public Map<String, Object> connectNetwork(String ip, Integer port) {
        Map<String, Object> result = new HashMap<>();
        try {
            if (rfidTemplate == null) {
                rfidTemplate = new RFIDTemplate();
            }
            if (rfidTemplate.isConnected()) {
                result.put("success", false);
                result.put("message", "设备已连接,请先断开连接");
                return result;
            }
            int portNum = port != null ? port : 6000;
            boolean connected = rfidTemplate.connectNetwork(ip, portNum);
            if (connected) {
                connectionType = "NET";
                result.put("success", true);
                result.put("message", "连接成功");
                result.put("ip", ip);
                result.put("port", portNum);
                log.info("RFID设备网络连接成功 - IP: {}, Port: {}", ip, portNum);
            } else {
                result.put("success", false);
                result.put("message", "连接失败,请检查IP和端口");
            }
        } catch (UnsatisfiedLinkError e) {
            log.error("RFID设备DLL方法链接失败", e);
            result.put("success", false);
            result.put("message", "DLL方法链接失败: " + e.getMessage());
            result.put("errorType", "UnsatisfiedLinkError");
            result.put("suggestion", "请检查DLL文件是否正确,或尝试重启应用");
        } catch (Exception e) {
            log.error("RFID设备连接异常", e);
            result.put("success", false);
            result.put("message", "连接异常: " + e.getMessage());
        }
        return result;
    }
    /**
     * 连接RFID设备(串口连接)
     *
     * @param port 串口号 (1=COM1, 2=COM2, 3=COM3...)
     * @param baud 波特率 (0=9600, 1=19200, 2=38400, 3=57600, 4=115200, 5=230400, 6=460800, 7=921600)
     * @return 连接结果
     */
    public Map<String, Object> connectComPort(Integer port, Integer baud) {
        Map<String, Object> result = new HashMap<>();
        try {
            if (rfidTemplate == null) {
                rfidTemplate = new RFIDTemplate();
            }
            if (rfidTemplate.isConnected()) {
                result.put("success", false);
                result.put("message", "设备已连接,请先断开连接");
                return result;
            }
            int portNum = port != null ? port : 3; // 默认COM3
            boolean connected;
            if (baud != null && baud >= 0 && baud <= 7) {
                connected = rfidTemplate.connectComPort(portNum, baud.byteValue());
            } else {
                // 自动检测波特率
                connected = rfidTemplate.connectComPortAuto(portNum, -1);
            }
            if (connected) {
                connectionType = "COM";
                result.put("success", true);
                result.put("message", "连接成功");
                result.put("port", "COM" + portNum);
                log.info("RFID设备串口连接成功 - COM{}", portNum);
            } else {
                result.put("success", false);
                result.put("message", "连接失败,请检查串口和波特率");
            }
        } catch (UnsatisfiedLinkError e) {
            log.error("RFID设备DLL方法链接失败", e);
            result.put("success", false);
            result.put("message", "DLL方法链接失败: " + e.getMessage());
            result.put("errorType", "UnsatisfiedLinkError");
            result.put("suggestion", "请检查DLL文件是否正确,或尝试重启应用");
        } catch (Exception e) {
            log.error("RFID设备连接异常", e);
            result.put("success", false);
            result.put("message", "连接异常: " + e.getMessage());
        }
        return result;
    }
    /**
     * 检测RFID标签(单次检测)
     * 只在检测到标签时打印日志
     *
     * @param scanTime 扫描时间(单位: 100ms,默认5)
     * @return 检测结果
     */
    public Map<String, Object> detectTags(Integer scanTime) {
        Map<String, Object> result = new HashMap<>();
        List<Map<String, Object>> tagList = new ArrayList<>();
        try {
            if (rfidTemplate == null || !rfidTemplate.isConnected()) {
                result.put("success", false);
                result.put("message", "设备未连接,请先连接设备");
                return result;
            }
            int scanTimeValue = scanTime != null ? scanTime : 5; // 默认5*100ms=500ms
            List<TagInfo> tags = rfidTemplate.readTags(4, 0, scanTimeValue);
            if (tags != null && !tags.isEmpty()) {
                // 检测到标签时才打印日志
                for (TagInfo tag : tags) {
                    Map<String, Object> tagMap = new HashMap<>();
                    tagMap.put("epc", tag.epc);
                    tagMap.put("rssi", tag.rssi);
                    tagMap.put("antenna", tag.antenna);
                    tagMap.put("timestamp", tag.timestamp);
                    tagList.add(tagMap);
                    // 打印检测到的标签信息
                    log.info(">>> 检测到RFID标签 - EPC: {}, RSSI: {}dBm, 天线: {}",
                            tag.epc, tag.rssi, tag.antenna);
                }
                result.put("success", true);
                result.put("message", "检测到 " + tags.size() + " 个标签");
                result.put("count", tags.size());
                result.put("tags", tagList);
            } else {
                // 检测不到标签时不打印日志(只返回结果)
                result.put("success", true);
                result.put("message", "未检测到标签");
                result.put("count", 0);
                result.put("tags", tagList);
            }
        } catch (Exception e) {
            log.error("RFID标签检测异常", e);
            result.put("success", false);
            result.put("message", "检测异常: " + e.getMessage());
        }
        return result;
    }
    /**
     * 断开RFID设备连接
     *
     * @return 断开结果
     */
    public Map<String, Object> disconnect() {
        Map<String, Object> result = new HashMap<>();
        try {
            if (rfidTemplate != null && rfidTemplate.isConnected()) {
                rfidTemplate.disconnect();
                connectionType = "";
                result.put("success", true);
                result.put("message", "断开连接成功");
                log.info("RFID设备连接已断开");
            } else {
                result.put("success", false);
                result.put("message", "设备未连接");
            }
        } catch (Exception e) {
            log.error("RFID设备断开连接异常", e);
            result.put("success", false);
            result.put("message", "断开连接异常: " + e.getMessage());
        }
        return result;
    }
    /**
     * 获取连接状态
     *
     * @return 连接状态
     */
    public Map<String, Object> getConnectionStatus() {
        Map<String, Object> result = new HashMap<>();
        try {
            boolean connected = rfidTemplate != null && rfidTemplate.isConnected();
            result.put("connected", connected);
            result.put("connectionType", connected ? connectionType : "");
            result.put("message", connected ? "设备已连接" : "设备未连接");
        } catch (Exception e) {
            log.error("获取RFID连接状态异常", e);
            result.put("connected", false);
            result.put("message", "获取状态异常: " + e.getMessage());
        }
        return result;
    }
    /**
     * 诊断DLL加载状态
     *
     * @return 诊断信息
     */
    public Map<String, Object> diagnoseDll() {
        Map<String, Object> result = new HashMap<>();
        try {
            // 检查DLL文件是否存在(使用项目根目录的相对路径)
            String projectBaseDir = System.getProperty("user.dir");
            java.io.File dllFile1 = new java.io.File(projectBaseDir, "src/main/resources/lib/com_rfid_uhf288_Device.dll");
            java.io.File dllFile2 = new java.io.File(projectBaseDir, "src/main/resources/lib/UHFReader288.dll");
            // 也检查临时目录中的DLL文件
            String tempDir = System.getProperty("java.io.tmpdir");
            java.io.File tempDll1 = new java.io.File(tempDir + "rfid-lib/com_rfid_uhf288_Device.dll");
            java.io.File tempDll2 = new java.io.File(tempDir + "rfid-lib/UHFReader288.dll");
            Map<String, Object> dllInfo = new HashMap<>();
            Map<String, Object> sourceDll1 = new HashMap<>();
            sourceDll1.put("exists", dllFile1.exists());
            sourceDll1.put("size", dllFile1.exists() ? dllFile1.length() : 0);
            sourceDll1.put("path", dllFile1.getAbsolutePath());
            sourceDll1.put("tempExists", tempDll1.exists());
            sourceDll1.put("tempSize", tempDll1.exists() ? tempDll1.length() : 0);
            sourceDll1.put("tempPath", tempDll1.getAbsolutePath());
            if (dllFile1.exists() && tempDll1.exists()) {
                sourceDll1.put("sizeMatch", dllFile1.length() == tempDll1.length());
            }
            dllInfo.put("com_rfid_uhf288_Device.dll", sourceDll1);
            Map<String, Object> sourceDll2 = new HashMap<>();
            sourceDll2.put("exists", dllFile2.exists());
            sourceDll2.put("size", dllFile2.exists() ? dllFile2.length() : 0);
            sourceDll2.put("path", dllFile2.getAbsolutePath());
            sourceDll2.put("tempExists", tempDll2.exists());
            sourceDll2.put("tempSize", tempDll2.exists() ? tempDll2.length() : 0);
            sourceDll2.put("tempPath", tempDll2.getAbsolutePath());
            if (dllFile2.exists() && tempDll2.exists()) {
                sourceDll2.put("sizeMatch", dllFile2.length() == tempDll2.length());
            }
            dllInfo.put("UHFReader288.dll", sourceDll2);
            result.put("dllFiles", dllInfo);
            // 检查Device类是否可以实例化
            boolean deviceCreated = false;
            String deviceError = null;
            try {
                if (rfidTemplate == null) {
                    rfidTemplate = new RFIDTemplate();
                }
                deviceCreated = true;
            } catch (Exception e) {
                deviceError = e.getMessage();
            }
            result.put("deviceCreated", deviceCreated);
            if (deviceError != null) {
                result.put("deviceError", deviceError);
            }
            // 检查native方法是否可用(实际尝试调用验证)
            boolean nativeMethodAvailable = false;
            String nativeMethodError = null;
            if (deviceCreated && rfidTemplate != null) {
                try {
                    // 实际尝试调用native方法来验证(使用无效参数,只测试方法链接)
                    // 如果方法不存在或链接失败,会抛出UnsatisfiedLinkError
                    boolean wasConnected = rfidTemplate.isConnected();
                    if (!wasConnected) {
                        // 尝试连接一个无效的IP地址,只测试native方法是否可用
                        // 注意:这里会失败,但我们只关心方法是否链接成功
                        try {
                            // 调用connectNetwork,如果native方法链接失败会抛出UnsatisfiedLinkError
                            boolean connected = rfidTemplate.connectNetwork("127.0.0.1", 9999);
                            // 如果执行到这里,说明native方法链接成功(即使连接失败)
                            nativeMethodAvailable = true;
                            // 如果意外连接成功,断开连接
                            if (connected) {
                                rfidTemplate.disconnect();
                            }
                        } catch (UnsatisfiedLinkError e) {
                            // 如果抛出UnsatisfiedLinkError,说明native方法链接失败
                            nativeMethodError = "DLL native方法链接失败: " + e.getMessage();
                            nativeMethodAvailable = false;
                        } catch (Exception e) {
                            // 其他异常(如连接失败、网络错误等)是正常的,说明方法链接成功
                            // 检查异常类型,UnsatisfiedLinkError应该已经被上面的catch捕获
                            if (e.getCause() instanceof UnsatisfiedLinkError) {
                                nativeMethodError = "DLL native方法链接失败: " + e.getCause().getMessage();
                                nativeMethodAvailable = false;
                            } else {
                                // 其他异常说明方法链接成功,只是调用失败
                                nativeMethodAvailable = true;
                            }
                        }
                    } else {
                        // 如果已经连接,说明之前调用过native方法,方法应该是可用的
                        nativeMethodAvailable = true;
                    }
                } catch (UnsatisfiedLinkError e) {
                    nativeMethodError = "DLL native方法链接失败: " + e.getMessage();
                    nativeMethodAvailable = false;
                } catch (Exception e) {
                    // 其他异常不影响判断
                    if (nativeMethodError == null) {
                        nativeMethodError = "验证异常: " + e.getMessage();
                    }
                }
            }
            result.put("nativeMethodAvailable", nativeMethodAvailable);
            if (nativeMethodError != null) {
                result.put("nativeMethodError", nativeMethodError);
            }
            // 提供建议
            List<String> suggestions = new ArrayList<>();
            if (!dllFile1.exists()) {
                suggestions.add("DLL文件不存在: com_rfid_uhf288_Device.dll");
                suggestions.add("请检查 src/main/resources/lib/ 目录");
            } else {
                suggestions.add("DLL文件存在: com_rfid_uhf288_Device.dll (大小: " + dllFile1.length() + " 字节)");
                // 检查DLL文件是否可能是文本文件(被Maven过滤损坏)
                if (dllFile1.length() < 1000) {
                    suggestions.add("警告:DLL文件大小异常小,可能被损坏");
                }
            }
            if (!deviceCreated) {
                suggestions.add("Device类实例化失败,请检查DLL文件是否存在");
            } else if (!nativeMethodAvailable) {
                suggestions.add("DLL已加载,但native方法不可用");
                suggestions.add("错误信息: " + (nativeMethodError != null ? nativeMethodError : "未知错误"));
                suggestions.add("可能原因:1. DLL版本不匹配 2. 方法签名不匹配 3. DLL文件损坏");
                suggestions.add("解决方案:");
                suggestions.add("1. 从demo项目(testdemo-jni)中复制DLL文件到当前项目");
                suggestions.add("2. 确保DLL文件没有被Maven资源过滤处理");
                suggestions.add("3. 检查DLL文件大小是否与demo项目中的一致");
                suggestions.add("4. 尝试重新编译项目: mvn clean compile");
                suggestions.add("5. 检查临时目录中的DLL文件: " + System.getProperty("java.io.tmpdir") + "rfid-lib");
            } else {
                suggestions.add("DLL加载正常,native方法可用");
            }
            result.put("suggestions", suggestions);
            result.put("message", nativeMethodAvailable ? "DLL状态正常" : "DLL状态异常");
        } catch (Exception e) {
            log.error("RFID DLL诊断异常", e);
            result.put("error", "诊断异常: " + e.getMessage());
        }
        return result;
    }
}
src/main/resources/application-dev.yml
@@ -635,4 +635,35 @@
    port: 5005
    devpPlcId: ${wcs-slave.devp[1].id}
    staArr: 107
    crnId: 2
    crnId: 2
  # RFID读写器配置
  rfid-config:
    # 全局默认配置
    reconnectInterval: 10  # 重连间隔(秒)
    tagScanInterval: 500   # 标签检测间隔(毫秒)
    tagScanTime: 10        # 标签扫描时间(单位: 100ms,默认10=1秒)
  # RFID读写器1
  rfid[0]:
    id: 1
    ip: 10.10.10.210
    port: 27011
    autoConnect: true      # 是否自动连接(true: 系统启动时自动连接,false: 手动连接)
  # RFID读写器2
  rfid[1]:
    id: 2
    ip: 10.10.10.211
    port: 27011
    autoConnect: true     # 是否自动连接
  # RFID读写器3
  rfid[2]:
    id: 3
    ip: 10.10.10.212
    port: 27011
    autoConnect: true     # 是否自动连接
  # RFID读写器4
  rfid[3]:
    id: 4
    ip: 10.10.10.213
    port: 27011
    autoConnect: true     # 是否自动连接
src/main/resources/application-prod.yml
@@ -635,4 +635,35 @@
    port: 5005
    devpPlcId: ${wcs-slave.devp[1].id}
    staArr: 107
    crnId: 2
    crnId: 2
  # RFID读写器配置
  rfid-config:
    # 全局默认配置
    reconnectInterval: 10  # 重连间隔(秒)
    tagScanInterval: 500   # 标签检测间隔(毫秒)
    tagScanTime: 10        # 标签扫描时间(单位: 100ms,默认10=1秒)
  # RFID读写器1
  rfid[0]:
    id: 1
    ip: 10.10.10.210
    port: 27011
    autoConnect: true      # 是否自动连接(true: 系统启动时自动连接,false: 手动连接)
  # RFID读写器2
  rfid[1]:
    id: 2
    ip: 10.10.10.211
    port: 27011
    autoConnect: true     # 是否自动连接
  # RFID读写器3
  rfid[2]:
    id: 3
    ip: 10.10.10.212
    port: 27011
    autoConnect: true     # 是否自动连接
  # RFID读写器4
  rfid[3]:
    id: 4
    ip: 10.10.10.213
    port: 27011
    autoConnect: true     # 是否自动连接
src/main/resources/lib/UHFReader288.dll
Binary files differ
src/main/resources/lib/com_rfid_uhf288_Device.dll
Binary files differ