From 7d03d9fe3714a10fdd51f24e3c84da31a36f4ad8 Mon Sep 17 00:00:00 2001
From: wzp <2040239371@qq.com>
Date: 星期二, 15 七月 2025 14:28:14 +0800
Subject: [PATCH] fix:修复docker转化pdf文件卡顿和IO暴涨问题。 用单例控制docker转化,并监控docker状态

---
 src/main/java/com/ots/common/utils/poi/WordUtil.java              |    6 
 src/main/java/com/ots/project/tool/PdfUtil.java                   |    1 
 src/main/java/com/ots/project/tool/report/LAQ/chart/LAQChart.java |   18 +-
 src/main/java/com/ots/project/tool/PdfDockerUtil.java             |  292 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 306 insertions(+), 11 deletions(-)

diff --git a/src/main/java/com/ots/common/utils/poi/WordUtil.java b/src/main/java/com/ots/common/utils/poi/WordUtil.java
index 59c478a..44f60fa 100644
--- a/src/main/java/com/ots/common/utils/poi/WordUtil.java
+++ b/src/main/java/com/ots/common/utils/poi/WordUtil.java
@@ -12,6 +12,7 @@
 import com.ots.project.exam.domain.TReportTemplate;
 import com.ots.project.exam.dto.JAQTableStyle;
 import com.ots.project.exam.dto.WordParam;
+import com.ots.project.tool.PdfDockerUtil;
 import com.ots.project.tool.PdfUtil;
 import com.ots.project.tool.ShellTool;
 import com.ots.project.tool.exam.ExamUtil;
@@ -1236,7 +1237,7 @@
         } catch (Exception e) {
             e.printStackTrace();
         }
-
+        //鍒犻櫎鏂囦欢
         deleteFileByStr(deleteFileStrList);
         return AjaxResult.success(fileName + ".zip");
     }
@@ -1287,7 +1288,8 @@
             }else if(ReportTypeEnum.LAQ.getCode().equals(reportType)){
                 // 鑾峰彇寮�濮嬫椂闂�
                 long startTime = System.currentTimeMillis();
-                PdfUtil.dockerConvertPDF(EssConfig.getProfile(),EssConfig.getDocx2pdfPath(),reportName);
+//                PdfUtil.dockerConvertPDF(EssConfig.getProfile(),EssConfig.getDocx2pdfPath(),reportName);
+                PdfDockerUtil.convertPDF(EssConfig.getProfile(),EssConfig.getDocx2pdfPath(),reportName);
 
                 // 鑾峰彇缁撴潫鏃堕棿
                 long endTime = System.currentTimeMillis();
diff --git a/src/main/java/com/ots/project/tool/PdfDockerUtil.java b/src/main/java/com/ots/project/tool/PdfDockerUtil.java
new file mode 100644
index 0000000..97a1b2c
--- /dev/null
+++ b/src/main/java/com/ots/project/tool/PdfDockerUtil.java
@@ -0,0 +1,292 @@
+package com.ots.project.tool;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.*;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.MessageFormat;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Docker杞寲pdf涓撶敤澶勭悊宸ュ叿
+ * 浣跨敤鍗曚緥妯″紡瀹炵幇
+ */
+@Slf4j
+public class PdfDockerUtil {
+    
+    /**
+     * 鍗曚緥瀹炰緥
+     */
+    private static volatile PdfDockerUtil instance;
+    
+    /**
+     * 瀹瑰櫒鍚嶇О鍓嶇紑
+     */
+    private static final String CONTAINER_NAME_PREFIX = "pdf_converter_";
+    
+    /**
+     * 鏂囦欢閿佽矾寰�
+     */
+    private static final String LOCK_FILE_PATH = System.getProperty("java.io.tmpdir") + "/pdf_docker_lock";
+    
+    /**
+     * 浠诲姟瓒呮椂鏃堕棿锛堢锛�
+     */
+    private static final int TASK_TIMEOUT_SECONDS = 300; // 5鍒嗛挓
+    
+    /**
+     * 绉佹湁鏋勯�犲嚱鏁帮紝闃叉澶栭儴瀹炰緥鍖�
+     */
+    private PdfDockerUtil() {
+        // 绉佹湁鏋勯�犲嚱鏁�
+    }
+    
+    /**
+     * 鑾峰彇鍗曚緥瀹炰緥
+     * 浣跨敤鍙岄噸妫�鏌ラ攣瀹氱‘淇濈嚎绋嬪畨鍏�
+     * @return PdfDockerUtil瀹炰緥
+     */
+    public static PdfDockerUtil getInstance() {
+        if (instance == null) {
+            synchronized (PdfDockerUtil.class) {
+                if (instance == null) {
+                    instance = new PdfDockerUtil();
+                }
+            }
+        }
+        return instance;
+    }
+    
+    /**
+     * docker word杞琾df
+     * @param profile 閰嶇疆鏂囦欢璺緞
+     * @param docx2pdfPath docker鍛戒护妯℃澘璺緞
+     * @param fileName 鏂囦欢鍚�
+     */
+    public void dockerConvertPDF(String profile, String docx2pdfPath, String fileName) {
+        FileLock lock = null;
+        Process proc = null;
+        
+        try {
+            // 1. 鑾峰彇鏂囦欢閿侊紝纭繚涓茶鎵ц
+            lock = acquireFileLock();
+            if (lock == null) {
+                log.error("鏃犳硶鑾峰彇鏂囦欢閿侊紝鍙兘鏈夊叾浠栬浆鎹换鍔℃鍦ㄦ墽琛�");
+                return;
+            }
+            
+            // 2. 鐢熸垚鍞竴瀹瑰櫒鍚嶇О
+            String containerName = CONTAINER_NAME_PREFIX + System.currentTimeMillis();
+            
+            // 3. 娓呯悊鏃у鍣�
+            cleanupOldContainers();
+            
+            // 4. 鏋勫缓Docker鍛戒护
+            String command = MessageFormat.format(docx2pdfPath, profile, fileName);
+            log.info("docker鎵ц鍛戒护:{}", command);
+            
+            // 5. 鎵цDocker鍛戒护锛堝甫瓒呮椂锛�
+            proc = Runtime.getRuntime().exec(command);
+            
+            // 6. 寮傛璇诲彇杈撳嚭娴�
+            ProcessOutputReader outputReader = new ProcessOutputReader(proc.getInputStream(), "STDOUT");
+            ProcessOutputReader errorReader = new ProcessOutputReader(proc.getErrorStream(), "STDERR");
+            
+            outputReader.start();
+            errorReader.start();
+            
+            // 7. 绛夊緟杩涚▼瀹屾垚锛堝甫瓒呮椂锛�
+            boolean completed = proc.waitFor(TASK_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+            
+            if (!completed) {
+                log.error("Docker浠诲姟鎵ц瓒呮椂锛坽}绉掞級锛屽己鍒剁粓姝㈣繘绋�", TASK_TIMEOUT_SECONDS);
+                forceKillProcess(proc);
+                return;
+            }
+            
+            int exitCode = proc.exitValue();
+            log.info("Docker杩涚▼閫�鍑虹爜: {}", exitCode);
+            
+            // 8. 绛夊緟杈撳嚭璇诲彇瀹屾垚
+            outputReader.join(5000);
+            errorReader.join(5000);
+            
+            if (exitCode != 0) {
+                log.error("Docker鍛戒护鎵ц澶辫触锛岄��鍑虹爜: {}", exitCode);
+            } else {
+                log.info("Docker鍛戒护鎵ц鎴愬姛");
+            }
+            
+        } catch (Exception e) {
+            log.error("Docker杞崲PDF澶辫触", e);
+        } finally {
+            // 9. 娓呯悊璧勬簮
+            cleanupResources(proc, lock);
+        }
+    }
+    
+    /**
+     * 鑾峰彇鏂囦欢閿�
+     */
+    private FileLock acquireFileLock() {
+        FileChannel channel = null;
+        try {
+            Path lockPath = Paths.get(LOCK_FILE_PATH);
+            Files.createDirectories(lockPath.getParent());
+            
+            if (!Files.exists(lockPath)) {
+                Files.createFile(lockPath);
+            }
+            
+            channel = new RandomAccessFile(lockPath.toFile(), "rw").getChannel();
+            FileLock lock = channel.tryLock();
+            
+            if (lock != null) {
+                log.info("鎴愬姛鑾峰彇鏂囦欢閿�");
+                return lock;
+            } else {
+                log.warn("鏂囦欢閿佽鍗犵敤锛屾棤娉曡幏鍙�");
+                if (channel != null) {
+                    channel.close();
+                }
+                return null;
+            }
+        } catch (Exception e) {
+            log.error("鑾峰彇鏂囦欢閿佸け璐�", e);
+            if (channel != null) {
+                try {
+                    channel.close();
+                } catch (IOException ex) {
+                    log.error("鍏抽棴鏂囦欢閫氶亾澶辫触", ex);
+                }
+            }
+            return null;
+        }
+    }
+    
+    /**
+     * 娓呯悊鏃у鍣�
+     */
+    private void cleanupOldContainers() {
+        try {
+            // 鏌ユ壘骞跺仠姝㈡墍鏈夌浉鍏冲鍣�
+            String findCommand = "docker ps -a --filter name=" + CONTAINER_NAME_PREFIX + "* --format '{{.Names}}'";
+            Process findProc = Runtime.getRuntime().exec(findCommand);
+            
+            BufferedReader reader = new BufferedReader(new InputStreamReader(findProc.getInputStream()));
+            String containerName;
+            
+            while ((containerName = reader.readLine()) != null) {
+                if (!containerName.trim().isEmpty()) {
+                    log.info("娓呯悊鏃у鍣�: {}", containerName);
+                    
+                    // 鍋滄瀹瑰櫒
+                    String stopCommand = "docker stop " + containerName;
+                    Runtime.getRuntime().exec(stopCommand);
+                    
+                    // 鍒犻櫎瀹瑰櫒
+                    String rmCommand = "docker rm " + containerName;
+                    Runtime.getRuntime().exec(rmCommand);
+                }
+            }
+            
+            reader.close();
+            findProc.waitFor(10, TimeUnit.SECONDS);
+            
+        } catch (Exception e) {
+            log.warn("娓呯悊鏃у鍣ㄦ椂鍑虹幇寮傚父", e);
+        }
+    }
+    
+    /**
+     * 寮哄埗缁堟杩涚▼
+     */
+    private void forceKillProcess(Process proc) {
+        try {
+            if (proc != null) {
+                proc.destroy();
+                
+                // 绛夊緟杩涚▼缁堟
+                if (!proc.waitFor(5, TimeUnit.SECONDS)) {
+                    proc.destroyForcibly();
+                    log.warn("寮哄埗缁堟杩涚▼");
+                }
+            }
+        } catch (Exception e) {
+            log.error("寮哄埗缁堟杩涚▼澶辫触", e);
+        }
+    }
+    
+    /**
+     * 娓呯悊璧勬簮
+     */
+    private void cleanupResources(Process proc, FileLock lock) {
+        try {
+            if (proc != null) {
+                forceKillProcess(proc);
+            }
+            
+            if (lock != null) {
+                lock.release();
+                log.info("閲婃斁鏂囦欢閿�");
+            }
+        } catch (Exception e) {
+            log.error("娓呯悊璧勬簮澶辫触", e);
+        }
+    }
+    
+    /**
+     * 杩涚▼杈撳嚭璇诲彇鍣�
+     */
+    private static class ProcessOutputReader extends Thread {
+        private final BufferedReader reader;
+        private final String streamType;
+        
+        public ProcessOutputReader(InputStream inputStream, String streamType) {
+            this.reader = new BufferedReader(new InputStreamReader(inputStream, java.nio.charset.StandardCharsets.UTF_8));
+            this.streamType = streamType;
+        }
+        
+        @Override
+        public void run() {
+            try {
+                String line;
+                log.info("=== Docker {} ===", streamType);
+                while ((line = reader.readLine()) != null) {
+                    if ("STDERR".equals(streamType)) {
+                        log.error("{}: {}", streamType, line);
+                    } else {
+                        log.info("{}: {}", streamType, line);
+                    }
+                }
+            } catch (IOException e) {
+                log.error("璇诲彇{}娴佸け璐�", streamType, e);
+            } finally {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                    log.error("鍏抽棴{}娴佸け璐�", streamType, e);
+                }
+            }
+        }
+    }
+    
+    /**
+     * 闈欐�佹柟娉曡皟鐢紝鏂逛究浣跨敤
+     * @param profile 閰嶇疆鏂囦欢璺緞
+     * @param docx2pdfPath docker鍛戒护妯℃澘璺緞
+     * @param fileName 鏂囦欢鍚�
+     * 鏂瑰紡1锛氶�氳繃闈欐�佹柟娉曡皟鐢紙鎺ㄨ崘锛�
+     * PdfDockerUtil.convertPDF(profile, docx2pdfPath, fileName);
+     * 鏂瑰紡2锛氶�氳繃瀹炰緥鏂规硶璋冪敤
+     * PdfDockerUtil pdfDockerUtil = PdfDockerUtil.getInstance();
+     * pdfDockerUtil.convertPDF(profile, docx2pdfPath, fileName);
+     */
+    public static void convertPDF(String profile, String docx2pdfPath, String fileName) {
+        getInstance().dockerConvertPDF(profile, docx2pdfPath, fileName);
+    }
+}
diff --git a/src/main/java/com/ots/project/tool/PdfUtil.java b/src/main/java/com/ots/project/tool/PdfUtil.java
index 39db254..20f9b63 100644
--- a/src/main/java/com/ots/project/tool/PdfUtil.java
+++ b/src/main/java/com/ots/project/tool/PdfUtil.java
@@ -84,6 +84,7 @@
      * @param profile
      * @param docx2pdfPath
      * @param fileName
+     * 杩欎釜鏈夋椂鍊檇ocker杞寲浼氬崱姝伙紝2025.7.15鎷熼噰鐢╬dfDockerUtil鏂版柟娉曞鐞�
      */
     public static void dockerConvertPDF(String profile,String docx2pdfPath,String fileName){
         try {
diff --git a/src/main/java/com/ots/project/tool/report/LAQ/chart/LAQChart.java b/src/main/java/com/ots/project/tool/report/LAQ/chart/LAQChart.java
index 404d971..fe67dd3 100644
--- a/src/main/java/com/ots/project/tool/report/LAQ/chart/LAQChart.java
+++ b/src/main/java/com/ots/project/tool/report/LAQ/chart/LAQChart.java
@@ -48,17 +48,17 @@
 
 
     public static void main(String[] args) throws Exception {
-        String dataPath = "D:\\娴嬭瘎绯荤粺\\闇�姹俓\LAQ\\report\\LAQ琛ㄥご鏁版嵁鏂囦欢.xlsx";
-        // 鑾峰彇瀵煎叆鏁版嵁
-        File file = new File(dataPath);
-        InputStream in = new FileInputStream(file);
-        ExcelUtil<LAQTemplate> util = new ExcelUtil<>(LAQTemplate.class);
-        List<LAQTemplate> laqTemplateList = util.importExcel(in);
+//        String dataPath = "D:\\娴嬭瘎绯荤粺\\闇�姹俓\LAQ\\report\\LAQ琛ㄥご鏁版嵁鏂囦欢.xlsx";
+//        // 鑾峰彇瀵煎叆鏁版嵁
+//        File file = new File(dataPath);
+//        InputStream in = new FileInputStream(file);
+//        ExcelUtil<LAQTemplate> util = new ExcelUtil<>(LAQTemplate.class);
+//        List<LAQTemplate> laqTemplateList = util.importExcel(in);
         // 鐢熸垚鏂囦欢闆嗗悎
         List<String> fileNameList = new ArrayList<>();
         List<String> deleteStrList = new ArrayList<>();
-        for (int i = 0; i < laqTemplateList.size(); i++) {
-            LAQTemplate laqTemplate = laqTemplateList.get(i);
+        for (int i = 0; i < 1; i++) {
+//            LAQTemplate laqTemplate = laqTemplateList.get(i);
             //缁勮鎶ュ憡鎵�鐢ㄦ暟鎹�
             Map<String, Object> textMap = new HashMap<>();
 //            textMap.put("sendEmailFileName",laqTemplate.getName());
@@ -83,7 +83,7 @@
 //            String zipFileName = WordUtil.makeReportFile("D:\\娴嬭瘎绯荤粺\\闇�姹俓\LAQ\\report\\LAQ鑻辨枃鎶ュ憡-20230926.docx", template, textMap, new HashMap<>(), deleteStrList);
 //            fileNameList.add(zipFileName);
             ZipSecureFile.setMinInflateRatio(0.001);
-            try (OutputStream os = new FileOutputStream("D:\\娴嬭瘎绯荤粺\\闇�姹俓\LAQ\\report\\LAQ鑻辨枃妯℃澘-wzp-淇敼鐗�-1.docx");XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage("D:\\娴嬭瘎绯荤粺\\闇�姹俓\LAQ\\report\\LAQ鑻辨枃妯℃澘-wzp-淇敼鐗�.docx"))){
+            try (OutputStream os = new FileOutputStream("D:\\TaiOS\\LAQ-1.docx");XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage("D:\\TaiOS\\LAQ.docx"))){
                 Map<Integer,List<SeriesData>> seriesDatas = initData(textMap);
                 changeChart(document,seriesDatas,textMap);
                 document.write(os);

--
Gitblit v1.9.1