From 0d9956362ef415d0b49318746e9a2ef955dcfebd Mon Sep 17 00:00:00 2001
From: 上海郢昱 <15922366+miu-haiqing@user.noreply.gitee.com>
Date: 星期二, 15 九月 2026 08:36:45 +0800
Subject: [PATCH] 质检设备数采功能实现

---
 src/main/java/com/hwtd/mes/collect/controller/DataCollectionController.java    |   79 +++
 src/main/java/com/hwtd/mes/collect/DataAcquisitionApplication.java             |    2 
 src/main/java/com/hwtd/mes/collect/service/DataCollectionService.java          |   14 
 src/main/resources/META-INF/MANIFEST.MF                                        |    2 
 src/main/java/com/hwtd/mes/collect/dto/SerialPortDTO.java                      |   66 ++
 src/main/java/com/hwtd/mes/collect/service/impl/DataCollectionServiceImpl.java |  159 ++++++
 pom.xml                                                                        |   12 
 README.md                                                                      |   45 +
 /dev/null                                                                      |  231 ----------
 src/main/java/com/hwtd/mes/collect/config/TomcatConfig.java                    |    2 
 src/main/java/com/hwtd/mes/collect/constant/CommonConstants.java               |    2 
 src/main/java/com/hwtd/mes/collect/util/Result.java                            |    4 
 src/main/java/com/hwtd/mes/collect/handler/GlobalExceptionHandler.java         |    4 
 src/main/java/com/hwtd/mes/collect/handler/SerialPortListener.java             |  644 ++++++++++++++++++++++++++++
 src/main/resources/application.yml                                             |    6 
 src/main/java/com/hwtd/mes/collect/dto/DatabaseDTO.java                        |   75 +++
 src/test/java/com/hwtd/mes/collect/DataAcquisitionApplicationTests.java        |    2 
 17 files changed, 1,102 insertions(+), 247 deletions(-)

diff --git a/README.md b/README.md
index 30f4f71..c602ddf 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,47 @@
 ## data-acquisition
 
-璁惧鏁版嵁閲囬泦鍣�
+浜ㄦ椇鐗瑰MES鏁版嵁閲囬泦鍣�
 
+### 涓插彛閲囬泦锛堟墜鍔ㄧ洃鍚級
+
+涓插彛涓嶅啀闅忛」鐩惎鍔ㄨ嚜鍔ㄧ洃鍚紝鏀逛负鎵嬪姩鐩戝惉锛氳皟鐢ㄩ噰闆嗘帴鍙f椂寮�鍚洃鍚紝閲囬泦缁撴潫鍚庤皟鐢ㄥ叧闂帴鍙c��
+
+| 鎺ュ彛 | 璇存槑 |
+| --- | --- |
+| `GET /lims/getFile?fileExtension=.serialPort` | 閲囬泦鎺ュ彛锛氳皟鐢ㄦ椂鑷姩寮�鍚洃鍚紝骞惰繑鍥炴湰娆¢噰闆嗗埌鐨勬暟鎹紱娌℃湁鏁版嵁鏃惰繑鍥炵┖闆嗗悎锛岀敱鍓嶇杞鍙栨暟 |
+| `GET /lims/openSerialPort` | 鎵嬪姩寮�鍚洃鍚紝骞惰繑鍥炲綋鍓嶆帴鏀跺埌鐨勬暟鎹垪琛紙骞傜瓑锛屽弬鏁颁竴鑷存椂澶嶇敤宸叉墦寮�鐨勪覆鍙o級 |
+| `GET /lims/closeSerialPort` | 鎵嬪姩鍏抽棴鐩戝惉锛堝箓绛夛紝閲囬泦缁撴潫鍚庤皟鐢紝閬垮厤涓插彛涓�鐩磋鍗犵敤锛� |
+| `GET /lims/serialPortStatus` | 鏌ヨ鐩戝惉鐘舵�侊細`listenName` / `listening` / `portOpen` / `dataSize` |
+
+涓插彛鍙傛暟鍏ㄩ儴鐢辨帴鍙d紶鍏ワ紝`/lims/getFile`锛坄fileExtension=.serialPort` 鏃讹級鍜� `/lims/openSerialPort` 閮芥敮鎸侊紝
+涓嶄紶鐨勫瓧娈典娇鐢ㄩ粯璁ゅ�硷紙`listenName` 蹇呬紶锛夈�俛pplication.yml 涓殑 `serialPort` 閰嶇疆宸蹭笉鍐嶇敓鏁堬紝鍙互鍒犻櫎銆�
+
+| 鍙傛暟 | 榛樿鍊� | 璇存槑 |
+| --- | --- | --- |
+| `listenName` | 蹇呬紶 | 涓插彛鍚嶇О锛屽 `COM12`锛涗笉浼犱細杩斿洖鈥滀覆鍙e悕绉颁笉鑳戒负绌衡�� |
+| `baudRate` | `9600` | 娉㈢壒鐜� |
+| `dataBits` | `8` | 鏁版嵁浣嶏紝5~8 |
+| `stopBits` | `1` | 鍋滄浣嶏紝1銆�2銆�3(1.5 浣�) |
+| `parity` | `NONE` | 鏍¢獙浣嶏細`NONE`/`ODD`/`EVEN`/`MARK`/`SPACE`锛屼篃鍏煎 0~4 |
+| `flowControl` | `NONE` | 娴佹帶锛歚NONE`/`RTS_CTS`/`XON_XOFF`锛屼篃鍏煎鏁板瓧甯搁噺 |
+| `readTimeout` | `1000` | 璇诲彇瓒呮椂锛堟绉掞級 |
+| `endMark` | `*` | 涓�甯ф暟鎹殑缁撴潫鏍囧織锛岀壒娈婂瓧绗︾敤 URL 缂栫爜锛屽鎹㈣ `%0A` |
+| `maxCount` | `6` | 鏁版嵁缂撳瓨闃熷垪闀垮害锛氶槦鍒楁弧鏃舵彃鍏ユ渶鏂颁竴鏉°�佺Щ闄ゆ渶鏃т竴鏉� |
+| `frameIdleMillis` | `200` | 甯х┖闂茶ˉ甯ф椂闂达紙姣锛夛細瓒呰繃璇ユ椂闂存病鏈夋柊鏁版嵁锛屽氨鎶婄紦鍐插尯鍓╀綑鏁版嵁褰撴垚涓�甯у彇鍑猴紱`0` 琛ㄧず鍏抽棴 |
+
+绀轰緥锛歚/lims/getFile?fileExtension=.serialPort&listenName=COM12&baudRate=19200&parity=EVEN&endMark=%0A&maxCount=6`
+
+鍙傛暟涓庡綋鍓嶇敓鏁堝弬鏁颁竴鑷存椂澶嶇敤宸茬粡鎵撳紑鐨勪覆鍙o紙涓嶄細閲嶅鎵撳紑锛夛紱鍙傛暟鍙樺寲鏃朵細鑷姩鎸夋柊鍙傛暟閲嶆柊鎵撳紑涓插彛锛�
+鍙傛暟闈炴硶鏃舵帴鍙g洿鎺ヨ繑鍥炲叿浣撳師鍥狅紙濡� `涓插彛鍙傛暟 dataBits 闈炴硶锛�9锛屽彇鍊艰寖鍥� 5~8`锛夈��
+
+閲囬泦鍒扮殑鏁版嵁鎸夐槦鍒楃紦瀛橈細鎻掑叆鏈�鏂扮殑涓�鏉★紝瓒呰繃 `maxCount` 鏉★紙榛樿 6 鏉★級鏃剁Щ闄ゆ渶鏃х殑涓�鏉★紝
+鍥犳鎺ュ彛姣忔鏈�澶氳繑鍥� `maxCount` 鏉℃渶鏂扮殑鏁版嵁锛堟寜鎺ユ敹鍏堝悗椤哄簭锛夛紱鏁版嵁琚彇璧板悗闃熷垪娓呯┖锛岄噸鏂板紑濮嬬紦瀛樸��
+
+鏁版嵁甯ф寜 `endMark` 鍒囧垎銆傚鏋滆澶囨槸銆屾瘡甯т互鏌愪釜瀛楃寮�澶淬�嶈�屼笉鏄粨灏撅紙渚嬪鍙� `*0 1 0`銆乣*0 2 0`锛�
+`*` 鐢ㄤ簬鍒嗛殧鍓嶅悗涓ゅ抚锛夛紝閭d箞鏈�鍚庝竴甯у悗闈㈡病鏈夋柊鐨� `*` 鏉ヨЕ鍙戝垏鍒嗭紝鍙潬缁撴潫鏍囧織浼氭紡鎺夋渶鍚庝竴鏉★紱
+姝ゆ椂鐢� `frameIdleMillis`锛堥粯璁� 200ms锛夊厹搴曪細涓插彛绌洪棽瓒呰繃璇ユ椂闂村悗锛屾妸鎺ユ敹缂撳啿鍖洪噷鍓╀笅鐨勬暟鎹綋浣滀竴甯у彇鍑恒��
+濡傛灉璁惧姣忓抚閮戒互缁撴潫鏍囧織缁撳熬锛岀紦鍐插尯姣忔鍒囧垎鍚庨兘鏄┖鐨勶紝绌洪棽琛ュ抚涓嶄細鍋氫换浣曚簨銆�
+
+骞跺彂璇存槑锛氬紑鍚� / 鍏抽棴涓插彛鐢卞悓涓�鎶婇攣淇濇姢锛屽绾跨▼骞跺彂璋冪敤閲囬泦鎺ュ彛涔熷彧浼氭墦寮�涓�娆′覆鍙o紝涓嶄細閲嶅娉ㄥ唽鐩戝惉鍣紱
+閲囬泦缁撴灉瀛樻斁鍦ㄥ悓姝ラ泦鍚堜腑锛屽绾跨▼鍚屾椂鍙栨暟鏃跺悓涓�鏉℃暟鎹彧浼氳涓�涓嚎绋嬪彇璧帮紝涓嶄細閲嶅涔熶笉浼氫涪澶便��
+璋冪敤鍏抽棴鎺ュ彛鍚庡啀娆¤皟鐢ㄩ噰闆嗘帴鍙d細閲嶆柊寮�鍚洃鍚紝骞舵竻鎺変笂涓�杞畫鐣欑殑鍗婂寘鏁版嵁鍜屾湭鍙栬蛋鐨勬暟鎹紝淇濊瘉姣忔閲囬泦鐨勬暟鎹彧灞炰簬鏈疆銆�
diff --git a/pom.xml b/pom.xml
index 2a51f47..7ff87b0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -38,6 +38,16 @@
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+            <version>42.7.7</version> <!-- 寤鸿浣跨敤杈冩柊绋冲畾鐗� -->
+        </dependency>
+        <dependency>
+        <groupId>com.zaxxer</groupId>
+        <artifactId>HikariCP</artifactId>
+        <version>4.0.3</version>
+    </dependency>
         <!--lombok-->
         <dependency>
             <groupId>org.projectlombok</groupId>
@@ -148,7 +158,7 @@
                 <artifactId>spring-boot-maven-plugin</artifactId>
                 <version>${spring-boot.version}</version>
                 <configuration>
-                    <mainClass>com.chinaztt.mes.docx.DataAcquisitionApplication</mainClass>
+                    <mainClass>com.hwtd.mes.collect.DataAcquisitionApplication</mainClass>
                     <skip>false</skip>
                 </configuration>
                 <executions>
diff --git a/src/main/java/com/chinaztt/mes/docx/config/SerialPortStartupRunner.java b/src/main/java/com/chinaztt/mes/docx/config/SerialPortStartupRunner.java
deleted file mode 100644
index a896d22..0000000
--- a/src/main/java/com/chinaztt/mes/docx/config/SerialPortStartupRunner.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.chinaztt.mes.docx.config;
-
-import com.chinaztt.mes.docx.handler.SerialPortListener;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.ApplicationArguments;
-import org.springframework.boot.ApplicationRunner;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-/**
- * 椤圭洰鍚姩瀹屾垚鍚庢墽琛屼覆鍙g洃鍚�
- */
-@Slf4j
-@Component
-public class SerialPortStartupRunner implements ApplicationRunner {
-
-    @Value("${serialPort.enable}")
-    public Boolean enableSerialPort;
-
-    @Resource
-    private SerialPortListener serialPortListenerService;
-
-    @Autowired
-    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
-
-    @Override
-    public void run(ApplicationArguments args) {
-        log.info("===== SpringBoot 椤圭洰鍚姩瀹屾垚锛屽紑濮嬪垵濮嬪寲涓插彛鐩戝惉 =====");
-        // 鍚姩涓插彛鐩戝惉锛堟牳蹇冭皟鐢級
-        if(enableSerialPort)threadPoolTaskExecutor.execute(() -> serialPortListenerService.serialPortDataListener());
-    }
-}
diff --git a/src/main/java/com/chinaztt/mes/docx/constant/FieldMatchRuleConstants.java b/src/main/java/com/chinaztt/mes/docx/constant/FieldMatchRuleConstants.java
deleted file mode 100644
index 652499c..0000000
--- a/src/main/java/com/chinaztt/mes/docx/constant/FieldMatchRuleConstants.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.chinaztt.mes.docx.constant;
-
-/**
- * 閲囬泦鍦板潃鏂囦欢鍚嶅尮閰嶈鍒�
- */
-public class FieldMatchRuleConstants {
-
-    public FieldMatchRuleConstants() {
-    }
-
-    /**
-     * 濮旀墭缂栧彿(绛変簬)
-     */
-    public final static String ENTRUST_CODE_EQUAL = "entrustCodeEqual";
-
-    /**
-     * 濮旀墭缂栧彿(鍖呭惈浜�)
-     */
-    public final static String ENTRUST_CODE_LIKE = "entrustCodeLike";
-
-    /**
-     * 鏍峰搧缂栧彿(绛変簬)
-     */
-    public final static String SAMPLE_CODE_EQUAL = "sampleCodeEqual";
-
-    /**
-     * 鏍峰搧缂栧彿(鍖呭惈浜�)
-     */
-    public final static String SAMPLE_CODE_LIKE = "sampleCodeLike";
-}
diff --git a/src/main/java/com/chinaztt/mes/docx/controller/DocxController.java b/src/main/java/com/chinaztt/mes/docx/controller/DocxController.java
deleted file mode 100644
index 7c4e04d..0000000
--- a/src/main/java/com/chinaztt/mes/docx/controller/DocxController.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.chinaztt.mes.docx.controller;
-
-import com.chinaztt.mes.docx.dto.GetFileDto;
-import com.chinaztt.mes.docx.service.DocxService;
-import com.chinaztt.mes.docx.util.Result;
-import net.sourceforge.tess4j.TesseractException;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.io.IOException;
-import java.sql.SQLException;
-
-@RestController
-@RequestMapping("/lims")
-public class DocxController {
-
-    @Autowired
-    private DocxService docxService;
-
-    @GetMapping("/getFile")
-    public Result<?> getFile(GetFileDto getFileDto) throws IOException, SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException, TesseractException {
-        return docxService.getFile(getFileDto);
-    }
-
-    @GetMapping("/moveFile")
-    public Result<?> moveFile(String startFilePath, String endFilePath, String fileType) {
-        return docxService.moveFile(startFilePath, endFilePath, fileType);
-    }
-
-    @GetMapping("/readXml")
-    public void readXml() {
-         docxService.readXml();
-    }
-
-}
diff --git a/src/main/java/com/chinaztt/mes/docx/dto/GetFileDto.java b/src/main/java/com/chinaztt/mes/docx/dto/GetFileDto.java
deleted file mode 100644
index 30fa2b0..0000000
--- a/src/main/java/com/chinaztt/mes/docx/dto/GetFileDto.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.chinaztt.mes.docx.dto;
-
-import lombok.Data;
-
-@Data
-public class GetFileDto {
-    // 閲囬泦璺緞
-    private String filePath;
-    // 鏂囦欢鍚庣紑
-    private String fileExtension;
-    // 濮旀墭鍗曞彿
-    private String entrustCode;
-    // 鏍峰搧缂栧彿
-    private String sampleCode;
-    // 濮旀墭缂栧彿瀛楁
-    private String mdbEntrustCode;
-    // 鏍峰搧缂栧彿瀛楁
-    private String mdbSampleCode;
-    // db鏂囦欢鍚嶇О
-    private String dbFileName;
-    // 鍏夌氦甯﹀瓧娈�
-    private String fiberOpticRibbonCode;
-    // 鍏夌氦甯︽暟鎹�
-    private String fiberOpticRibbon;
-    // 绠″鑹叉爣瀛楁
-    private String bushingColorField;
-    // 绠″鑹叉爣鏁版嵁
-    private String bushingColor;
-    //鏁版嵁搴撶敤鎴峰悕
-    private String dbUserName;
-    //鏁版嵁搴撳瘑鐮�
-    private String dbPassword;
-    //鏁版嵁搴撹〃鍚�
-    private String dbTable;
-
-    //鎵规鍙�
-    private String lotBatchNo;
-
-    //鐢电紗棰滆壊鏍囪瘑
-    private String cableTag;
-
-    /**
-     * 杩藉姞鏈熬sql
-     */
-    private String lastSql;
-
-    /**
-     * 鏄惁鍖归厤鏂囦欢鍚嶇О
-     */
-    private Boolean isMatchFileName;
-
-    /**
-     * 鍖归厤瑙勫垯锛氱瓑浜�/鍖呭惈
-     */
-    private String fieldMatchRule;
-
-}
diff --git a/src/main/java/com/chinaztt/mes/docx/handler/SerialPortListener.java b/src/main/java/com/chinaztt/mes/docx/handler/SerialPortListener.java
deleted file mode 100644
index d0edcff..0000000
--- a/src/main/java/com/chinaztt/mes/docx/handler/SerialPortListener.java
+++ /dev/null
@@ -1,145 +0,0 @@
-package com.chinaztt.mes.docx.handler;
-
-import com.fazecast.jSerialComm.SerialPort;
-import com.fazecast.jSerialComm.SerialPortDataListener;
-import com.fazecast.jSerialComm.SerialPortEvent;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-
-@Slf4j
-@Component
-public class SerialPortListener {
-
-    // 涓插彛鏍稿績瀵硅薄
-    private static SerialPort serialPort;
-
-    // 瀹氫箟缂撳啿鍖猴紝鏆傚瓨闆舵暎鏁版嵁
-    private static final StringBuilder dataBuffer = new StringBuilder();
-
-    // 瀹氫箟鏁版嵁缁撴潫鏍囧織
-    private static final String END_MARK = "g";
-
-    public List<Double> dataList = new ArrayList<>(6);
-
-    private static final int MAX_COUNT = 6;
-
-    @Value("${serialPort.listenName}")
-    public String listenName;
-
-    // 鏍囪鐩戝惉鏄惁杩愯
-    private volatile boolean isListening = false;
-
-    public void serialPortDataListener(){
-        // 鍙岄噸鏍¢獙閿侊紝閬垮厤閲嶅鍚姩
-        if (isListening) {
-            log.warn("涓插彛 {} 鐩戝惉宸插惎鍔紝鏃犻渶閲嶅鎵ц", listenName);
-            return;
-        }
-
-        synchronized (this) {
-            if (isListening) {
-                return;
-            }
-            isListening = true;
-        }
-
-        // 2. 閫夋嫨鐩爣涓插彛
-        String targetPortName = listenName;
-        serialPort = SerialPort.getCommPort(targetPortName);
-
-        // 3. 閰嶇疆涓插彛鍙傛暟锛堥渶涓庤澶囩涓�鑷达級
-        serialPort.setBaudRate(9600);       // 娉㈢壒鐜�
-        serialPort.setNumDataBits(8);       // 鏁版嵁浣�
-        serialPort.setNumStopBits(1);       // 鍋滄浣�
-        serialPort.setParity(SerialPort.NO_PARITY); // 鏍¢獙浣嶏紙鏃犳牎楠岋級
-        serialPort.setFlowControl(SerialPort.NO_PARITY); // 鍏抽棴娴佹帶
-        serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 1000, 0); // 璇诲彇瓒呮椂
-
-        // 4. 鎵撳紑涓插彛
-        if (serialPort.openPort()) {
-            log.info("涓插彛鎵撳紑鎴愬姛锛歿}",targetPortName);
-        } else {
-            log.error("涓插彛鎵撳紑澶辫触锛佽妫�鏌ヤ覆鍙f槸鍚﹁鍗犵敤鎴栧悕绉版槸鍚︽纭�");
-            isListening = false;
-            return;
-        }
-
-        // 5. 娉ㄥ唽涓插彛鏁版嵁鐩戝惉鍣紙寮傛璇诲彇锛岄伩鍏嶉樆濉炰富绾跨▼锛�
-        try {
-            serialPort.addDataListener(new SerialPortDataListener() {
-                // 鎸囧畾鐩戝惉鐨勪簨浠剁被鍨嬶細鏁版嵁鍙敤鏃惰Е鍙�
-                @Override
-                public int getListeningEvents() {
-                    return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;
-                }
-
-                // 鏁版嵁鍙敤鏃剁殑澶勭悊閫昏緫
-                @Override
-                public void serialEvent(SerialPortEvent event) {
-                    if (event.getEventType() == SerialPort.LISTENING_EVENT_DATA_AVAILABLE) {
-                        // 璇诲彇缂撳啿鍖轰腑鐨勬墍鏈夊瓧鑺�
-                        byte[] buffer = new byte[serialPort.bytesAvailable()];
-                        int readBytes = serialPort.readBytes(buffer, buffer.length);
-
-                        if (readBytes > 0) {
-                            // 鎶婃湰娆℃敹鍒扮殑闆舵暎鏁版嵁杞垚瀛楃涓诧紝杩藉姞鍒扮紦鍐插尯
-                            String received = new String(buffer, 0, readBytes, StandardCharsets.UTF_8);
-                            dataBuffer.append(received);
-
-                            // 妫�鏌ョ紦鍐插尯鏄惁鍖呭惈鈥滅粨鏉熸爣蹇椻�濓紝寰幆澶勭悊鎵�鏈夊畬鏁存暟鎹�
-                            int endIndex = dataBuffer.indexOf(END_MARK);
-                            while (endIndex != -1) {
-                                // 鎻愬彇鈥滃紑澶村埌缁撴潫鏍囧織鈥濈殑瀹屾暣鏁版嵁
-                                String completeData = dataBuffer.substring(0, endIndex).replace(" ", "").replace("\n","");
-                                // 鎵撳嵃/澶勭悊鍚堝苟鍚庣殑瀹屾暣鏁版嵁
-                                double parseDouble = Double.parseDouble(completeData);
-                                log.info("鎺ユ敹鍒扮殑鏁版嵁-->{}",parseDouble);
-                                if(dataList.size()<MAX_COUNT){
-                                    dataList.add(parseDouble);
-                                }
-                                // 绉婚櫎缂撳啿鍖轰腑宸插鐞嗙殑閮ㄥ垎锛堜繚鐣欏墿浣欐湭瀹屾垚鐨勫唴瀹癸級
-                                dataBuffer.delete(0, endIndex + END_MARK.length());
-                                // 缁х画妫�鏌ョ紦鍐插尯鏄惁杩樻湁鍏朵粬瀹屾暣鏁版嵁
-                                endIndex = dataBuffer.indexOf(END_MARK);
-                            }
-                        }
-                    }
-                }
-            });
-        } catch (Exception e) {
-            log.warn("涓插彛鐩戝惉瀛愮嚎绋嬭涓柇", e);
-            Thread.currentThread().interrupt();
-        }
-    }
-
-    /**
-     * 鍏抽棴涓插彛
-     */
-    private void closeSerialPort() {
-        if (serialPort != null && serialPort.isOpen()) {
-            serialPort.removeDataListener(); // 绉婚櫎鐩戝惉
-            serialPort.closePort(); // 鍏抽棴涓插彛
-            log.info("涓插彛 {} 宸插叧闂�", listenName);
-        }
-        isListening = false;
-    }
-
-    /**
-     * 椤圭洰鍋滄鏃跺叧闂覆鍙�
-     */
-    @PreDestroy
-    public void destroy() {
-        log.info("椤圭洰鍋滄锛屽叧闂覆鍙� {} 鐩戝惉", listenName);
-        isListening = false; // 缁堟瀛愮嚎绋嬪惊鐜�
-        closeSerialPort();
-    }
-
-}
diff --git a/src/main/java/com/chinaztt/mes/docx/pojo/Chemical.java b/src/main/java/com/chinaztt/mes/docx/pojo/Chemical.java
deleted file mode 100644
index ce15cfc..0000000
--- a/src/main/java/com/chinaztt/mes/docx/pojo/Chemical.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.chinaztt.mes.docx.pojo;
-
-import lombok.Data;
-
-import java.io.Serializable;
-import java.util.Date;
-
-/**
- * @Description 鍖栧鎴愬垎淇℃伅
- * @Author fz
- **/
-@Data
-public class Chemical implements Serializable {
-
-    private String name;// 鍏冪礌鍚�
-    private String value = "-";// 妫�楠屾暟鍊�
-    private String record = "-";// 璁板綍鏁板��
-    private String detail = "-";// 鏍囧噯鏄庣粏
-    private String result = "-";// 妫�楠岀粨璁�
-    private Date testTime;
-    private Date equipmentTime;
-}
diff --git a/src/main/java/com/chinaztt/mes/docx/pojo/TestBatch.java b/src/main/java/com/chinaztt/mes/docx/pojo/TestBatch.java
deleted file mode 100644
index 9a0f6c2..0000000
--- a/src/main/java/com/chinaztt/mes/docx/pojo/TestBatch.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.chinaztt.mes.docx.pojo;
-
-import lombok.Data;
-
-import java.io.Serializable;
-import java.util.Date;
-import java.util.List;
-
-/**
- * @Description 鍏夎氨浠笂鐨勬楠屼俊鎭�
- * @Author fz
- **/
-@Data
-public class TestBatch implements Serializable {
-
-    private String batchNo;// 妫�楠屾壒娆′俊鎭�
-    private Date equipmentTime;// 璁板綍鏃堕棿
-    private List<Chemical> chemicals;// 鍖栧鎴愬垎鍒楄〃
-}
diff --git a/src/main/java/com/chinaztt/mes/docx/service/DocxService.java b/src/main/java/com/chinaztt/mes/docx/service/DocxService.java
deleted file mode 100644
index 7b6d49d..0000000
--- a/src/main/java/com/chinaztt/mes/docx/service/DocxService.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.chinaztt.mes.docx.service;
-
-import com.chinaztt.mes.docx.dto.GetFileDto;
-import com.chinaztt.mes.docx.util.Result;
-import net.sourceforge.tess4j.TesseractException;
-
-import java.io.IOException;
-import java.sql.SQLException;
-
-public interface DocxService {
-    Result<?> getFile(GetFileDto getFileDto) throws IOException, SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException, TesseractException;
-
-    Result<?> moveFile(String startFilePath, String endFilePath, String fileType);
-
-    void readXml();
-
-}
diff --git a/src/main/java/com/chinaztt/mes/docx/service/impl/DocxServiceImpl.java b/src/main/java/com/chinaztt/mes/docx/service/impl/DocxServiceImpl.java
deleted file mode 100644
index fffe1ad..0000000
--- a/src/main/java/com/chinaztt/mes/docx/service/impl/DocxServiceImpl.java
+++ /dev/null
@@ -1,195 +0,0 @@
-package com.chinaztt.mes.docx.service.impl;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.ObjectUtil;
-import com.chinaztt.mes.docx.constant.FieldMatchRuleConstants;
-import com.chinaztt.mes.docx.dto.GetFileDto;
-import com.chinaztt.mes.docx.handler.SerialPortListener;
-import com.chinaztt.mes.docx.pojo.TestBatch;
-import com.chinaztt.mes.docx.service.DocxService;
-import com.chinaztt.mes.docx.util.XMLFileListener;
-import com.chinaztt.mes.docx.util.Result;
-import com.chinaztt.mes.docx.util.TakeWords;
-import lombok.extern.slf4j.Slf4j;
-import net.sourceforge.tess4j.TesseractException;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.io.File;
-import java.io.IOException;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-@Service
-@Slf4j
-public class DocxServiceImpl implements DocxService {
-
-    @Autowired
-    private SerialPortListener serialPortListener;
-
-    @Override
-    public Result<?> getFile(GetFileDto getFileDto) throws IOException, SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException, TesseractException {
-        String fileExtension = getFileDto.getFileExtension();
-        if(StringUtils.equals(".pngInExcel",getFileDto.getFileExtension())){
-            fileExtension = ".xls";
-        }
-        String entrustCode = "";
-        if(StringUtils.isNotBlank(getFileDto.getEntrustCode()) && getFileDto.getIsMatchFileName()){
-            entrustCode = getFileDto.getEntrustCode().substring(8);
-        }
-        File file = getFileStart(getFileDto.getFilePath(), fileExtension,getFileDto.getIsMatchFileName(),getFileDto.getFieldMatchRule(),entrustCode,getFileDto.getSampleCode());
-        if (file != null && !file.exists()) {
-            return Result.failed("鏈煡璇㈠埌璇ヨ矾寰勶細" + getFileDto.getFilePath() + "涓嬪瓨鍦細" + getFileDto.getFileExtension() + "缁撳熬鐨勬枃浠讹紒");
-        }
-        switch (getFileDto.getFileExtension()) {
-            case ".docx":
-                return Result.ok(TakeWords.readWordFile(file));
-            case ".pngInExcel":
-                return Result.ok(TakeWords.readPngContextInExcel(file));
-            case ".xls":
-            case ".xlsx":
-                try {
-                    return Result.ok(TakeWords.readExcelFile(file));
-                } catch (Exception e) {
-                    return Result.failed("鍙︿竴涓▼搴忔鍦ㄤ娇鐢ㄦ鏂囦欢锛屾棤娉曡繘琛屾暟鎹噰闆嗐��");
-                }
-            case ".txt":
-                return Result.ok(TakeWords.readTxtFile(file));
-            case ".csv":
-                return Result.ok(TakeWords.readCsvFile(file));
-            case ".mdb":
-                if (ObjectUtil.isEmpty(getFileDto.getDbFileName()) || Objects.equals(getFileDto.getDbFileName(), "null")) {
-                    return Result.failed("鏈厤缃�.mdb閲囬泦鏂囦欢鍚嶇О锛�");
-                }
-                return Result.ok(TakeWords.readMdbFile(file, getFileDto));
-            case ".db":
-                if (ObjectUtil.isEmpty(getFileDto.getDbFileName()) || Objects.equals(getFileDto.getDbFileName(), "null")) {
-                    return Result.failed("鏈厤缃�.db閲囬泦鏂囦欢鍚嶇О锛�");
-                }
-                return Result.ok(TakeWords.readDbFile(file, getFileDto));
-            case ".mysql":
-                if (ObjectUtil.isEmpty(getFileDto.getDbFileName()) || Objects.equals(getFileDto.getDbFileName(), "null")) {
-                    return Result.failed("鏈厤缃�.mysql閲囬泦鏂囦欢鍚嶇О锛�");
-                }
-                return Result.ok(TakeWords.getMysqlFile(getFileDto));
-            case ".png":
-                return Result.ok(TakeWords.readPngFile(file));
-            case ".mqtt":
-                return Result.ok("mqtt---");
-            case ".serialPort":
-                List<Double> valList = new ArrayList<>(serialPortListener.dataList);
-                serialPortListener.dataList.clear();
-                return Result.ok(valList);
-            case ".sqlserver":
-                if (ObjectUtil.isEmpty(getFileDto.getDbFileName()) || Objects.equals(getFileDto.getDbFileName(), "null")) {
-                    return Result.failed("鏈厤缃�.sqlserver閲囬泦鏂囦欢鍚嶇О锛�");
-                }
-                return Result.ok(TakeWords.readSqlServerDataBase(getFileDto));
-            default:
-                return Result.failed("鍚庣紑鍚嶉厤缃敊璇紒");
-        }
-    }
-
-    @Override
-    public Result<?> moveFile(String startFilePath, String endFilePath, String fileType) {
-        // 婧愭枃浠惰矾寰�
-        File startFile= getFileStart(startFilePath, fileType);
-        // 鐩殑鐩綍璺緞
-        File endDirection=new File(endFilePath);
-        // 濡傛灉鐩殑鐩綍璺緞涓嶅瓨鍦紝鍒欒繘琛屽垱寤�
-        if(!endDirection.exists()) {
-            endDirection.mkdirs();
-        }
-        // 鐩殑鏂囦欢璺緞=鐩殑鐩綍璺緞+婧愭枃浠跺悕绉�
-        File endFile=new File(endDirection+ File.separator+ startFile.getName());
-
-        try {
-	    // 璋冪敤File绫荤殑鏍稿績鏂规硶renameTo
-            if (startFile.renameTo(endFile)) {
-                return Result.ok("鏂囦欢绉诲姩鎴愬姛锛�");
-            } else {
-                return Result.failed("鏂囦欢绉诲姩澶辫触锛�");
-            }
-        }catch(Exception e) {
-            return Result.failed("鏂囦欢绉诲姩鍑虹幇寮傚父锛�");
-        }
-    }
-
-    public static File getLatestFile(List<File> files) {
-        File latestFile = null;
-        long latestTime = 0;
-
-        for (File file : files) {
-            long lastModified = file.lastModified();
-            if (lastModified > latestTime) {
-                latestTime = lastModified;
-                latestFile = file;
-            }
-        }
-
-        return latestFile;
-    }
-
-    public static File getFileStart(String filePath, String fileExtension){
-        return getFileStart(filePath,fileExtension,false,null,null,null);
-    }
-
-    public static File getFileStart(String filePath, String fileExtension,Boolean isMatchFileName,String matchRule,String entrustCode,String sampleCode) {
-        List<File> files = FileUtil.loopFiles(filePath);
-        List<File> list = new ArrayList<>();
-        files.forEach(i -> {
-            boolean b;
-            switch (fileExtension) {
-                case ".docx":
-                    b = i.getName().endsWith(".docx") || i.getName().endsWith(".doc") || i.getName().endsWith(".DOCX") || i.getName().endsWith(".DOC");
-                    break;
-                case ".xlsx":
-
-                    b = i.getName().endsWith(".xlsx") || i.getName().endsWith(".xls") || i.getName().endsWith(".XLSX") || i.getName().endsWith(".XLS");
-                    break;
-                default:
-                    b = i.getName().endsWith(fileExtension);
-                    break;
-            }
-            if(isMatchFileName){
-                b = matchFileName(i.getName(),matchRule,entrustCode,sampleCode);
-            }
-            if (b) {
-                list.add(i);
-            }
-        });
-        return getLatestFile(list);
-    }
-
-    /**
-     * 鍖归厤鏂囦欢鍚嶇О
-     * @param fileName    鏂囦欢鍚嶇О
-     * @param matchRule   鍖归厤瑙勫垯
-     * @param entrustCode 濮旀墭缂栧彿
-     * @param sampleCode  鏍峰搧鍚嶇О
-     * @return
-     */
-    private static Boolean matchFileName(String fileName,String matchRule,String entrustCode,String sampleCode){
-        if(FieldMatchRuleConstants.ENTRUST_CODE_EQUAL.equals(matchRule)){
-            return fileName.equals(entrustCode);
-        }else if(FieldMatchRuleConstants.ENTRUST_CODE_LIKE.equals(matchRule)){
-            return fileName.contains(entrustCode);
-        }else if(FieldMatchRuleConstants.SAMPLE_CODE_EQUAL.equals(matchRule)){
-            return fileName.equals(sampleCode);
-        }else if(FieldMatchRuleConstants.SAMPLE_CODE_LIKE.equals(matchRule)){
-            return fileName.contains(sampleCode);
-        }
-        return false;
-    }
-
-    @Override
-    public void readXml() {
-        XMLFileListener fileListener = new XMLFileListener();
-        List<TestBatch> testBatches = fileListener.explainXml(new File("C:\\Users\\27233\\Desktop\\251117鏁伴噰鏂囦欢\\鏁伴噰鏂囦欢\\鍏夎氨浠猂esults_20251018133246.xml"));
-        testBatches.forEach(System.out::println);
-    }
-
-}
diff --git a/src/main/java/com/chinaztt/mes/docx/util/TakeWords.java b/src/main/java/com/chinaztt/mes/docx/util/TakeWords.java
deleted file mode 100644
index 284072e..0000000
--- a/src/main/java/com/chinaztt/mes/docx/util/TakeWords.java
+++ /dev/null
@@ -1,554 +0,0 @@
-package com.chinaztt.mes.docx.util;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.http.HttpRequest;
-import cn.hutool.json.JSONUtil;
-import com.chinaztt.mes.docx.dto.GetFileDto;
-import com.opencsv.CSVReader;
-import com.opencsv.CSVReaderBuilder;
-import com.opencsv.exceptions.CsvValidationException;
-import lombok.extern.slf4j.Slf4j;
-import net.sourceforge.tess4j.Tesseract;
-import net.sourceforge.tess4j.TesseractException;
-import org.apache.commons.lang3.ObjectUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.poi.hssf.usermodel.HSSFPictureData;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hwpf.extractor.WordExtractor;
-import org.apache.poi.ooxml.POIXMLDocument;
-import org.apache.poi.ooxml.extractor.POIXMLTextExtractor;
-import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.usermodel.WorkbookFactory;
-import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
-
-import java.io.*;
-import java.sql.*;
-import java.util.*;
-import java.util.regex.Pattern;
-
-@Slf4j
-public class TakeWords {
-
-    private static final String splitIdentifier = "@-@"; // 鑷畾涔夊敮涓�鏍囪瘑绗�
-
-    // 绉戝璁℃暟娉曟鍒欐ā寮�
-    private static final Pattern SCIENTIFIC_PATTERN = Pattern.compile(
-            "^[+-]?\\d+(\\.\\d+)?[eE][+-]?\\d+$"
-    );
-
-    /**
-     * 澶勭悊mdb鏁版嵁搴撴帓闄ゅ瓧娈电被鍨�
-     */
-    private final static List<String> MDB_EXCLUDE_TYPES = Arrays.asList("java.sql.Blob");
-
-    public static Object readWordFile(File file) {
-        String result = "";
-        //棣栧厛鍒ゆ柇鏂囦欢涓殑鏄痙oc/docx
-        try {
-            if (file.getName().endsWith(".doc")) {
-                InputStream is = new FileInputStream(file);
-                WordExtractor re = new WordExtractor(is);
-                result = re.getText();
-                re.close();
-            } else if (file.getName().endsWith(".docx")) {
-                OPCPackage opcPackage = POIXMLDocument.openPackage(file.getPath());
-                POIXMLTextExtractor extractor = new XWPFWordExtractor(opcPackage);
-                result = extractor.getText();
-                extractor.close();
-            }
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-        return result;
-    }
-
-    /**
-     * 璇诲彇excel鏂囦欢,鍏煎.xlsx,.xls鏍煎紡
-     * @param file
-     * @return
-     */
-    public static Object readExcelFile(File file) {
-        StringBuilder result = new StringBuilder();
-        try (
-                FileInputStream fis = new FileInputStream(file);
-                Workbook workbook = WorkbookFactory.create(fis)
-        ) {
-            //閬嶅巻宸ヤ綔绨夸腑鐨勬墍鏈夋暟鎹�
-            Sheet sheet = workbook.getSheetAt(0);
-            //鑾峰彇鏈�鍚庝竴琛岀殑num锛屽嵆鎬昏鏁般�傛澶勪粠0寮�濮�
-            int maxRow = sheet.getLastRowNum();
-            for (int row = 0; row <= maxRow; row++) {
-                if(Objects.nonNull(sheet.getRow(row))){
-                    int maxRol = sheet.getRow(row).getLastCellNum();
-                    StringBuilder aLine = new StringBuilder();
-                    for (int rol = 0; rol < maxRol; rol++) {
-                        aLine.append(sheet.getRow(row).getCell(rol)).append(splitIdentifier);
-                    }
-                    result.append(aLine).append("\n");
-                }
-            }
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-        return result.toString();
-    }
-
-    /**
-     * 璇诲彇excel鏂囦欢涓殑鍥剧墖鍐呭
-     * @param file
-     * @return
-     * @throws IOException
-     */
-    public static Object readPngContextInExcel(File file) throws IOException {
-        String result = "";
-        try (FileInputStream fis = new FileInputStream(file);
-             Workbook workbook = new HSSFWorkbook(fis)) {
-            // 鑾峰彇绗竴涓伐浣滆〃
-            Sheet sheet = workbook.getSheetAt(0);
-            // 璇诲彇鍥剧墖淇℃伅
-            if (workbook instanceof HSSFWorkbook) {
-                HSSFWorkbook hssfWorkbook = (HSSFWorkbook) workbook;
-                List<HSSFPictureData> pictures = hssfWorkbook.getAllPictures();
-                //澶勭悊鏈�鍚庝竴寮犲浘鐗囨暟鎹�
-                HSSFPictureData lastPicture = pictures.get(pictures.size()-1);
-                // 鑾峰彇鍥剧墖绫诲瀷
-                String pictureType = lastPicture.suggestFileExtension();
-                // 鑾峰彇鍥剧墖鏁版嵁
-                byte[] pictureData = lastPicture.getData();
-                // 鍒涘缓涓存椂鏂囦欢
-                File tempFile = File.createTempFile(UUID.randomUUID().toString(), "." + pictureType);
-                try (FileOutputStream fos = new FileOutputStream(tempFile)) {
-                    fos.write(pictureData);
-                }
-                String ocrResult;
-                try {
-                    ocrResult = ocrImageContext(tempFile.getAbsolutePath());
-                } finally {
-                    // 鍒犻櫎涓存椂鏂囦欢
-                    tempFile.delete();
-                }
-                result = ocrResult;
-            }
-        }
-        return result;
-
-    }
-
-    public static Object readPngFile1(File file) throws IOException, TesseractException {
-        // 鑾峰彇 tessdata 鐩綍鐨勭粷瀵硅矾寰�
-        String arch = System.getProperty("sun.arch.data.model");
-        File tessDataDir;
-        if (arch.contains("32")) {
-            tessDataDir = FileUtil.file(".", "/jre_32/tessdata");
-        } else {
-            tessDataDir = FileUtil.file(".", "/jre_64/tessdata");
-        }
-        String path = tessDataDir.getCanonicalPath();
-        // 妫�鏌� chi_sim.traineddata 鏂囦欢鏄惁瀛樺湪
-        File chiSimFile = new File(path, "chi_sim.traineddata");
-        if (!chiSimFile.exists()) {
-            throw new FileNotFoundException("chi_sim.traineddata 鏂囦欢鏈壘鍒帮紝璇锋鏌ヨ矾寰�: " + chiSimFile.getAbsolutePath());
-        }
-        // 璁剧疆閰嶇疆鏂囦欢澶广�佽瘑鍒瑷�銆佽瘑鍒ā寮�
-        Tesseract tesseract = new Tesseract();
-        tesseract.setDatapath(path);
-        // 璁剧疆璇嗗埆璇█涓轰腑鏂囩畝浣撳拰鑻辨枃锛堝鏋滆璁剧疆涓鸿嫳鏂囧彲鏀逛负 "eng"锛�
-        tesseract.setLanguage("chi_sim+eng");
-        // 浣跨敤 OSD 杩涜鑷姩椤甸潰鍒嗗壊浠ヨ繘琛屽浘鍍忓鐞�
-        tesseract.setPageSegMode(1);
-        // 璁剧疆寮曟搸妯″紡鏄缁忕綉缁� LSTM 寮曟搸
-        tesseract.setOcrEngineMode(1);
-        // 寮�濮嬭瘑鍒暣寮犲浘鐗囦腑鐨勬枃瀛�
-        return tesseract.doOCR(file);
-    }
-
-    public static Object readTxtFile(File file) throws IOException {
-        FileInputStream fin = new FileInputStream(file);
-        InputStreamReader reader = new InputStreamReader(fin);
-        BufferedReader buffReader = new BufferedReader(reader);
-        StringBuilder stringBuilder = new StringBuilder();
-        String strTmp = "";
-        while ((strTmp = buffReader.readLine()) != null) {
-            strTmp = strTmp.replaceAll("\t",",");
-            stringBuilder.append(strTmp).append("\n");
-        }
-        buffReader.close();
-        return stringBuilder.toString();
-    }
-
-    public static Object readCsvFile(File file) {
-
-        StringBuilder stringBuilder = new StringBuilder();
-        // 鍒涘缓 reader
-        try (FileReader fileReader = new FileReader(file);
-             CSVReader csvReader = new CSVReaderBuilder(fileReader).build()) {
-
-            String[] nextLine;
-            while ((nextLine = csvReader.readNext()) != null) {
-                // 澶勭悊姣忎竴琛屾暟鎹�
-                for (String cell : nextLine) {
-                    if(StringUtils.isNotBlank(cell)){
-                        stringBuilder.append(scientificToNumber(cell)).append(splitIdentifier);
-                    }
-                }
-                stringBuilder.append("\n");
-            }
-        } catch (IOException e) {
-            e.printStackTrace();
-        } catch (CsvValidationException e) {
-            throw new RuntimeException(e);
-        }
-        return stringBuilder.toString();
-    }
-
-    /**
-     * 灏嗙瀛﹁鏁版硶杞崲涓烘暟瀛�
-     * @param cell
-     * @return
-     */
-    public static String scientificToNumber(String cell){
-        if(SCIENTIFIC_PATTERN.matcher(cell).matches()){
-            return String.valueOf(Double.parseDouble(cell));
-        }
-        return cell;
-    }
-
-    public static Object readMdbFile(File file, GetFileDto getFileDto) throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException {
-        Map<String, Object> tableMap = new HashMap<>(16);
-        Properties prop = new Properties();
-        //璁剧疆缂栫爜
-        prop.put("charSet", "UTF-8");
-        prop.put("user",  StringUtils.isNotBlank(getFileDto.getDbUserName())?getFileDto.getDbUserName():"");
-        prop.put("password", StringUtils.isNotBlank(getFileDto.getDbPassword())?getFileDto.getDbPassword():"");
-        //鏁版嵁鍦板潃
-        String dbUrl = "jdbc:ucanaccess://" + file.getPath();
-        //寮曞叆椹卞姩
-        Class.forName("net.ucanaccess.jdbc.UcanaccessDriver").newInstance();
-        Connection conn = null;
-        PreparedStatement preparedStatement = null;
-        ResultSet rs = null;
-
-        //杩炴帴鏁版嵁搴撹祫婧�
-        conn = DriverManager.getConnection(dbUrl, prop);
-        try {
-            List<Object> list = new ArrayList<>();
-            //閬嶅巻鑾峰彇澶氬紶琛ㄦ暟鎹�
-            String s = "select * from " + getFileDto.getDbFileName() + " where 1=1";
-            if(StringUtils.isNotBlank(getFileDto.getMdbEntrustCode())){
-                s+=" and " + getFileDto.getMdbEntrustCode() + " = '" + getFileDto.getEntrustCode()+ "'";
-            }
-            if(StringUtils.isNotBlank(getFileDto.getMdbSampleCode())){
-                s+=" and " + getFileDto.getMdbSampleCode() + " = '" + getFileDto.getSampleCode() + "'";
-            }
-            if(ObjectUtils.allNotNull(getFileDto.getBushingColorField(), getFileDto.getBushingColor()) && !getFileDto.getBushingColorField().equals("null")){
-                s+=" and " + getFileDto.getBushingColorField() + " = '" + getFileDto.getBushingColor() + "'";
-            }
-
-            preparedStatement = conn.prepareStatement(s);
-            rs = preparedStatement.executeQuery();
-            ResultSetMetaData data = rs.getMetaData();
-            while (rs.next()) {
-                Map<String, Object> map = new HashMap<>();
-                for (int i = 1; i <= data.getColumnCount(); i++) {
-                    //鍒楀悕
-                    String columnName = data.getColumnName(i);
-                    //鍒楀瓧娈电被鍨�
-                    String columnClassName = data.getColumnClassName(i);
-                    Object columnValue = null;
-                    if(!MDB_EXCLUDE_TYPES.contains(columnClassName)){
-                        columnValue = rs.getObject(i);
-                    }
-                    map.put(columnName, columnValue);
-                }
-                list.add(map);
-            }
-            tableMap.put("data", list);
-        } catch (Exception e) {
-            e.printStackTrace();
-        } finally {
-            closeA1l(conn, preparedStatement, rs);
-        }
-        return tableMap;
-    }
-
-    private static void closeA1l(Connection conn, PreparedStatement preparedStatement, ResultSet rs) {
-        try {
-            if (null != rs) {
-                rs.close();
-            }
-            if (null != preparedStatement) {
-                preparedStatement.close();
-            }
-            if (null != conn) {
-                conn.close();
-            }
-        } catch (Exception ignore) {
-        }
-    }
-
-    public static Object getMysqlFile(GetFileDto getFileDto){
-        Map<String, Object> tableMap = new HashMap<>(16);
-        // 浠� GetFileDto 鑾峰彇鏁版嵁搴撳悕锛屽搴斻�愭枃浠跺悕绉般�戝瓧娈�
-        String dbName = getFileDto.getDbFileName();
-        String user = getFileDto.getDbUserName();
-        String password = getFileDto.getDbPassword();
-        // 浠� GetFileDto 鑾峰彇鏁版嵁琛ㄥ悕锛屽搴斻�愭暟鎹簱琛ㄥ悕銆戝瓧娈�
-        String table = getFileDto.getDbTable();
-        // 妫�鏌ユ暟鎹簱鍚嶅拰琛ㄥ悕鏄惁涓虹┖
-        if (dbName == null || dbName.isEmpty() || table == null || table.isEmpty()) {
-            return Result.failed("鏁版嵁搴撳悕鎴栬〃鍚嶄笉鑳戒负绌�");
-        }
-        // 鏁版嵁搴撹繛鎺ヤ俊鎭�
-        String url = "jdbc:mysql://localhost:3306/"+dbName+"?useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true&characterEncoding=utf8";
-        Connection connection = null;
-        PreparedStatement preparedStatement = null;
-        ResultSet resultSet = null;
-        List<Map<String, Object>> dataList = new ArrayList<>();
-
-        try {
-            // 寤虹珛杩炴帴
-            connection = DriverManager.getConnection(url, user, password);
-            // 鏋勫缓鍩虹 SQL
-
-            String sql = "SELECT * FROM "+table+" WHERE 1=1";
-            if(StringUtils.isNotBlank(getFileDto.getMdbEntrustCode()) ){
-                sql+=" AND (" + getFileDto.getMdbEntrustCode() + " = TRIM('" + getFileDto.getEntrustCode()+ "')";
-                if(StringUtils.isNotBlank(getFileDto.getLotBatchNo())){
-                    sql+=" OR "+ getFileDto.getMdbEntrustCode() + " = TRIM('" + getFileDto.getLotBatchNo()+ "')";
-                }
-                sql+=")";
-            }
-            if(StringUtils.isNotBlank(getFileDto.getMdbSampleCode())){
-                sql+=" AND " + getFileDto.getMdbSampleCode() + " = '" + getFileDto.getSampleCode() + "'";
-            }
-            if(StringUtils.isNotBlank(getFileDto.getCableTag())){
-                sql+=" AND Color = '" + getFileDto.getCableTag() + "'";
-            }
-            // 鍒涘缓 PreparedStatement 瀵硅薄鎵ц SQL
-            preparedStatement = connection.prepareStatement(sql);
-            resultSet = preparedStatement.executeQuery();
-            ResultSetMetaData metaData = resultSet.getMetaData();
-            int columnCount = metaData.getColumnCount();
-            // 閬嶅巻缁撴灉闆嗚幏鍙栨暟鎹�
-            while (resultSet.next()) {
-                Map<String, Object> rowData = new HashMap<>();
-                for (int i = 1; i <= columnCount; i++) {
-                    String columnName = metaData.getColumnName(i);
-                    rowData.put(columnName, resultSet.getObject(i));
-                }
-                dataList.add(rowData);
-            }
-            tableMap.put("data", dataList);
-        } catch (Exception e) {
-            e.printStackTrace();
-            // 鍋囪 R 绫绘湁 failed 鏂规硶锛岃嫢娌℃湁闇�琛ュ厖瀹炵幇
-            return Result.failed("鏁版嵁搴撴煡璇㈠嚭閿�: " + e.getMessage());
-        } finally {
-            try {
-                if (resultSet != null) {
-                    resultSet.close();
-                }
-                if (preparedStatement != null) {
-                    preparedStatement.close();
-                }
-                if (connection != null) {
-                    connection.close();
-                }
-            } catch (SQLException e) {
-                e.printStackTrace();
-            }
-        }
-        return tableMap;
-    }
-
-    public static Object readDbFile(File file, GetFileDto getFileDto) throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException {
-        Map<String, Object> tableMap = new HashMap<>(16);
-        Properties prop = new Properties();
-        //璁剧疆缂栫爜
-        prop.put("charSet", "GBK");
-        prop.put("user", "");
-        prop.put("password", "");
-        //鏁版嵁鍦板潃
-        String dbUrl = "jdbc:sqlite:" + file.getPath();
-        //寮曞叆椹卞姩
-        Class.forName("org.sqlite.JDBC").newInstance();
-        Connection conn = null;
-        PreparedStatement preparedStatement = null;
-        ResultSet rs = null;
-        //杩炴帴鏁版嵁搴撹祫婧�
-        conn = DriverManager.getConnection(dbUrl, prop);
-        try {
-            List<Object> list = new ArrayList<>();
-            //杞箟涓枃
-            String sampleCode = changeCharset(getFileDto.getSampleCode(), "GBK");
-            String sql = "select * from " + getFileDto.getDbFileName() + " where 1=1";
-            if(StringUtils.isNotBlank(getFileDto.getMdbEntrustCode())){
-                sql+=" and " + getFileDto.getMdbEntrustCode() + " = '" + getFileDto.getEntrustCode() +"'";
-            }
-            if(StringUtils.isNotBlank(getFileDto.getMdbSampleCode())){
-                sql+=" and " + getFileDto.getMdbSampleCode() + " = '" + sampleCode + "'";
-            }
-            if (ObjectUtils.allNotNull(getFileDto.getFiberOpticRibbonCode(), getFileDto.getFiberOpticRibbon()) && !getFileDto.getFiberOpticRibbonCode().equals("null")) {
-                sql = sql + " and " + getFileDto.getFiberOpticRibbonCode() + " = '" + getFileDto.getFiberOpticRibbon() + "'";
-            }
-            //閬嶅巻鑾峰彇澶氬紶琛ㄦ暟鎹�
-            preparedStatement = conn.prepareStatement(sql);
-            rs = preparedStatement.executeQuery();
-            ResultSetMetaData data = rs.getMetaData();
-            while (rs.next()) {
-                Map<String, String> map = new HashMap<>();
-                for (int i = 1; i <= data.getColumnCount(); i++) {
-                    //鍒楀悕
-                    String columnName = data.getColumnName(i);
-                    //灏嗚繑鍥炵殑缁撴灉杞崲浠巙tf-8缂栫爜
-                    map.put(columnName, changeCharset(rs.getString(i),"UTF-8"));
-                }
-                list.add(map);
-            }
-            tableMap.put("data", list);
-        } catch (Exception e) {
-        } finally {
-            closeA1l(conn, preparedStatement, rs);
-        }
-        return tableMap;
-    }
-
-    /**
-     * ocr璇嗗埆鍥剧墖鍐呭
-     * @param imagePath 鍥剧墖璺緞
-     * @return
-     */
-    public static String ocrImageContext(String imagePath){
-        //璋冪敤ocr璇嗗埆鏈嶅姟
-        Map<String,Object> jsonMap = new HashMap<>();
-        jsonMap.put("imagePath",imagePath);
-        String requestBody = JSONUtil.toJsonStr(jsonMap);
-        return HttpRequest.post("localhost:8080/ocr/recognize").body(requestBody).execute().body();
-    }
-
-    public static Object readPngFile(File file) throws IOException, TesseractException {
-        String canonicalPath32 = FileUtil.file(".", "/jre_32/tessdata").getCanonicalPath();
-        String canonicalPath64 = FileUtil.file(".", "/jre_64/tessdata").getCanonicalPath();
-        String path;
-        // 鍒ゆ柇鐢佃剳鏄�32浣嶈繕鏄�64浣�
-        String arch = System.getProperty("sun.arch.data.model");
-        if (arch.contains("32")) {
-            path = canonicalPath32.replaceAll("/chi_sim.traineddata", "").replaceAll("\\\\", "/");
-        } else {
-            path = canonicalPath64.replaceAll("/chi_sim.traineddata", "").replaceAll("\\\\", "/");
-        }
-        // 璁剧疆 TESSDATA_PREFIX 鐜鍙橀噺
-//        System.setProperty("TESSDATA_PREFIX", path);
-        //璁剧疆閰嶇疆鏂囦欢澶瑰井瑙嗐�佽瘑鍒瑷�銆佽瘑鍒ā寮�
-        Tesseract tesseract = new Tesseract();
-        tesseract.setDatapath(path);
-        //璁剧疆璇嗗埆璇█涓轰腑鏂囩畝浣擄紝锛堝鏋滆璁剧疆涓鸿嫳鏂囧彲鏀逛负"eng"锛�
-        tesseract.setLanguage("chi_sim");
-        //浣跨敤 OSD 杩涜鑷姩椤甸潰鍒嗗壊浠ヨ繘琛屽浘鍍忓鐞�
-        tesseract.setPageSegMode(1);
-        //璁剧疆寮曟搸妯″紡鏄缁忕綉缁淟STM寮曟搸
-        tesseract.setOcrEngineMode(1);
-        //寮�濮嬭瘑鍒暣寮犲浘鐗囦腑鐨勬枃瀛�
-        return tesseract.doOCR(file);
-    }
-
-    /**
-     * 瀛楃涓茬紪鐮佽浆鎹�
-     *
-     * @param str 瑕佽浆鎹㈢殑瀛楃涓�
-     * @param unicode 瀛楃缂栫爜
-     * @return
-     */
-    public static String changeCharset(String str, String unicode) {
-        if(Objects.isNull(str)){
-            return "";
-        }
-        try {
-            return new String(str.getBytes(), unicode);
-        } catch (UnsupportedEncodingException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * 璇诲彇sqlserver鏁版嵁
-     * @param getFileDto 璇锋眰鍙傛暟瀵硅薄
-     * @return
-     */
-    public static Object readSqlServerDataBase(GetFileDto getFileDto) {
-        Map<String, Object> tableMap = new HashMap<>(16);
-        // 浠� GetFileDto 鑾峰彇鏁版嵁搴撳悕锛屽搴斻�愭枃浠跺悕绉般�戝瓧娈�
-        String dbName = getFileDto.getDbFileName();
-        String user = getFileDto.getDbUserName();
-        String password = getFileDto.getDbPassword();
-        // 浠� GetFileDto 鑾峰彇鏁版嵁琛ㄥ悕锛屽搴斻�愭暟鎹簱琛ㄥ悕銆戝瓧娈�
-        String table = getFileDto.getDbTable();
-        // 妫�鏌ユ暟鎹簱鍚嶅拰琛ㄥ悕鏄惁涓虹┖
-        if (dbName == null || dbName.isEmpty() || table == null || table.isEmpty()) {
-            return Result.failed("鏁版嵁搴撳悕鎴栬〃鍚嶄笉鑳戒负绌�");
-        }
-        // 鏁版嵁搴撹繛鎺ヤ俊鎭�
-        String url = "jdbc:sqlserver://localhost:1433;DatabaseName="+dbName+";encrypt=false;trustServerCertificate=true";
-        Connection connection = null;
-        PreparedStatement preparedStatement = null;
-        ResultSet resultSet = null;
-        List<Map<String, Object>> dataList = new ArrayList<>();
-        try {
-            // 寤虹珛杩炴帴
-            connection = DriverManager.getConnection(url, user, password);
-            // 鏋勫缓鍩虹 SQL
-
-            String sql = "SELECT * FROM "+table+" WHERE 1=1";
-            if(StringUtils.isNotBlank(getFileDto.getMdbEntrustCode()) ){
-                sql+=" AND (" + getFileDto.getMdbEntrustCode() + " = LTRIM(RTRIM('" + getFileDto.getEntrustCode()+ "'))";
-                if(StringUtils.isNotBlank(getFileDto.getLotBatchNo())){
-                    sql+=" OR "+ getFileDto.getMdbEntrustCode() + " = LTRIM(RTRIM('" + getFileDto.getLotBatchNo()+ "'))";
-                }
-                sql+=")";
-            }
-            if(StringUtils.isNotBlank(getFileDto.getMdbSampleCode())){
-                sql+=" AND " + getFileDto.getMdbSampleCode() + " = '" + getFileDto.getSampleCode() + "'";
-            }
-            if(StringUtils.isNotBlank(getFileDto.getLastSql())){
-                sql+=getFileDto.getLastSql();
-            }
-            // 鍒涘缓 PreparedStatement 瀵硅薄鎵ц SQL
-            preparedStatement = connection.prepareStatement(sql);
-            resultSet = preparedStatement.executeQuery();
-            ResultSetMetaData metaData = resultSet.getMetaData();
-            int columnCount = metaData.getColumnCount();
-            // 閬嶅巻缁撴灉闆嗚幏鍙栨暟鎹�
-            while (resultSet.next()) {
-                Map<String, Object> rowData = new HashMap<>();
-                for (int i = 1; i <= columnCount; i++) {
-                    String columnName = metaData.getColumnName(i);
-                    rowData.put(columnName, resultSet.getObject(i));
-                }
-                dataList.add(rowData);
-            }
-            tableMap.put("data", dataList);
-        } catch (Exception e) {
-            e.printStackTrace();
-            // 鍋囪 R 绫绘湁 failed 鏂规硶锛岃嫢娌℃湁闇�琛ュ厖瀹炵幇
-            return Result.failed("鏁版嵁搴撴煡璇㈠嚭閿�: " + e.getMessage());
-        } finally {
-            try {
-                if (resultSet != null) {
-                    resultSet.close();
-                }
-                if (preparedStatement != null) {
-                    preparedStatement.close();
-                }
-                if (connection != null) {
-                    connection.close();
-                }
-            } catch (SQLException e) {
-                e.printStackTrace();
-            }
-        }
-        return tableMap;
-    }
-
-}
diff --git a/src/main/java/com/chinaztt/mes/docx/util/XMLFileListener.java b/src/main/java/com/chinaztt/mes/docx/util/XMLFileListener.java
deleted file mode 100644
index 585dfc0..0000000
--- a/src/main/java/com/chinaztt/mes/docx/util/XMLFileListener.java
+++ /dev/null
@@ -1,231 +0,0 @@
-package com.chinaztt.mes.docx.util;
-
-import com.chinaztt.mes.docx.pojo.Chemical;
-import com.chinaztt.mes.docx.pojo.TestBatch;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.SerializationUtils;
-import org.dom4j.Attribute;
-import org.dom4j.Document;
-import org.dom4j.Element;
-import org.dom4j.io.SAXReader;
-
-import java.io.File;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-/**
- * @Description 鏂囦欢鍙樺寲澶勭悊
- * @Author fz
- **/
-@Slf4j
-public class XMLFileListener {
-
-    private final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-
-    /**
-     * 瑙f瀽xml鏂囦欢
-     *
-     * @param file
-     */
-    public List<TestBatch> explainXml(File file) {
-        // 閫氳繃鍚庣紑鍚嶅垽鏂槸鍚︽槸xml鏂囦欢
-        if (file.exists() && file.isFile()) {
-            String fileName = file.getName();
-            if (".xml".equals(fileName.substring(fileName.lastIndexOf(".")))) {
-                // 鍒涘缓reader瀵硅薄
-                SAXReader reader = new SAXReader();
-                // 鍔犺浇xml鏂囦欢
-                Document document;
-                try {
-                    document = reader.read(file);
-                } catch (Exception e) {
-                    log.error("鏂囨。鍐呭闈瀤ml鏍煎紡锛屾棤娉曡В鏋愶紒");
-                    return null;
-                }
-                // 鏍硅妭鐐� SampleResults
-                Element root = document.getRootElement();
-                // 妫�楠屾壒娆′俊鎭妭鐐� SampleResult
-                Element sampleResult = root.element("SampleResult");
-                List<Attribute> attributes = sampleResult.attributes();
-                String name;
-                String value;
-                String batchNo = null;
-                String mark = null;
-                String reportTime = null;
-                for (Attribute attribute : attributes) {
-                    name = attribute.getName();
-                    value = attribute.getValue();
-                    if ("Type".equals(name) && "TypeStandardization".equals(value)) {
-                        log.info("鏍″噯鏁版嵁锛屼笉杩涜閲囬泦...");
-                        return null;
-                    } else if ("Name".equals(name)) {
-                        batchNo = value;
-                    } else if ("TypeCorrSample".equals(name)) {
-                        mark = value;
-                    } else if ("RecalculationDateTime".equals(name)) {
-                        reportTime = value;
-                    }
-                }
-                if (batchNo == null || batchNo.trim().length() == 0) {
-                    log.warn("鏃犳硶瑙f瀽鎵规鍙蜂俊鎭紝姝や负蹇呰淇℃伅鎵�浠ョ粓姝㈣В鏋愶紒");
-                    return null;
-                }
-                // 鍏堝垽鏂槸鍚︽槸姹熶笢閲戝叿鐨勫鎵樿鍗�
-//                List<String> batchNos = saveTestBatchService.explainBatchNo(batchNo.trim());
-//                if (batchNos == null || batchNos.size() == 0) {
-//                    return null;
-//                }
-//                if (batchNos.get(0).equals(batchNo.trim())) {
-//                    log.warn(batchNo.trim() + " 闈炴娴嬪崟鍙凤紝涓嶈繘琛岃В鏋�...");
-//                    return null;
-//                }
-                // 鍐嶅幓闄よ灪鏍撹灪姣嶇殑濮旀墭璁㈠崟(鐜颁笉鍋氶噰闆�)
-                /*batchNos = saveTestBatchService.excludeBatchNo(batchNos);
-                if (batchNos == null || batchNos.size() == 0) {
-                    log.warn("璇ユ壒娆′负铻烘爴/铻烘瘝鐨勬娴嬪崟锛岀幇涓嶅仛閲囬泦...");
-                    return null;
-                }*/
-                // 鍖呭惈鍏蜂綋妫�楠屼俊鎭妭鐐� MeasurementReplicates
-                Element measurement = sampleResult.element("MeasurementReplicates");
-                List<Element> elements = measurement.elements();
-                List<TestBatch> batches = new ArrayList<>(elements.size());
-                TestBatch batch;
-                Date time;
-                List<Element> children;
-                for (Element element : elements) {
-                    batch = new TestBatch();
-                    try {
-                        value = element.attributeValue("MeasureDateTime").replaceFirst("T", " ");
-                        time = SDF.parse(value);
-                    } catch (ParseException e) {
-                        e.printStackTrace();
-                        log.error("鎶ュ憡鏃堕棿鏍煎紡闈� yyyy-MM-ddTHH:mm:ss 鎴� yyyy-MM-dd HH:mm:ss锛屾棤娉曡В鏋愶紒");
-                        return null;
-                    }
-                    batch.setEquipmentTime(time);
-                    // 鍙栨湭琚垹闄ょ殑妫�楠屼俊鎭�
-                    value = element.attributeValue("IsDeleted");
-                    if ("No".equals(value)) {
-                        element = element.element("Measurement");
-                        // 鐪熸鍖呭惈妫�楠岀粨鏋滅殑鑺傜偣 Elements
-                        element = element.element("Elements");
-                        children = element.elements("Element");
-                        batch.setChemicals(explainElements(children, time));
-                        batches.add(batch);
-                    }
-                }
-                if (!batches.isEmpty()) {
-                    // 鍖呭惈妫�楠屾暟鎹钩鍧囧�艰妭鐐� MeasurementStatistics
-                    elements = null;
-                    try {
-                        measurement = sampleResult.element("MeasurementStatistics").element("Measurement").element("Elements");
-                        elements = measurement.elements("Element");
-                    } catch (Exception e) {
-                        log.error("妫�楠屾暟鎹钩鍧囧�兼棤娉曡В鏋愶紒");
-                    }
-                    if (elements != null && !elements.isEmpty()) {
-                        batch = new TestBatch();
-                        time = batches.get(batches.size() - 1).getEquipmentTime();
-                        batch.setEquipmentTime(time);
-                        batch.setChemicals(explainElements(elements, time));
-                        batches.add(batch);
-                    }
-//                    List<List<TestBatch>> testBatches = new ArrayList<>(batchNos.size());
-//                    if (batchNos.size() > 1) {
-//                        List<TestBatch> batchList;
-//                        for (String no : batchNos) {
-//                            log.info("鎶ュ憡妫�楠屾壒娆★細" + no + "\t鏉愭枡鐗屽彿锛�" + mark + "\t鐢熸垚鏃堕棿锛�" + reportTime);
-//                            batchList = cloneBatches(batches, no);
-//                            testBatches.add(batchList);
-//                        }
-//                    } else if (batchNos.size() == 1) {
-//                        log.info("鎶ュ憡妫�楠屾壒娆★細" + batchNos.get(0) + "\t鏉愭枡鐗屽彿锛�" + mark + "\t鐢熸垚鏃堕棿锛�" + reportTime);
-//                        for (TestBatch testBatch : batches) {
-//                            testBatch.setBatchNo(batchNos.get(0));
-//                        }
-//                        testBatches.add(batches);
-//                    }
-//                    log.info(fileName + " 瑙f瀽瀹屾垚...");
-//                    return testBatches;
-                    return batches;
-                } else {
-                    log.warn(fileName + " 鏈В鏋愬嚭鏈夋晥鏁版嵁锛�");
-                    return null;
-                }
-            }
-            log.warn(fileName + " 闈瀤ml鏂囦欢锛屾棤娉曡В鏋愶紒");
-        }
-        return null;
-    }
-
-    private List<Chemical> explainElements(List<Element> elements, Date time) {
-        List<Chemical> chemicals = new ArrayList<>(elements.size());
-        Chemical chemical;
-        String value;
-        List<Element> results;
-        for (Element child : elements) {
-            chemical = new Chemical();
-            value = child.attributeValue("ElementName");
-            chemical.setName(value);
-            results = child.elements();
-            if (results.size() == 3) {
-                for (Element result : results) {
-                    value = result.attributeValue("StatType");
-                    if ("Reported".equals(value)) {
-                        /*value = result.attributeValue("CalibrationStatus");
-                        if (!"InRange".equals(value)) {
-                            chemical.setRemark(value);
-                        }*/
-                        result = result.element("ResultValue");
-                        value = result.getTextTrim();
-                        chemical.setValue(value);
-                        chemical.setEquipmentTime(time);
-                    }
-                }
-            } else {
-                for (Element result : results) {
-                    value = result.attributeValue("Type");
-                    if ("ConcTypeCorr".equals(value)) {
-                        value = result.attributeValue("StatType");
-                        if ("Reported".equals(value)) {
-                            /*value = result.attributeValue("CalibrationStatus");
-                            if (!"InRange".equals(value)) {
-                                chemical.setRemark(value);
-                            }*/
-                            result = result.element("ResultValue");
-                            value = result.getTextTrim();
-                            chemical.setValue(value);
-                            chemical.setEquipmentTime(time);
-                        }
-                    }
-                }
-            }
-            if (!"-".equals(chemical.getValue())) {
-                chemicals.add(chemical);
-            }
-        }
-        return chemicals;
-    }
-
-    /**
-     * 瀵硅薄鏁扮粍娣辨嫹璐�
-     *
-     * @param batches
-     * @param batchNo
-     * @return
-     */
-    private List<TestBatch> cloneBatches(List<TestBatch> batches, String batchNo) {
-        List<TestBatch> testBatches = new ArrayList<>(batches.size());
-        TestBatch testBatch;
-        for (TestBatch batch : batches) {
-            testBatch = SerializationUtils.clone(batch);
-            testBatch.setBatchNo(batchNo);
-            testBatches.add(testBatch);
-        }
-        return testBatches;
-    }
-
-}
diff --git a/src/main/java/com/chinaztt/mes/docx/DataAcquisitionApplication.java b/src/main/java/com/hwtd/mes/collect/DataAcquisitionApplication.java
similarity index 90%
rename from src/main/java/com/chinaztt/mes/docx/DataAcquisitionApplication.java
rename to src/main/java/com/hwtd/mes/collect/DataAcquisitionApplication.java
index f44be8f..362e762 100644
--- a/src/main/java/com/chinaztt/mes/docx/DataAcquisitionApplication.java
+++ b/src/main/java/com/hwtd/mes/collect/DataAcquisitionApplication.java
@@ -1,4 +1,4 @@
-package com.chinaztt.mes.docx;
+package com.hwtd.mes.collect;
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
diff --git a/src/main/java/com/chinaztt/mes/docx/config/TomcatConfig.java b/src/main/java/com/hwtd/mes/collect/config/TomcatConfig.java
similarity index 94%
rename from src/main/java/com/chinaztt/mes/docx/config/TomcatConfig.java
rename to src/main/java/com/hwtd/mes/collect/config/TomcatConfig.java
index 05e219c..2ff267a 100644
--- a/src/main/java/com/chinaztt/mes/docx/config/TomcatConfig.java
+++ b/src/main/java/com/hwtd/mes/collect/config/TomcatConfig.java
@@ -1,4 +1,4 @@
-package com.chinaztt.mes.docx.config;
+package com.hwtd.mes.collect.config;
 
 import org.apache.catalina.connector.Connector;
 import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
diff --git a/src/main/java/com/chinaztt/mes/docx/constant/CommonConstants.java b/src/main/java/com/hwtd/mes/collect/constant/CommonConstants.java
similarity index 68%
rename from src/main/java/com/chinaztt/mes/docx/constant/CommonConstants.java
rename to src/main/java/com/hwtd/mes/collect/constant/CommonConstants.java
index 4763f4a..4dce581 100644
--- a/src/main/java/com/chinaztt/mes/docx/constant/CommonConstants.java
+++ b/src/main/java/com/hwtd/mes/collect/constant/CommonConstants.java
@@ -1,4 +1,4 @@
-package com.chinaztt.mes.docx.constant;
+package com.hwtd.mes.collect.constant;
 
 
 public interface CommonConstants {
diff --git a/src/main/java/com/hwtd/mes/collect/controller/DataCollectionController.java b/src/main/java/com/hwtd/mes/collect/controller/DataCollectionController.java
new file mode 100644
index 0000000..4b569fd
--- /dev/null
+++ b/src/main/java/com/hwtd/mes/collect/controller/DataCollectionController.java
@@ -0,0 +1,79 @@
+package com.hwtd.mes.collect.controller;
+
+import com.hwtd.mes.collect.dto.DatabaseDTO;
+import com.hwtd.mes.collect.dto.SerialPortDTO;
+import com.hwtd.mes.collect.handler.SerialPortListener;
+import com.hwtd.mes.collect.service.DataCollectionService;
+import com.hwtd.mes.collect.util.Result;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/collection")
+public class DataCollectionController {
+
+    @Autowired
+    private DataCollectionService dataCollectionService;
+
+    @Autowired
+    private SerialPortListener serialPortListener;
+
+    /**
+     * 鎵嬪姩寮�鍚覆鍙g洃鍚紝骞惰繑鍥炲綋鍓嶆帴鏀跺埌鐨勬暟鎹垪琛紙闃熷垪寮忕紦瀛橈紝鏈�澶� maxCount 鏉★紝娌℃湁鏁版嵁鏃惰繑鍥炵┖闆嗗悎锛夈��
+     * <p>
+     * 涓插彛鍙傛暟閫氳繃璇锋眰鍙傛暟浼犲叆锛堜笉浼犵殑瀛楁浣跨敤榛樿鍊硷紝listenName 蹇呬紶锛夛細
+     * listenName銆乥audRate銆乨ataBits銆乻topBits銆乸arity銆乫lowControl銆乺eadTimeout銆乪ndMark銆乵axCount銆�
+     * 骞傜瓑鎺ュ彛锛氬弬鏁颁竴鑷存椂鐩存帴澶嶇敤宸叉墦寮�鐨勪覆鍙c�佷笉浼氶噸澶嶆墦寮�锛屽弬鏁板彉鍖栨椂鎸夋柊鍙傛暟閲嶆柊鎵撳紑锛�
+     * 澶氱嚎绋嬪苟鍙戣皟鐢ㄥ悓鏍峰彧浼氭墦寮�涓�娆°�傚弬鏁伴潪娉曟椂鐢� GlobalExceptionHandler 杩斿洖鍏蜂綋鍘熷洜銆�
+     */
+    @GetMapping("/openSerialPort")
+    public Result<?> openSerialPort(SerialPortDTO serialPortDTO) {
+        if (!serialPortListener.startListening(serialPortDTO)) {
+            String listenName = serialPortDTO == null || serialPortDTO.getSerialPortName() == null
+                    ? "" : serialPortDTO.getSerialPortName();
+            return Result.failed("涓插彛 " + listenName + " 鐩戝惉寮�鍚け璐ワ紝璇锋鏌ヤ覆鍙f槸鍚﹀瓨鍦ㄣ�佹槸鍚﹁鍏朵粬绋嬪簭鍗犵敤锛�");
+        }
+        return Result.ok(serialPortListener.drainData());
+    }
+
+    /**
+     * 鎵嬪姩鍏抽棴涓插彛鐩戝惉銆�
+     * 骞傜瓑鎺ュ彛锛氭湭寮�鍚椂璋冪敤涔熶細姝e父杩斿洖锛屼笉浼氭姤閿欍��
+     */
+    @GetMapping("/closeSerialPort")
+    public Result<?> closeSerialPort() {
+        if (serialPortListener.closeListening()) {
+            return Result.ok("涓插彛 " + serialPortListener.getListenName() + " 鐩戝惉宸插叧闂�");
+        }
+        return Result.failed("涓插彛 " + serialPortListener.getListenName() + " 鐩戝惉鍏抽棴澶辫触锛岃妫�鏌ヤ覆鍙g姸鎬侊紒");
+    }
+
+    /**
+     * 鏌ヨ涓插彛鐩戝惉鐘舵�侊紝渚夸簬鍓嶇鍒ゆ柇鏄惁闇�瑕佽皟鐢ㄥ紑鍚� / 鍏抽棴鎺ュ彛
+     */
+    @GetMapping("/serialPortStatus")
+    public Result<?> serialPortStatus() {
+        Map<String, Object> status = new LinkedHashMap<>();
+        status.put("listenName", serialPortListener.getListenName());
+        status.put("listening", serialPortListener.isListening());
+        status.put("portOpen", serialPortListener.isPortOpen());
+        status.put("dataSize", serialPortListener.dataSize());
+        return Result.ok(status);
+    }
+
+    @GetMapping("/getAccessData")
+    public Result<?> getAccessData(DatabaseDTO databaseDTO) {
+        return Result.ok(dataCollectionService.getAccessData(databaseDTO));
+    }
+
+    @GetMapping("/getPostgreSqlData")
+    public Result<?> getPostgreSqlData(DatabaseDTO databaseDTO) {
+        return Result.ok(dataCollectionService.getPostgreSqlData(databaseDTO));
+    }
+
+}
diff --git a/src/main/java/com/hwtd/mes/collect/dto/DatabaseDTO.java b/src/main/java/com/hwtd/mes/collect/dto/DatabaseDTO.java
new file mode 100644
index 0000000..51fbe5a
--- /dev/null
+++ b/src/main/java/com/hwtd/mes/collect/dto/DatabaseDTO.java
@@ -0,0 +1,75 @@
+package com.hwtd.mes.collect.dto;
+
+import lombok.Data;
+
+/**
+ *
+ * 鏁版嵁搴撻噰闆嗗弬鏁�
+ * @author 27233
+ * @date 2026-09-14 9:44
+ */
+@Data
+public class DatabaseDTO {
+
+    /**
+     * 鏁版嵁搴撳湴鍧�
+     */
+    private String filePath;
+
+    /**
+     * ip鍦板潃
+     */
+    private String ipAddress;
+
+    /**
+     *
+     * 绔彛鍙�
+     */
+    private Integer serverPort;
+
+    /**
+     * 涓婚敭瀛楁
+     */
+    private String mainColumn;
+
+    /**
+     * 鏁版嵁搴撳悕
+     */
+    private String databaseName;
+
+    /**
+     * 鏁版嵁琛ㄥ悕
+     */
+    private String tableName;
+
+    /**
+     * 鐢ㄦ埛鍚�
+     */
+    private String userName;
+
+    /**
+     * 瀵嗙爜
+     */
+    private String password;
+
+    /**
+     * 鐩樺彿
+     */
+    private String batchCode;
+
+    /**
+     * 閲囬泦鐐逛綅瀛楁
+     */
+    private String pointColumns;
+
+    /**
+     * 鎺掑簭瀛楁鍚嶇О
+     */
+    private String orderColumn;
+
+    /**
+     * 鎺掑簭瑙勫垯
+     */
+    private String orderRule;
+
+}
diff --git a/src/main/java/com/hwtd/mes/collect/dto/SerialPortDTO.java b/src/main/java/com/hwtd/mes/collect/dto/SerialPortDTO.java
new file mode 100644
index 0000000..3ee4a50
--- /dev/null
+++ b/src/main/java/com/hwtd/mes/collect/dto/SerialPortDTO.java
@@ -0,0 +1,66 @@
+package com.hwtd.mes.collect.dto;
+
+import lombok.Data;
+
+/**
+ * 涓插彛鍙傛暟锛岀敱鎺ュ彛浼犲叆锛堜笉浼犵殑瀛楁浣跨敤榛樿鍊硷級銆�
+ * <p>
+ * 閲囬泦鎺ュ彛 {@code /lims/getFile?fileExtension=.serialPort} 鍜� {@code /lims/openSerialPort} 閮芥敮鎸佽繖浜涘弬鏁帮紝
+ * 渚嬪锛歿@code /lims/openSerialPort?listenName=COM7&baudRate=19200&dataBits=8&stopBits=1&parity=NONE&endMark=*&maxCount=6}
+ */
+@Data
+public class SerialPortDTO {
+
+    /** 榛樿娉㈢壒鐜� */
+    public static final int DEFAULT_BAUD_RATE = 9600;
+    /** 榛樿鏁版嵁浣� */
+    public static final int DEFAULT_DATA_BITS = 8;
+    /** 榛樿鍋滄浣� */
+    public static final int DEFAULT_STOP_BITS = 1;
+    /** 榛樿鏍¢獙浣� */
+    public static final String DEFAULT_PARITY = "NONE";
+    /** 榛樿娴佹帶 */
+    public static final String DEFAULT_FLOW_CONTROL = "NONE";
+    /** 榛樿璇诲彇瓒呮椂锛堟绉掞級 */
+    public static final int DEFAULT_READ_TIMEOUT = 1000;
+    /** 榛樿缁撴潫鏍囧織 */
+    public static final String DEFAULT_END_MARK = "*";
+    /** 榛樿鍗曡疆閲囬泦鏉℃暟涓婇檺 */
+    public static final int DEFAULT_MAX_COUNT = 1;
+    /** 榛樿甯х┖闂茶ˉ甯ф椂闂达紙姣锛� */
+    public static final int DEFAULT_FRAME_IDLE_MILLIS = 200;
+
+    /** 涓插彛鍚嶇О锛屽 COM12锛涘繀浼狅紝涓嶄紶浼氳繑鍥炩�滀覆鍙e悕绉颁笉鑳戒负绌衡�� */
+    private String serialPortName;
+
+    /** 娉㈢壒鐜囷紝榛樿 9600 */
+    private Integer baudRate = DEFAULT_BAUD_RATE;
+
+    /** 鏁版嵁浣� 5~8锛岄粯璁� 8 */
+    private Integer dataBits = DEFAULT_DATA_BITS;
+
+    /** 鍋滄浣� 1銆�2銆�3(1.5 浣�)锛岄粯璁� 1 */
+    private Integer stopBits = DEFAULT_STOP_BITS;
+
+    /** 鏍¢獙浣嶏細NONE/ODD/EVEN/MARK/SPACE锛堜笉鍖哄垎澶у皬鍐欙級锛屼篃鍏煎 0~4 鐨勬暟瀛楋紝榛樿 NONE */
+    private String parity = DEFAULT_PARITY;
+
+    /** 娴佹帶锛歂ONE/RTS_CTS/XON_XOFF锛堜笉鍖哄垎澶у皬鍐欙級锛屼篃鍏煎鏁板瓧甯搁噺锛岄粯璁� NONE */
+    private String flowControl = DEFAULT_FLOW_CONTROL;
+
+    /** 璇诲彇瓒呮椂锛堟绉掞級锛岄粯璁� 1000 */
+    private Integer readTimeout = DEFAULT_READ_TIMEOUT;
+
+    /** 涓�甯ф暟鎹殑缁撴潫鏍囧織锛岄粯璁� *锛涚壒娈婂瓧绗﹀彲鐢� URL 缂栫爜浼犲叆锛屽鎹㈣ %0A */
+    private String endMark = DEFAULT_END_MARK;
+
+    /** 鏁版嵁缂撳瓨闃熷垪闀垮害锛岄粯璁� 6锛涢槦鍒楁弧鏃舵彃鍏ユ渶鏂颁竴鏉°�佺Щ闄ゆ渶鏃т竴鏉★紝鎺ュ彛鏈�澶氳繑鍥� maxCount 鏉℃暟鎹� */
+    private Integer maxCount = DEFAULT_MAX_COUNT;
+
+    /**
+     * 甯х┖闂茶ˉ甯ф椂闂达紙姣锛夛紝榛樿 200锛�
+     * 璁惧鍙戝畬涓�甯у悗瓒呰繃璇ユ椂闂存病鏈夋柊鏁版嵁锛屽氨鎶婃帴鏀剁紦鍐插尯閲屽墿涓嬬殑鏁版嵁褰撲綔涓�甯у彇鍑烘潵锛�
+     * 閬垮厤璁惧鏈�鍚庝竴甯ф病鏈夌粨鏉熸爣蹇楁椂琚紡鎺夛紱璁句负 0 琛ㄧず鍏抽棴绌洪棽琛ュ抚锛屽彧鎸夌粨鏉熸爣蹇楀垏甯с��
+     */
+    private Integer frameIdleMillis = DEFAULT_FRAME_IDLE_MILLIS;
+}
diff --git a/src/main/java/com/chinaztt/mes/docx/handler/GlobalExceptionHandler.java b/src/main/java/com/hwtd/mes/collect/handler/GlobalExceptionHandler.java
similarity index 80%
rename from src/main/java/com/chinaztt/mes/docx/handler/GlobalExceptionHandler.java
rename to src/main/java/com/hwtd/mes/collect/handler/GlobalExceptionHandler.java
index a658526..c0e7388 100644
--- a/src/main/java/com/chinaztt/mes/docx/handler/GlobalExceptionHandler.java
+++ b/src/main/java/com/hwtd/mes/collect/handler/GlobalExceptionHandler.java
@@ -1,6 +1,6 @@
-package com.chinaztt.mes.docx.handler;
+package com.hwtd.mes.collect.handler;
 
-import com.chinaztt.mes.docx.util.Result;
+import com.hwtd.mes.collect.util.Result;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
 
diff --git a/src/main/java/com/hwtd/mes/collect/handler/SerialPortListener.java b/src/main/java/com/hwtd/mes/collect/handler/SerialPortListener.java
new file mode 100644
index 0000000..84409ee
--- /dev/null
+++ b/src/main/java/com/hwtd/mes/collect/handler/SerialPortListener.java
@@ -0,0 +1,644 @@
+package com.hwtd.mes.collect.handler;
+
+import com.hwtd.mes.collect.dto.SerialPortDTO;
+import com.fazecast.jSerialComm.SerialPort;
+import com.fazecast.jSerialComm.SerialPortDataListener;
+import com.fazecast.jSerialComm.SerialPortEvent;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * 涓插彛鐩戝惉锛堟墜鍔ㄦā寮忥級
+ * <p>
+ * 涓庡師鏉モ�滈」鐩惎鍔ㄥ氨寮�濮嬬洃鍚�濈殑鏂瑰紡涓嶅悓锛岀幇鍦ㄦ敼涓烘墜鍔ㄧ洃鍚細
+ * <ul>
+ *     <li>璋冪敤閲囬泦鎺ュ彛锛�/lims/getFile 涓� fileExtension=.serialPort锛夋椂寮�鍚洃鍚紝涓插彛娌℃湁鏁版嵁鏃舵帴鍙h繑鍥炵┖闆嗗悎锛岀敱鍓嶇杞鍙栨暟锛�</li>
+ *     <li>涔熷彲浠ヨ皟鐢� /lims/openSerialPort 鎵嬪姩寮�鍚洃鍚紱</li>
+ *     <li>閲囬泦缁撴潫鍚庤皟鐢� /lims/closeSerialPort 鎵嬪姩鍏抽棴鐩戝惉锛堝箓绛夛紝鏈紑鍚椂璋冪敤涔熶笉浼氭姤閿欙級锛�</li>
+ *     <li>椤圭洰鍋滄鏃惰嚜鍔ㄥ叧闂洃鍚��</li>
+ * </ul>
+ * 涓插彛鍙傛暟锛堜覆鍙e悕銆佹尝鐗圭巼銆佹暟鎹綅銆佸仠姝綅銆佹牎楠屼綅銆佹祦鎺с�佽鍙栬秴鏃躲�佺粨鏉熸爣蹇椼�佸崟杞潯鏁颁笂闄愶級鍏ㄩ儴鐢辨帴鍙d紶鍏ワ紝
+ * 涓嶄紶鏃朵娇鐢� {@link SerialPortDTO} 閲岀殑榛樿鍊硷紱鍙傛暟鍜屽綋鍓嶇敓鏁堢殑鍙傛暟涓嶄竴鑷存椂浼氳嚜鍔ㄦ寜鏂板弬鏁伴噸鏂版墦寮�涓插彛锛�
+ * 鍙傛暟涓�鑷村垯澶嶇敤宸茬粡鎵撳紑鐨勪覆鍙o紝涓嶄細閲嶅鎵撳紑銆�
+ * <p>
+ * 骞跺彂璇存槑锛�
+ * <ul>
+ *     <li>寮�鍚�/鍏抽棴涓插彛缁熶竴鐢� {@link #portLock} 淇濊瘉浜掓枼锛岄噸澶嶈皟鐢ㄥ彧浼氱湡姝f墦寮�涓�娆′覆鍙o紝
+ *         澶氱嚎绋嬪苟鍙戣皟鐢ㄩ噰闆嗘帴鍙d篃涓嶄細閲嶅鎵撳紑銆侀噸澶嶆敞鍐岀洃鍚櫒锛�</li>
+ *     <li>閲囬泦鍒扮殑鏁版嵁鏀惧湪鍚屾闆嗗悎涓紝澶氱嚎绋嬪悓鏃跺彇鏁版椂姣忔潯鏁版嵁鍙細琚竴涓嚎绋嬪彇璧帮紝涓嶄細閲嶅銆佷笉浼氫涪澶憋紱</li>
+ *     <li>鐩戝惉鐘舵�佷娇鐢� volatile 鏍囪锛屽叧闂覆鍙e悗鍥炶皟绾跨▼涓嶄細鍐嶅鐞嗘暟鎹��</li>
+ * </ul>
+ * 鏁版嵁缂撳瓨璇存槑锛氶噰闆嗗埌鐨勬暟鎹寜闃熷垪缂撳瓨锛屾彃鍏ユ渶鏂扮殑涓�鏉★紝瓒呭嚭 maxCount 鏉★紙榛樿 6 鏉★級鏃剁Щ闄ゆ渶鏃х殑涓�鏉★紝
+ * 鍥犳鎺ュ彛姣忔鏈�澶氳繑鍥� maxCount 鏉℃渶鏂扮殑鏁版嵁锛堟寜鎺ユ敹鍏堝悗椤哄簭锛夛紱鏁版嵁琚彇璧板悗闃熷垪娓呯┖锛岄噸鏂板紑濮嬬紦瀛樸��
+ * <p>
+ * 甯у垏鍒嗚鏄庯細榛樿鎸夌粨鏉熸爣蹇� endMark 鍒囧垎鏁版嵁甯э紱濡傛灉璁惧鏈�鍚庝竴甯т笉甯︾粨鏉熸爣蹇楋紙渚嬪姣忓抚浠� * 寮�澶磋�屼笉鏄粨灏撅級锛�
+ * 涓插彛绌洪棽 frameIdleMillis 姣锛堥粯璁� 200ms锛夊悗浼氭妸鎺ユ敹缂撳啿鍖洪噷鍓╀笅鐨勬暟鎹綔涓轰竴甯у彇鍑猴紝閬垮厤婕忔帀鏈�鍚庝竴鏉°��
+ *
+ * @author data-acquisition
+ */
+@Slf4j
+@Component
+public class SerialPortListener {
+
+    /** 涓�鐩存敹涓嶅埌缁撴潫鏍囧織鏃舵帴鏀剁紦鍐插尯鐨勬渶澶ч暱搴︼紝瓒呰繃鍒欎涪寮冿紝闃叉鍐呭瓨鏃犻檺澧為暱 */
+    private static final int MAX_RECEIVE_BUFFER_LENGTH = 4096;
+
+    /**
+     * 涓插彛寮�鍏抽攣锛氬紑鍚� / 鍏抽棴涓插彛浜掓枼銆�
+     * 澶氱嚎绋嬪苟鍙戣皟鐢ㄩ噰闆嗘帴鍙f椂锛屽彧鏈変竴涓嚎绋嬭兘鐪熸鎵撳紑涓插彛锛屽叾瀹冪嚎绋嬪鐢ㄥ凡缁忔墦寮�鐨勪覆鍙c��
+     */
+    private final ReentrantLock portLock = new ReentrantLock();
+
+    /** 涓插彛瀵硅薄锛屽彧鍦ㄦ寔鏈� {@link #portLock} 鏃跺垱寤哄拰鍏抽棴锛涘閮ㄥ彧鍋氱姸鎬佸垽鏂� */
+    private volatile SerialPort serialPort;
+
+    /** 鏄惁姝e湪鐩戝惉锛坴olatile锛氫覆鍙e洖璋冪嚎绋嬩笌涓氬姟绾跨▼涔嬮棿绔嬪嵆鍙锛� */
+    private volatile boolean listening = false;
+
+    /** 褰撳墠鐢熸晥鐨勪覆鍙e弬鏁帮紝鍙湪鎸佹湁 {@link #portLock} 鏃跺彉鏇� */
+    private volatile ActiveSetting activeSetting;
+
+    /** 鏈�鍚庝竴娆℃敹鍒颁覆鍙f暟鎹殑鏃堕棿锛岀敤浜庡垽鏂覆鍙f槸鍚﹀凡缁忕┖闂诧紙绌洪棽琛ュ抚锛� */
+    private volatile long lastDataTime = 0L;
+
+    /** 绌洪棽琛ュ抚浠诲姟锛氳澶囨渶鍚庝竴甯т笉甯︾粨鏉熸爣蹇楁椂锛岄潬瀹冩妸鍓╀綑鏁版嵁鍙栧嚭鏉� */
+    private final ScheduledExecutorService frameFlushExecutor = Executors.newSingleThreadScheduledExecutor(runnable -> {
+        Thread thread = new Thread(runnable, "serial-port-frame-flush");
+        thread.setDaemon(true);
+        return thread;
+    });
+
+    /** 鎺ユ敹缂撳啿鍖猴紝鐢变覆鍙e洖璋冪嚎绋嬪啓鍏ワ紝鐢ㄨ嚜韬綔涓洪攣淇濇姢 */
+    private final StringBuilder receiveBuffer = new StringBuilder();
+
+    /**
+     * 閲囬泦鍒扮殑鏁版嵁锛氫覆鍙e洖璋冪嚎绋嬪啓鍏ワ紝涓氬姟绾跨▼璇诲彇骞舵竻绌猴紝浣跨敤鍚屾闆嗗悎淇濊瘉绾跨▼瀹夊叏銆�
+     * 闃熷垪寮忕紦瀛橈細浠庡熬閮ㄦ彃鍏ユ渶鏂扮殑涓�鏉★紝瓒呭嚭 maxCount 鏃朵粠澶撮儴绉婚櫎鏈�鏃х殑涓�鏉★紝鏈�澶氫繚鐣� maxCount 鏉℃暟鎹��
+     */
+    private final List<String> dataList = Collections.synchronizedList(new ArrayList<>());
+
+    /**
+     * 寮�鍚覆鍙g洃鍚紙骞傜瓑鎿嶄綔锛�
+     * <p>
+     * 澶氱嚎绋嬪悓鏃惰皟鐢ㄦ椂锛氱涓�涓嚎绋嬬湡姝f墦寮�涓插彛骞舵敞鍐岀洃鍚櫒锛屽叾瀹冪嚎绋嬬洿鎺ュ鐢紝涓嶄細閲嶅鎵撳紑涓插彛銆�
+     * 涓插彛鍙傛暟涓庡綋鍓嶇敓鏁堝弬鏁颁笉涓�鑷存椂浼氶噸鏂版墦寮�涓插彛锛涗覆鍙h鎷斿嚭瀵艰嚧寮傚父鏂紑鏃讹紝涓嬫璋冪敤浼氳嚜鍔ㄩ噸鏂版墦寮�銆�
+     *
+     * @param setting 鎺ュ彛浼犲叆鐨勪覆鍙e弬鏁帮紝涓� null 鏃跺叏閮ㄤ娇鐢ㄩ粯璁ゅ��
+     * @return true=鐩戝惉宸插紑鍚紙鍖呭惈鏈璋冪敤涔嬪墠灏卞凡寮�鍚殑鎯呭喌锛夛紱false=寮�鍚け璐ワ紙涓插彛涓嶅瓨鍦ㄣ�佽鍗犵敤锛屾垨涓插彛鍔熻兘鏈惎鐢級
+     * @throws IllegalArgumentException 涓插彛鍙傛暟闈炴硶锛堢敱 GlobalExceptionHandler 杩斿洖缁欏墠绔級
+     */
+    public boolean startListening(SerialPortDTO setting) {
+        // 鍙傛暟鏍¢獙銆佽ˉ榛樿鍊兼斁鍦ㄥ姞閿佷箣鍓嶏細鍙傛暟涓嶅鐩存帴鎶涘紓甯革紝涓嶅崰鐢ㄤ覆鍙�
+        ActiveSetting requested = toActiveSetting(setting);
+        portLock.lock();
+        try {
+            // 宸茬粡鍦ㄧ洃鍚�佷覆鍙f甯镐笖鍙傛暟娌℃湁鍙樺寲锛氱洿鎺ュ鐢紙閲嶅寮�鍚殑鍞竴鍒ゅ畾鐐癸級
+            if (listening && isPortOpen() && requested.equals(activeSetting)) {
+                log.debug("涓插彛 {} 鐩戝惉宸插紑鍚笖鍙傛暟鏈彉鍖栵紝鏈璋冪敤鐩存帴澶嶇敤", requested.getSerialPortName());
+                return true;
+            }
+            if (activeSetting != null && !requested.equals(activeSetting)) {
+                log.info("涓插彛鍙傛暟鍙戠敓鍙樺寲锛屾寜鏂板弬鏁伴噸鏂版墦寮�涓插彛锛歿} -> {}", activeSetting, requested);
+            }
+            // 棣栨寮�鍚�佸弬鏁板彉鍖栥�佷笂娆℃墦寮�澶辫触銆佹垨涓插彛寮傚父鏂紑鏃讹紝鍏堟竻鐞嗘畫鐣欑姸鎬佸啀閲嶆柊鎵撳紑
+            closePortInternal();
+            if (!openPort(requested)) {
+                return false;
+            }
+            activeSetting = requested;
+            log.info("涓插彛 {} 鐩戝惉宸插紑鍚紙{}锛�", requested.getSerialPortName(), requested.describe());
+            return true;
+        } finally {
+            portLock.unlock();
+        }
+    }
+
+    /**
+     * 鍏抽棴涓插彛鐩戝惉锛堝箓绛夋搷浣滐級
+     *
+     * @return true=宸插叧闂紙鍖呭惈鏈璋冪敤涔嬪墠灏辨湭寮�鍚殑鎯呭喌锛夛紱false=鍏抽棴杩囩▼涓嚭鐜板紓甯�
+     */
+    public boolean closeListening() {
+        portLock.lock();
+        try {
+            boolean success = closePortInternal();
+            if (success) {
+                log.info("涓插彛 {} 鐩戝惉宸插叧闂�", getListenName());
+            } else {
+                log.warn("涓插彛 {} 鐩戝惉鍏抽棴澶辫触锛岃妫�鏌ヤ覆鍙g姸鎬�", getListenName());
+            }
+            return success;
+        } finally {
+            portLock.unlock();
+        }
+    }
+
+    /**
+     * 鍙栬蛋褰撳墠閲囬泦鍒扮殑鏁版嵁锛堝彇璧板悗娓呯┖缂撳啿鍖猴級锛屼緵閲囬泦鎺ュ彛璋冪敤銆�
+     * 鍔犻攣 + 蹇収 + 娓呯┖鏄竴涓師瀛愭搷浣滐紝澶氱嚎绋嬪苟鍙戝彇鏁版椂鍚屼竴鏉℃暟鎹彧浼氳涓�涓嚎绋嬪彇璧般��
+     *
+     * @return 鏈鍙栬蛋鐨勬暟鎹紝娌℃湁鏁版嵁鏃惰繑鍥炵┖闆嗗悎
+     */
+    public List<String> drainData() {
+        synchronized (dataList) {
+            if (dataList.isEmpty()) {
+                return new ArrayList<>();
+            }
+            List<String> snapshot = new ArrayList<>(dataList);
+            dataList.clear();
+            log.info("涓插彛 {} 鏈鍙栬蛋 {} 鏉℃暟鎹�", getListenName(), snapshot.size());
+            return snapshot;
+        }
+    }
+
+    /**
+     * @return 鏄惁姝e湪鐩戝惉
+     */
+    public boolean isListening() {
+        return listening && isPortOpen();
+    }
+
+    /**
+     * @return 涓插彛鏄惁宸茬粡鎵撳紑
+     */
+    public boolean isPortOpen() {
+        SerialPort port = serialPort;
+        return port != null && port.isOpen();
+    }
+
+    /**
+     * @return 褰撳墠缂撳啿鍖轰腑杩樻湭琚彇璧扮殑鏁版嵁鏉℃暟
+     */
+    public int dataSize() {
+        synchronized (dataList) {
+            return dataList.size();
+        }
+    }
+
+    /**
+     * @return 褰撳墠鐢熸晥鐨勪覆鍙e悕绉帮紱杩樻病寮�鍚繃鐩戝惉鏃惰繑鍥為厤缃殑榛樿涓插彛鍚嶇О
+     */
+    public String getListenName() {
+        ActiveSetting current = activeSetting;
+        return current != null ? current.getSerialPortName() : "";
+    }
+
+    /**
+     * 椤圭洰鍋滄鏃跺叧闂覆鍙�
+     */
+    @PreDestroy
+    public void destroy() {
+        log.info("椤圭洰鍋滄锛屽叧闂覆鍙� {} 鐩戝惉", getListenName());
+        closeListening();
+        frameFlushExecutor.shutdownNow();
+    }
+
+    /**
+     * 鎶婃帴鍙d紶鍏ョ殑涓插彛鍙傛暟琛ラ綈榛樿鍊煎苟鏍¢獙锛岃浆鎹㈡垚褰撳墠浼氳瘽浣跨敤鐨勫弬鏁板揩鐓�
+     *
+     * @param setting 鎺ュ彛浼犲叆鐨勫弬鏁帮紝涓� null 鏃跺叏閮ㄤ娇鐢ㄩ粯璁ゅ��
+     * @return 褰掍竴鍖栧悗鐨勪覆鍙e弬鏁�
+     * @throws IllegalArgumentException 鍙傛暟闈炴硶
+     */
+    private ActiveSetting toActiveSetting(SerialPortDTO setting) {
+        SerialPortDTO source = setting == null ? new SerialPortDTO() : setting;
+        String portName = isBlank(source.getSerialPortName()) ? "" : source.getSerialPortName().trim();
+        if (isBlank(portName)) {
+            throw new IllegalArgumentException("涓插彛鍚嶇О涓嶈兘涓虹┖锛氳閫氳繃 listenName 鍙傛暟浼犲叆");
+        }
+        int baudRate = intOrDefault(source.getBaudRate(), SerialPortDTO.DEFAULT_BAUD_RATE);
+        if (baudRate <= 0) {
+            throw new IllegalArgumentException("涓插彛鍙傛暟 baudRate 闈炴硶锛�" + baudRate + "锛屽繀椤诲ぇ浜� 0");
+        }
+        int dataBits = checkRange("dataBits", intOrDefault(source.getDataBits(), SerialPortDTO.DEFAULT_DATA_BITS), 5, 8);
+        int stopBits = checkRange("stopBits", intOrDefault(source.getStopBits(), SerialPortDTO.DEFAULT_STOP_BITS), 1, 3);
+        int readTimeout = intOrDefault(source.getReadTimeout(), SerialPortDTO.DEFAULT_READ_TIMEOUT);
+        if (readTimeout < 0) {
+            throw new IllegalArgumentException("涓插彛鍙傛暟 readTimeout 闈炴硶锛�" + readTimeout + "锛屼笉鑳藉皬浜� 0");
+        }
+        int maxCount = intOrDefault(source.getMaxCount(), SerialPortDTO.DEFAULT_MAX_COUNT);
+        if (maxCount < 1) {
+            throw new IllegalArgumentException("涓插彛鍙傛暟 maxCount 闈炴硶锛�" + maxCount + "锛屼笉鑳藉皬浜� 1");
+        }
+        int frameIdleMillis = intOrDefault(source.getFrameIdleMillis(), SerialPortDTO.DEFAULT_FRAME_IDLE_MILLIS);
+        if (frameIdleMillis < 0) {
+            throw new IllegalArgumentException("涓插彛鍙傛暟 frameIdleMillis 闈炴硶锛�" + frameIdleMillis + "锛屼笉鑳藉皬浜� 0");
+        }
+        String endMark = isBlank(source.getEndMark()) ? SerialPortDTO.DEFAULT_END_MARK : source.getEndMark();
+        String parity = isBlank(source.getParity()) ? SerialPortDTO.DEFAULT_PARITY : source.getParity();
+        String flowControl = isBlank(source.getFlowControl()) ? SerialPortDTO.DEFAULT_FLOW_CONTROL : source.getFlowControl();
+        return new ActiveSetting(portName, baudRate, dataBits, stopBits,
+                parseParity(parity), parseFlowControl(flowControl), readTimeout, endMark, maxCount, frameIdleMillis);
+    }
+
+    /**
+     * 鎵撳紑涓插彛骞舵敞鍐屾暟鎹洃鍚櫒锛堣皟鐢ㄦ柟蹇呴』鎸佹湁 {@link #portLock}锛�
+     *
+     * @return 鏄惁鎵撳紑鎴愬姛
+     */
+    private boolean openPort(ActiveSetting setting) {
+        SerialPort port;
+        try {
+            port = SerialPort.getCommPort(setting.getSerialPortName());
+            port.setBaudRate(setting.getBaudRate());        // 娉㈢壒鐜�
+            port.setNumDataBits(setting.getDataBits());     // 鏁版嵁浣�
+            port.setNumStopBits(setting.getStopBits());     // 鍋滄浣�
+            port.setParity(setting.getParity());            // 鏍¢獙浣�
+            port.setFlowControl(setting.getFlowControl());  // 娴佹帶
+            port.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, setting.getReadTimeout(), 0); // 璇诲彇瓒呮椂
+
+            if (!port.openPort()) {
+                log.error("涓插彛 {} 鎵撳紑澶辫触锛岃妫�鏌ヤ覆鍙f槸鍚﹀瓨鍦ㄣ�佹槸鍚﹁鍏朵粬绋嬪簭鍗犵敤", setting.getSerialPortName());
+                return false;
+            }
+        } catch (Throwable t) {
+            // 涓插彛鍚嶇О闈炴硶銆佸弬鏁颁笉琚┍鍔ㄦ敮鎸併�侀┍鍔ㄥ紓甯哥瓑鎯呭喌缁熶竴杩斿洖澶辫触锛岄伩鍏嶆妸寮傚父鎶涚粰璋冪敤鏂癸紙HTTP 绾跨▼锛�
+            log.error("涓插彛 {} 鎵撳紑寮傚父锛歿}", setting.getSerialPortName(), t.getMessage(), t);
+            return false;
+        }
+        serialPort = port;
+        // 鏂颁竴杞噰闆嗗紑濮嬶細娓呮帀涓婁竴杞湭鎺ユ敹瀹屾暣鐨勫崐鍖呭拰娌¤鍙栬蛋鐨勬暟鎹紝閬垮厤涓婁竴杞殑鏁版嵁娣峰叆鏈疆缁撴灉
+        synchronized (receiveBuffer) {
+            receiveBuffer.setLength(0);
+        }
+        discardCollectedData();
+        // 鍏堢疆涓虹洃鍚腑鍐嶆敞鍐岀洃鍚櫒锛岄伩鍏嶆敞鍐屽畬鎴愬悗绗竴鎵规暟鎹洜鐘舵�佹湭灏辩华琚涪寮�
+        listening = true;
+        try {
+            port.addDataListener(buildDataListener(port, setting));
+        } catch (Exception e) {
+            log.error("涓插彛 {} 娉ㄥ唽鏁版嵁鐩戝惉鍣ㄥけ璐�", setting.getSerialPortName(), e);
+            // 娉ㄥ唽澶辫触鏃跺洖婊氾紝閬垮厤涓插彛琚崰鐢ㄥ嵈璇讳笉鍒版暟鎹�
+            closePortInternal();
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 鍏抽棴涓插彛骞堕噴鏀捐祫婧愶紙璋冪敤鏂瑰繀椤绘寔鏈� {@link #portLock}锛屾湰鏂规硶涓嶄細鎶涘嚭寮傚父锛�
+     *
+     * @return 鏄惁姝e父鍏抽棴
+     */
+    private boolean closePortInternal() {
+        SerialPort port = serialPort;
+        serialPort = null;
+        // 鍏堢疆涓烘湭鐩戝惉锛氫覆鍙e洖璋冪嚎绋嬩笉鍐嶅鐞嗗悗缁暟鎹�
+        listening = false;
+        boolean success = true;
+        if (port != null) {
+            try {
+                port.removeDataListener(); // 绉婚櫎鐩戝惉锛岄伩鍏嶅叧闂繃绋嬩腑鍥炶皟杩樺湪瑙﹀彂
+                if (port.isOpen() && !port.closePort()) {
+                    log.warn("涓插彛 {} 鍏抽棴杩斿洖澶辫触锛岃纭涓插彛鏄惁宸茶鎷斿嚭", getListenName());
+                    success = false;
+                }
+            } catch (Exception e) {
+                log.error("鍏抽棴涓插彛 {} 鍑虹幇寮傚父", getListenName(), e);
+                success = false;
+            }
+        }
+        // 涓㈠純鏈帴鏀跺畬鏁寸殑鍗婂寘鏁版嵁锛岄伩鍏嶄笅娆″紑鍚椂鎷煎嚭閿欒鏁版嵁
+        synchronized (receiveBuffer) {
+            receiveBuffer.setLength(0);
+        }
+        return success;
+    }
+
+    /**
+     * 涓㈠純涓婁竴杞病鏈夊彇璧扮殑鏁版嵁锛堣皟鐢ㄦ柟蹇呴』鎸佹湁 {@link #portLock}锛�
+     */
+    private void discardCollectedData() {
+        List<String> abandoned = drainData();
+        if (!abandoned.isEmpty()) {
+            log.warn("涓插彛 {} 寮�鍚柊涓�杞洃鍚紝涓㈠純涓婁竴杞湭琚彇璧扮殑 {} 鏉℃暟鎹細{}", getListenName(), abandoned.size(), abandoned);
+        }
+    }
+
+    /**
+     * 鏋勫缓涓插彛鏁版嵁鐩戝惉鍣紝鏁版嵁鍒拌揪鏃跺湪 jSerialComm 鐨勭洃鍚嚎绋嬩腑鍥炶皟
+     * <p>
+     * 鏈疆浣跨敤鐨勫弬鏁帮紙缁撴潫鏍囧織銆佹潯鏁颁笂闄愶級鐩存帴鍥哄寲鍦ㄧ洃鍚櫒閲岋紝閬垮厤瑙f瀽鏃惰鍒颁笅涓�杞殑鍙傛暟銆�
+     */
+    private SerialPortDataListener buildDataListener(final SerialPort port, final ActiveSetting setting) {
+        return new SerialPortDataListener() {
+            /** 鎸囧畾鐩戝惉鐨勪簨浠剁被鍨嬶細鏁版嵁鍙敤鏃惰Е鍙� */
+            @Override
+            public int getListeningEvents() {
+                return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;
+            }
+
+            /** 鏁版嵁鍙敤鏃剁殑澶勭悊閫昏緫 */
+            @Override
+            public void serialEvent(SerialPortEvent event) {
+                if (event.getEventType() != SerialPort.LISTENING_EVENT_DATA_AVAILABLE) {
+                    return;
+                }
+                // 鍏抽棴涓插彛鍚庡彲鑳借繕鏈変竴娆″洖璋冨湪璺笂锛岃繖閲屽啀鍏滃簳鍒ゆ柇涓�娆�
+                if (!listening || !setting.equals(activeSetting)) {
+                    return;
+                }
+                try {
+                    int available = port.bytesAvailable();
+                    if (available <= 0) {
+                        return;
+                    }
+                    // 璇诲彇缂撳啿鍖轰腑鐨勬墍鏈夊瓧鑺�
+                    byte[] buffer = new byte[available];
+                    int readBytes = port.readBytes(buffer, buffer.length);
+                    if (readBytes > 0) {
+                        // 鎶婃湰娆℃敹鍒扮殑闆舵暎鏁版嵁杞垚瀛楃涓诧紝杩藉姞鍒扮紦鍐插尯
+                        parseAndCollect(setting, new String(buffer, 0, readBytes, StandardCharsets.UTF_8));
+                    }
+                } catch (Exception e) {
+                    // 鍗曟璇诲彇寮傚父涓嶅奖鍝嶅悗缁洃鍚�
+                    log.error("涓插彛 {} 璇诲彇鏁版嵁寮傚父锛歿}", setting.getSerialPortName(), e.getMessage(), e);
+                }
+            }
+        };
+    }
+
+    /**
+     * 瑙f瀽鎺ユ敹鍒扮殑鏁版嵁锛氭寜缁撴潫鏍囧織鍒囧垎锛岃В鏋愭垚鏁板�煎悗鏀惧叆閲囬泦缁撴灉
+     *
+     * @param setting  鏈疆閲囬泦浣跨敤鐨勪覆鍙e弬鏁�
+     * @param received 鏈浠庝覆鍙h鍒扮殑瀛楃涓�
+     */
+    private void parseAndCollect(ActiveSetting setting, String received) {
+        List<String> completeValues = new ArrayList<>();
+        synchronized (receiveBuffer) {
+            // 璁板綍鏀跺埌鏁版嵁鐨勬椂闂达紝绌洪棽琛ュ抚闈犲畠鍒ゆ柇涓插彛鏄惁宸茬粡娌℃湁鏂版暟鎹�
+            lastDataTime = System.currentTimeMillis();
+            receiveBuffer.append(received);
+            // 妫�鏌ョ紦鍐插尯鏄惁鍖呭惈鈥滅粨鏉熸爣蹇椻�濓紝寰幆澶勭悊鎵�鏈夊畬鏁存暟鎹�
+            int endIndex = receiveBuffer.indexOf(setting.getEndMark());
+            while (endIndex != -1) {
+                // 鎻愬彇鈥滃紑澶村埌缁撴潫鏍囧織鈥濈殑瀹屾暣鏁版嵁
+                String completeData = normalizeFrame(receiveBuffer.substring(0, endIndex));
+                // 绉婚櫎缂撳啿鍖轰腑宸插鐞嗙殑閮ㄥ垎锛堜繚鐣欏墿浣欐湭瀹屾垚鐨勫唴瀹癸級
+                receiveBuffer.delete(0, endIndex + setting.getEndMark().length());
+                if (!completeData.isEmpty()) {
+                    try {
+                        completeValues.add(completeData);
+                    } catch (NumberFormatException e) {
+                        // 骞叉壈鏁版嵁鍙拷鐣ュ綋鍓嶈繖涓�鏉★紝涓嶅奖鍝嶅悗缁暟鎹В鏋�
+                        log.warn("涓插彛 {} 鏀跺埌鏃犳硶瑙f瀽鐨勬暟鎹紝宸插拷鐣ワ細[{}]", setting.getSerialPortName(), completeData);
+                    }
+                }
+                endIndex = receiveBuffer.indexOf(setting.getEndMark());
+            }
+            // 涓�鐩存病鏈夌粨鏉熸爣蹇楁椂缂撳啿鍖轰細鎸佺画澧為暱锛岃秴杩囦笂闄愮洿鎺ヤ涪寮冿紝闃叉鍐呭瓨娉勬紡
+            if (receiveBuffer.length() > MAX_RECEIVE_BUFFER_LENGTH) {
+                log.warn("涓插彛 {} 鎺ユ敹缂撳啿鍖鸿秴杩� {} 涓瓧绗︿粛鏈敹鍒扮粨鏉熸爣蹇楋紝宸蹭涪寮冪紦瀛樻暟鎹�",
+                        setting.getSerialPortName(), MAX_RECEIVE_BUFFER_LENGTH);
+                receiveBuffer.setLength(0);
+            }
+        }
+        if (completeValues.isEmpty()) {
+            return;
+        }
+        enqueue(setting, completeValues);
+    }
+
+    /**
+     * 鎶婃暟鎹斁鍏ョ紦瀛橀槦鍒楋細浠庡熬閮ㄦ彃鍏ユ渶鏂扮殑涓�鏉★紝瓒呭嚭 maxCount 鏃朵粠澶撮儴绉婚櫎鏈�鏃х殑涓�鏉�
+     */
+    private void enqueue(ActiveSetting setting, List<String> values) {
+        synchronized (dataList) {
+            for (String value : values) {
+                dataList.add(value);
+                while (dataList.size() > setting.getMaxCount()) {
+                    String removed = dataList.remove(0);
+                    log.debug("涓插彛 {} 缂撳瓨宸叉弧 {} 鏉★紝绉婚櫎鏈�鏃х殑涓�鏉℃暟鎹� {}",
+                            setting.getSerialPortName(), setting.getMaxCount(), removed);
+                }
+                log.info("涓插彛 {} 鎺ユ敹鍒版暟鎹�-->{}", setting.getSerialPortName(), value);
+            }
+        }
+    }
+
+    /**
+     * 鍚姩绌洪棽琛ュ抚浠诲姟锛氳澶囨渶鍚庝竴甯т笉甯︾粨鏉熸爣蹇楁椂锛岄潬瀹冩妸鍓╀綑鏁版嵁鍙栧嚭鏉�
+     */
+    @PostConstruct
+    void startFrameFlushTask() {
+        frameFlushExecutor.scheduleWithFixedDelay(this::flushIdleFrame, 100, 100, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * 绌洪棽琛ュ抚锛氫覆鍙h秴杩� frameIdleMillis 娌℃湁鏂版暟鎹椂锛屾妸鎺ユ敹缂撳啿鍖洪噷鍓╀笅鐨勬暟鎹綋浣滀竴甯у彇鍑烘潵銆�
+     * <p>
+     * 鍏稿瀷鍦烘櫙锛氳澶囨瘡甯т互鏌愪釜瀛楃鈥滃紑澶粹�濊�屼笉鏄�滅粨灏锯�濓紙濡� *0 1 0锛夛紝
+     * 杩欐椂鏈�鍚庝竴甯т笉浼氭湁鍚庣画鏁版嵁鏉ヨЕ鍙戝垏鍒嗭紝鍙潬缁撴潫鏍囧織姘歌繙鍙栦笉鍑烘潵銆�
+     * 濡傛灉璁惧姣忓抚閮藉甫缁撴潫鏍囧織锛岀紦鍐插尯鍦ㄦ瘡娆″垏鍒嗗悗閮芥槸绌虹殑锛岃繖閲屼笉浼氬仛浠讳綍浜嬨��
+     */
+    private void flushIdleFrame() {
+        try {
+            ActiveSetting setting = activeSetting;
+            if (!listening || setting == null || setting.getFrameIdleMillis() <= 0) {
+                return;
+            }
+            String pending;
+            synchronized (receiveBuffer) {
+                if (receiveBuffer.length() == 0) {
+                    return;
+                }
+                long idle = System.currentTimeMillis() - lastDataTime;
+                if (idle < setting.getFrameIdleMillis()) {
+                    return;
+                }
+                pending = normalizeFrame(receiveBuffer.toString());
+                receiveBuffer.setLength(0);
+                log.info("涓插彛 {} 宸茬┖闂� {}ms 娌℃湁鏀跺埌鏂扮殑缁撴潫鏍囧織锛屾妸缂撳啿鍖哄墿浣欐暟鎹� [{}] 浣滀负涓�甯у彇鍑�",
+                        setting.getSerialPortName(), idle, pending);
+            }
+            if (!pending.isEmpty()) {
+                enqueue(setting, Collections.singletonList(pending));
+            }
+        } catch (Exception e) {
+            // 琛ュ抚寮傚父涓嶈兘褰卞搷鍚庣画琛ュ抚
+            log.error("涓插彛绌洪棽琛ュ抚寮傚父锛歿}", e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 鍘绘帀鏁版嵁閲岀殑鎹㈣鍜岄灏剧┖鐧�
+     */
+    private static String normalizeFrame(String value) {
+        return value.replace("\n", "").replace("\r", "").trim();
+    }
+
+    /**
+     * 瑙f瀽鏍¢獙浣嶅弬鏁帮細鏀寔 NONE/ODD/EVEN/MARK/SPACE锛堜笉鍖哄垎澶у皬鍐欙級锛屼篃鍏煎 0~4 鐨勬暟瀛�
+     */
+    private static int parseParity(String parity) {
+        String value = parity.trim().toUpperCase(Locale.ROOT);
+        switch (value) {
+            case "NONE":
+            case "N":
+            case "NO":
+                return SerialPort.NO_PARITY;
+            case "ODD":
+            case "O":
+                return SerialPort.ODD_PARITY;
+            case "EVEN":
+            case "E":
+                return SerialPort.EVEN_PARITY;
+            case "MARK":
+            case "M":
+                return SerialPort.MARK_PARITY;
+            case "SPACE":
+            case "S":
+                return SerialPort.SPACE_PARITY;
+            default:
+                int number = parseInt(value, -1);
+                if (number >= SerialPort.NO_PARITY && number <= SerialPort.SPACE_PARITY) {
+                    return number;
+                }
+                throw new IllegalArgumentException("涓插彛鍙傛暟 parity 闈炴硶锛�" + parity + "锛屽彲閫� NONE/ODD/EVEN/MARK/SPACE锛屾垨 0~4 鐨勬暟瀛�");
+        }
+    }
+
+    /**
+     * 瑙f瀽娴佹帶鍙傛暟锛氭敮鎸� NONE/RTS_CTS/XON_XOFF锛堜笉鍖哄垎澶у皬鍐欙級锛屼篃鍏煎 jSerialComm 鐨勬暟瀛楀父閲�
+     */
+    private static int parseFlowControl(String flowControl) {
+        String value = flowControl.trim().toUpperCase(Locale.ROOT).replace('-', '_');
+        switch (value) {
+            case "NONE":
+            case "OFF":
+            case "DISABLED":
+                return SerialPort.FLOW_CONTROL_DISABLED;
+            case "RTS_CTS":
+            case "RTSCTS":
+            case "HARDWARE":
+                return SerialPort.FLOW_CONTROL_RTS_ENABLED | SerialPort.FLOW_CONTROL_CTS_ENABLED;
+            case "XON_XOFF":
+            case "XONXOFF":
+            case "SOFTWARE":
+                return SerialPort.FLOW_CONTROL_XONXOFF_IN_ENABLED | SerialPort.FLOW_CONTROL_XONXOFF_OUT_ENABLED;
+            default:
+                int number = parseInt(value, -1);
+                if (number >= 0) {
+                    return number;
+                }
+                throw new IllegalArgumentException("涓插彛鍙傛暟 flowControl 闈炴硶锛�" + flowControl + "锛屽彲閫� NONE/RTS_CTS/XON_XOFF锛屾垨鏁板瓧甯搁噺");
+        }
+    }
+
+    /**
+     * 鏍¢獙鍙栧�艰寖鍥�
+     */
+    private static int checkRange(String name, int value, int min, int max) {
+        if (value < min || value > max) {
+            throw new IllegalArgumentException("涓插彛鍙傛暟 " + name + " 闈炴硶锛�" + value + "锛屽彇鍊艰寖鍥� " + min + "~" + max);
+        }
+        return value;
+    }
+
+    /**
+     * 鎺ュ彛娌′紶锛坣ull锛夋椂浣跨敤榛樿鍊�
+     */
+    private static int intOrDefault(Integer value, int defaultValue) {
+        return value == null ? defaultValue : value;
+    }
+
+    /**
+     * 瑙f瀽鏁板瓧锛岃В鏋愪笉浜嗚繑鍥為粯璁ゅ��
+     */
+    private static int parseInt(String value, int defaultValue) {
+        try {
+            return Integer.parseInt(value);
+        } catch (NumberFormatException e) {
+            return defaultValue;
+        }
+    }
+
+    private static boolean isBlank(String value) {
+        return value == null || value.trim().isEmpty();
+    }
+
+    /**
+     * 褰撳墠鐢熸晥鐨勪覆鍙e弬鏁帮紙鎺ュ彛鍙傛暟琛ラ粯璁ゅ�笺�佹牎楠屻�佸綊涓�鍖栦箣鍚庣殑蹇収锛岀敤浜庡垽鏂弬鏁版槸鍚﹀彂鐢熷彉鍖栵級
+     */
+    @Data
+    private static final class ActiveSetting {
+
+        /** 涓插彛鍚嶇О */
+        private final String serialPortName;
+        /** 娉㈢壒鐜� */
+        private final int baudRate;
+        /** 鏁版嵁浣� */
+        private final int dataBits;
+        /** 鍋滄浣� */
+        private final int stopBits;
+        /** 鏍¢獙浣嶏紙jSerialComm 甯搁噺锛� */
+        private final int parity;
+        /** 娴佹帶锛坖SerialComm 甯搁噺锛� */
+        private final int flowControl;
+        /** 璇诲彇瓒呮椂锛堟绉掞級 */
+        private final int readTimeout;
+        /** 涓�甯ф暟鎹殑缁撴潫鏍囧織 */
+        private final String endMark;
+        /** 鍗曡疆閲囬泦鏈�澶氫繚鐣欑殑鏁版嵁鏉℃暟 */
+        private final int maxCount;
+        /** 甯х┖闂茶ˉ甯ф椂闂达紙姣锛夛紝0 琛ㄧず鍏抽棴 */
+        private final int frameIdleMillis;
+
+        /**
+         * 鏃ュ織鐢ㄧ殑鍙傛暟鎻忚堪
+         */
+        String describe() {
+            return "娉㈢壒鐜� " + baudRate
+                    + "锛屾暟鎹綅 " + dataBits
+                    + "锛屽仠姝綅 " + stopBits
+                    + "锛屾牎楠屼綅 " + parityName()
+                    + "锛屾祦鎺� " + flowControlName()
+                    + "锛岃鍙栬秴鏃� " + readTimeout + "ms"
+                    + "锛岀粨鏉熸爣蹇� [" + endMark + "]"
+                    + "锛屽崟杞渶澶� " + maxCount + " 鏉�"
+                    + "锛岀┖闂茶ˉ甯� " + (frameIdleMillis > 0 ? frameIdleMillis + "ms" : "鍏抽棴");
+        }
+
+        private String parityName() {
+            switch (parity) {
+                case SerialPort.ODD_PARITY:
+                    return "濂囨牎楠�";
+                case SerialPort.EVEN_PARITY:
+                    return "鍋舵牎楠�";
+                case SerialPort.MARK_PARITY:
+                    return "MARK";
+                case SerialPort.SPACE_PARITY:
+                    return "SPACE";
+                default:
+                    return "鏃犳牎楠�";
+            }
+        }
+
+        private String flowControlName() {
+            if (flowControl == SerialPort.FLOW_CONTROL_DISABLED) {
+                return "鏃�";
+            }
+            if (flowControl == (SerialPort.FLOW_CONTROL_RTS_ENABLED | SerialPort.FLOW_CONTROL_CTS_ENABLED)) {
+                return "RTS/CTS";
+            }
+            if (flowControl == (SerialPort.FLOW_CONTROL_XONXOFF_IN_ENABLED | SerialPort.FLOW_CONTROL_XONXOFF_OUT_ENABLED)) {
+                return "XON/XOFF";
+            }
+            return String.valueOf(flowControl);
+        }
+    }
+}
diff --git a/src/main/java/com/hwtd/mes/collect/service/DataCollectionService.java b/src/main/java/com/hwtd/mes/collect/service/DataCollectionService.java
new file mode 100644
index 0000000..e24bd59
--- /dev/null
+++ b/src/main/java/com/hwtd/mes/collect/service/DataCollectionService.java
@@ -0,0 +1,14 @@
+package com.hwtd.mes.collect.service;
+
+import com.hwtd.mes.collect.dto.DatabaseDTO;
+
+import java.util.List;
+import java.util.Map;
+
+public interface DataCollectionService {
+
+    List<Map<String,Object>> getAccessData(DatabaseDTO databaseDTO);
+
+    List<Map<String,Object>> getPostgreSqlData(DatabaseDTO databaseDTO);
+
+}
diff --git a/src/main/java/com/hwtd/mes/collect/service/impl/DataCollectionServiceImpl.java b/src/main/java/com/hwtd/mes/collect/service/impl/DataCollectionServiceImpl.java
new file mode 100644
index 0000000..678eb5e
--- /dev/null
+++ b/src/main/java/com/hwtd/mes/collect/service/impl/DataCollectionServiceImpl.java
@@ -0,0 +1,159 @@
+package com.hwtd.mes.collect.service.impl;
+
+import com.hwtd.mes.collect.dto.DatabaseDTO;
+import com.hwtd.mes.collect.service.DataCollectionService;
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.sql.*;
+import java.util.*;
+
+@Service
+@Slf4j
+public class DataCollectionServiceImpl implements DataCollectionService {
+
+    /**
+     * 澶勭悊mdb鏁版嵁搴撴帓闄ゅ瓧娈电被鍨�
+     */
+    private final static List<String> MDB_EXCLUDE_TYPES = Arrays.asList("java.sql.Blob");
+
+    @Override
+    public List<Map<String, Object>> getAccessData(DatabaseDTO databaseDTO) {
+        List<Map<String,Object>> list = new ArrayList<>();
+        try{
+            Properties prop = new Properties();
+            //璁剧疆缂栫爜
+            prop.put("charSet", "UTF-8");
+            prop.put("user",  StringUtils.isNotBlank(databaseDTO.getUserName())?databaseDTO.getUserName():"");
+            prop.put("password", StringUtils.isNotBlank(databaseDTO.getPassword())?databaseDTO.getPassword():"");
+            //鏁版嵁鍦板潃
+            String dbUrl = "jdbc:ucanaccess://" + databaseDTO.getFilePath();
+            //寮曞叆椹卞姩
+            Class.forName("net.ucanaccess.jdbc.UcanaccessDriver").newInstance();
+            Connection conn = null;
+            PreparedStatement preparedStatement = null;
+            ResultSet rs = null;
+            //杩炴帴鏁版嵁搴撹祫婧�
+            conn = DriverManager.getConnection(dbUrl, prop);
+            try {
+                //閬嶅巻鑾峰彇澶氬紶琛ㄦ暟鎹�
+                String s = "SELECT "+databaseDTO.getPointColumns()+" FROM " + databaseDTO.getTableName() + " WHERE 1=1";
+                if(StringUtils.isNotBlank(databaseDTO.getMainColumn()) && StringUtils.isNotBlank(databaseDTO.getBatchCode())){
+                    s+=" and " + databaseDTO.getMainColumn() + " = '" + databaseDTO.getBatchCode()+ "'";
+                }
+                if(StringUtils.isNotBlank(databaseDTO.getOrderColumn())){
+                    String orderRule = StringUtils.isNotBlank(databaseDTO.getOrderRule())?databaseDTO.getOrderRule():"ASC";
+                    s+=" ORDER BY " + databaseDTO.getOrderColumn() + " " + orderRule;
+                }
+                preparedStatement = conn.prepareStatement(s);
+                rs = preparedStatement.executeQuery();
+                ResultSetMetaData data = rs.getMetaData();
+                while (rs.next()) {
+                    Map<String, Object> map = new HashMap<>();
+                    for (int i = 1; i <= data.getColumnCount(); i++) {
+                        //鍒楀悕
+                        String columnName = data.getColumnName(i);
+                        //鍒楀瓧娈电被鍨�
+                        String columnClassName = data.getColumnClassName(i);
+                        Object columnValue = null;
+                        if(!MDB_EXCLUDE_TYPES.contains(columnClassName)){
+                            columnValue = rs.getObject(i);
+                        }
+                        map.put(columnName, columnValue);
+                    }
+                    list.add(map);
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            } finally {
+                closeA1l(conn, preparedStatement, rs);
+            }
+            return list;
+        }catch (Exception e){
+            throw new RuntimeException("Access鏁版嵁搴撻噰闆嗗紓甯革細"+e.getMessage());
+        }
+    }
+
+    @Override
+    public List<Map<String, Object>> getPostgreSqlData(DatabaseDTO databaseDTO) {
+        List<Map<String, Object>> dataList = new ArrayList<>();
+        try{
+            String dbName = databaseDTO.getDatabaseName();
+            String user = databaseDTO.getUserName();
+            String password = databaseDTO.getPassword();
+            // 浠� GetFileDto 鑾峰彇鏁版嵁琛ㄥ悕锛屽搴斻�愭暟鎹簱琛ㄥ悕銆戝瓧娈�
+            String table = databaseDTO.getTableName();
+            // 妫�鏌ユ暟鎹簱鍚嶅拰琛ㄥ悕鏄惁涓虹┖
+            if (dbName == null || dbName.isEmpty() || table == null || table.isEmpty()) {
+                throw new RuntimeException("鏁版嵁搴撳悕鎴栬〃鍚嶄笉鑳戒负绌�");
+            }
+            // 鏁版嵁搴撹繛鎺ヤ俊鎭�
+            String url = String.format("jdbc:postgresql://%s:%s/%s",databaseDTO.getIpAddress(),databaseDTO.getServerPort(),dbName);
+            Connection connection = null;
+            PreparedStatement preparedStatement = null;
+            ResultSet resultSet = null;
+
+            HikariConfig config = new HikariConfig();
+            config.setJdbcUrl(url);
+            config.setUsername(user);
+            config.setPassword(password);
+            config.setMaximumPoolSize(10);
+            config.setConnectionTimeout(30000);
+
+            HikariDataSource ds = new HikariDataSource(config);
+            try {
+                // 寤虹珛杩炴帴
+                connection = ds.getConnection();
+                // 鏋勫缓鍩虹 SQL
+                String sql = "SELECT "+databaseDTO.getPointColumns()+" FROM "+table+" WHERE 1=1";
+                if(StringUtils.isNotBlank(databaseDTO.getMainColumn()) && StringUtils.isNotBlank(databaseDTO.getBatchCode())){
+                    sql+=" AND (" + databaseDTO.getMainColumn() + " = TRIM('" + databaseDTO.getBatchCode()+ "')";
+                }
+                if(StringUtils.isNotBlank(databaseDTO.getOrderColumn())){
+                    String orderRule = StringUtils.isNotBlank(databaseDTO.getOrderRule())?databaseDTO.getOrderRule():"ASC";
+                    sql+=" ORDER BY " + databaseDTO.getOrderColumn() + " " + orderRule;
+                }
+                // 鍒涘缓 PreparedStatement 瀵硅薄鎵ц SQL
+                preparedStatement = connection.prepareStatement(sql);
+                resultSet = preparedStatement.executeQuery();
+                ResultSetMetaData metaData = resultSet.getMetaData();
+                int columnCount = metaData.getColumnCount();
+                // 閬嶅巻缁撴灉闆嗚幏鍙栨暟鎹�
+                while (resultSet.next()) {
+                    Map<String, Object> rowData = new HashMap<>();
+                    for (int i = 1; i <= columnCount; i++) {
+                        String columnName = metaData.getColumnName(i);
+                        rowData.put(columnName, resultSet.getObject(i));
+                    }
+                    dataList.add(rowData);
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            } finally {
+                closeA1l(connection, preparedStatement, resultSet);
+            }
+            return dataList;
+        }catch (Exception e){
+            throw new RuntimeException("PostgreSql鏁版嵁搴撻噰闆嗗紓甯革細"+e.getMessage());
+        }
+    }
+
+    private static void closeA1l(Connection conn, PreparedStatement preparedStatement, ResultSet rs) {
+        try {
+            if (null != rs) {
+                rs.close();
+            }
+            if (null != preparedStatement) {
+                preparedStatement.close();
+            }
+            if (null != conn) {
+                conn.close();
+            }
+        } catch (Exception ignore) {
+        }
+    }
+
+}
diff --git a/src/main/java/com/chinaztt/mes/docx/util/Result.java b/src/main/java/com/hwtd/mes/collect/util/Result.java
similarity index 96%
rename from src/main/java/com/chinaztt/mes/docx/util/Result.java
rename to src/main/java/com/hwtd/mes/collect/util/Result.java
index 63f4c24..3a17d09 100644
--- a/src/main/java/com/chinaztt/mes/docx/util/Result.java
+++ b/src/main/java/com/hwtd/mes/collect/util/Result.java
@@ -3,9 +3,9 @@
 // (powered by FernFlower decompiler)
 //
 
-package com.chinaztt.mes.docx.util;
+package com.hwtd.mes.collect.util;
 
-import com.chinaztt.mes.docx.constant.CommonConstants;
+import com.hwtd.mes.collect.constant.CommonConstants;
 
 import java.io.Serializable;
 
diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF
index 66f3248..7308c6f 100644
--- a/src/main/resources/META-INF/MANIFEST.MF
+++ b/src/main/resources/META-INF/MANIFEST.MF
@@ -1,3 +1,3 @@
 Manifest-Version: 1.0
-Main-Class: com.chinaztt.mes.docx.DataAcquisitionApplication
+Main-Class: com.hwtd.mes.collect.DataAcquisitionApplication
 
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index f9cabdb..969a046 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -2,8 +2,4 @@
   port: 9527
 
 logging:
-  file-location: D:\lims-acquistion\logs
-
-serialPort:
-  enable: false # 鏄惁寮�鍚覆鍙g洃鍚�
-  listenName: COM4 # 鐩戝惉鐨勪覆鍙e悕绉�
\ No newline at end of file
+  file-location: D:\lims-acquistion\logs
\ No newline at end of file
diff --git a/src/test/java/com/chinaztt/mes/docx/DataAcquisitionApplicationTests.java b/src/test/java/com/hwtd/mes/collect/DataAcquisitionApplicationTests.java
similarity index 93%
rename from src/test/java/com/chinaztt/mes/docx/DataAcquisitionApplicationTests.java
rename to src/test/java/com/hwtd/mes/collect/DataAcquisitionApplicationTests.java
index f531c24..81c1408 100644
--- a/src/test/java/com/chinaztt/mes/docx/DataAcquisitionApplicationTests.java
+++ b/src/test/java/com/hwtd/mes/collect/DataAcquisitionApplicationTests.java
@@ -1,4 +1,4 @@
-package com.chinaztt.mes.docx;
+package com.hwtd.mes.collect;
 
 import org.apache.commons.lang3.ObjectUtils;
 import org.junit.jupiter.api.Test;

--
Gitblit v1.9.3