|  |  |  | 
|---|
|  |  |  | import com.documents4j.api.IConverter; | 
|---|
|  |  |  | import com.documents4j.job.LocalConverter; | 
|---|
|  |  |  | import lombok.extern.slf4j.Slf4j; | 
|---|
|  |  |  | import org.apache.poi.xwpf.usermodel.*; | 
|---|
|  |  |  | import org.springframework.beans.factory.annotation.Autowired; | 
|---|
|  |  |  | import org.springframework.mock.web.MockMultipartFile; | 
|---|
|  |  |  | import org.springframework.stereotype.Component; | 
|---|
|  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | import java.io.*; | 
|---|
|  |  |  | import java.net.URL; | 
|---|
|  |  |  | import java.nio.charset.StandardCharsets; | 
|---|
|  |  |  | import java.nio.file.Files; | 
|---|
|  |  |  | import java.util.ArrayList; | 
|---|
|  |  |  | import java.util.Arrays; | 
|---|
|  |  |  | import java.util.List; | 
|---|
|  |  |  | import java.util.Map; | 
|---|
|  |  |  | import java.util.concurrent.TimeUnit; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | @Slf4j | 
|---|
|  |  |  | @Component | 
|---|
|  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * word 转 pdf | 
|---|
|  |  |  | * | 
|---|
|  |  |  | * @param url | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | public  String wordToPdf(String url,String filePath, String fileName) { | 
|---|
|  |  |  | //    public  String wordToPdf(String url,String filePath, String fileName) { | 
|---|
|  |  |  | //        try { | 
|---|
|  |  |  | //            DocumentType documentType = DocumentType.DOC; | 
|---|
|  |  |  | //            if(url.contains(".docx")){ | 
|---|
|  |  |  | //                documentType = DocumentType.DOCX; | 
|---|
|  |  |  | //            } | 
|---|
|  |  |  | //            if(url.contains(".doc")){ | 
|---|
|  |  |  | //                documentType = DocumentType.DOC; | 
|---|
|  |  |  | //            } | 
|---|
|  |  |  | //            if(url.contains(".xlsx")){ | 
|---|
|  |  |  | //                documentType = DocumentType.XLSX; | 
|---|
|  |  |  | //            }else { | 
|---|
|  |  |  | //                if(url.contains(".xls")){ | 
|---|
|  |  |  | //                    documentType = DocumentType.XLS; | 
|---|
|  |  |  | //                } | 
|---|
|  |  |  | //            } | 
|---|
|  |  |  | //            InputStream inputStream = new URL(url).openStream(); | 
|---|
|  |  |  | //            ByteArrayOutputStream stream = new ByteArrayOutputStream(); | 
|---|
|  |  |  | //            IConverter converter = LocalConverter.builder().build(); | 
|---|
|  |  |  | //            converter.convert(inputStream) | 
|---|
|  |  |  | //                    .as(documentType) | 
|---|
|  |  |  | //                    .to(stream) | 
|---|
|  |  |  | //                    .as(DocumentType.PDF).execute(); | 
|---|
|  |  |  | // | 
|---|
|  |  |  | //            //上传图片 | 
|---|
|  |  |  | //            byte2File(stream.toByteArray(),filePath + "/pdf",fileName.substring(0,fileName.lastIndexOf(".")) + ".pdf"); | 
|---|
|  |  |  | //            MultipartFile multipartFile = convertToMultipartFile(stream,fileName.substring(0,fileName.lastIndexOf(".")) ); | 
|---|
|  |  |  | //            String s = tencentCosUtil.upLoadFile(multipartFile,"/wordToPdf"); | 
|---|
|  |  |  | // | 
|---|
|  |  |  | //            stream.close(); | 
|---|
|  |  |  | //            inputStream.close(); | 
|---|
|  |  |  | //            return s; | 
|---|
|  |  |  | //        } catch (Exception e) { | 
|---|
|  |  |  | //            e.printStackTrace(); | 
|---|
|  |  |  | //        } | 
|---|
|  |  |  | //        return null; | 
|---|
|  |  |  | //    } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public String wordToPdf(String filePath, String fileName) { | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | DocumentType documentType = DocumentType.DOC; | 
|---|
|  |  |  | if(url.contains(".docx")){ | 
|---|
|  |  |  | documentType = DocumentType.DOCX; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if(url.contains(".doc")){ | 
|---|
|  |  |  | documentType = DocumentType.DOC; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if(url.contains(".xlsx")){ | 
|---|
|  |  |  | documentType = DocumentType.XLSX; | 
|---|
|  |  |  | }else { | 
|---|
|  |  |  | if(url.contains(".xls")){ | 
|---|
|  |  |  | documentType = DocumentType.XLS; | 
|---|
|  |  |  | // 确保路径正确性 | 
|---|
|  |  |  | String inputFile = new File(filePath, fileName).getAbsolutePath(); | 
|---|
|  |  |  | String outputDir = new File(filePath, "pdf").getAbsolutePath(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 创建输出目录 | 
|---|
|  |  |  | new File(outputDir).mkdirs(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 使用完整的转换参数 | 
|---|
|  |  |  | List<String> command = Arrays.asList( | 
|---|
|  |  |  | "/usr/bin/libreoffice",  // 使用完整路径 | 
|---|
|  |  |  | "--headless", | 
|---|
|  |  |  | "--norestore", | 
|---|
|  |  |  | "--convert-to", | 
|---|
|  |  |  | "pdf:writer_pdf_Export:PDFExport{" + | 
|---|
|  |  |  | "EmbedStandardFonts=1;" + | 
|---|
|  |  |  | "EmbedFonts=1;" + | 
|---|
|  |  |  | "EmbedOnlyUsedFonts=0;" + | 
|---|
|  |  |  | "UseTaggedPDF=1" + | 
|---|
|  |  |  | "}", | 
|---|
|  |  |  | "--outdir", | 
|---|
|  |  |  | outputDir, | 
|---|
|  |  |  | inputFile | 
|---|
|  |  |  | ); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 创建进程构建器 | 
|---|
|  |  |  | ProcessBuilder pb = new ProcessBuilder(command); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 设置环境变量 | 
|---|
|  |  |  | Map<String, String> env = pb.environment(); | 
|---|
|  |  |  | env.put("LC_ALL", "zh_CN.UTF-8"); | 
|---|
|  |  |  | env.put("LANG", "zh_CN.UTF-8"); | 
|---|
|  |  |  | env.put("LANGUAGE", "zh_CN.UTF-8"); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 重定向错误流到标准输出 | 
|---|
|  |  |  | pb.redirectErrorStream(true); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 启动进程 | 
|---|
|  |  |  | Process process = pb.start(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 读取输出 | 
|---|
|  |  |  | StringBuilder output = new StringBuilder(); | 
|---|
|  |  |  | try (BufferedReader reader = new BufferedReader( | 
|---|
|  |  |  | new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) { | 
|---|
|  |  |  | String line; | 
|---|
|  |  |  | while ((line = reader.readLine()) != null) { | 
|---|
|  |  |  | output.append(line).append("\n"); | 
|---|
|  |  |  | System.out.println(line); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | InputStream inputStream = new URL(url).openStream(); | 
|---|
|  |  |  | ByteArrayOutputStream stream = new ByteArrayOutputStream(); | 
|---|
|  |  |  | IConverter converter = LocalConverter.builder().build(); | 
|---|
|  |  |  | converter.convert(inputStream) | 
|---|
|  |  |  | .as(documentType) | 
|---|
|  |  |  | .to(stream) | 
|---|
|  |  |  | .as(DocumentType.PDF).execute(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //上传图片 | 
|---|
|  |  |  | byte2File(stream.toByteArray(),filePath + "/pdf",fileName.substring(0,fileName.lastIndexOf(".")) + ".pdf"); | 
|---|
|  |  |  | MultipartFile multipartFile = convertToMultipartFile(stream,fileName.substring(0,fileName.lastIndexOf(".")) ); | 
|---|
|  |  |  | // 等待进程完成,设置超时 | 
|---|
|  |  |  | if (!process.waitFor(120, TimeUnit.SECONDS)) { | 
|---|
|  |  |  | process.destroyForcibly(); | 
|---|
|  |  |  | throw new RuntimeException("转换超时"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | int exitCode = process.exitValue(); | 
|---|
|  |  |  | if (exitCode != 0) { | 
|---|
|  |  |  | throw new RuntimeException("转换失败,退出码:" + exitCode + "\n输出:" + output); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 检查生成的PDF文件 | 
|---|
|  |  |  | String pdfFileName = fileName.substring(0, fileName.lastIndexOf(".")) + ".pdf"; | 
|---|
|  |  |  | File pdfFile = new File(outputDir, pdfFileName); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (!pdfFile.exists() || pdfFile.length() == 0) { | 
|---|
|  |  |  | throw new RuntimeException("PDF文件未生成或为空"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | String absolutePath = pdfFile.getAbsolutePath(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | MultipartFile multipartFile = convertFileToMultipartFile(pdfFile); | 
|---|
|  |  |  | String s = tencentCosUtil.upLoadFile(multipartFile,"/wordToPdf"); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | stream.close(); | 
|---|
|  |  |  | inputStream.close(); | 
|---|
|  |  |  | return s; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } catch (Exception e) { | 
|---|
|  |  |  | e.printStackTrace(); | 
|---|
|  |  |  | throw new RuntimeException("PDF转换失败: " + e.getMessage(), e); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | return null; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public MultipartFile convertFileToMultipartFile(File file) throws IOException { | 
|---|
|  |  |  | // 读取文件内容到字节数组 | 
|---|
|  |  |  | byte[] fileContent = Files.readAllBytes(file.toPath()); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 创建 MultipartFile 对象 | 
|---|
|  |  |  | MultipartFile multipartFile = new MockMultipartFile( | 
|---|
|  |  |  | file.getName(),       // 文件名 | 
|---|
|  |  |  | file.getName(),       // 原始文件名 | 
|---|
|  |  |  | "application/pdf",  // 内容类型,根据实际情况调整 | 
|---|
|  |  |  | fileContent           // 文件内容 | 
|---|
|  |  |  | ); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | return multipartFile; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 在使用前检查和配置环境 | 
|---|
|  |  |  | public static void setupEnvironment() { | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | // 1. 检查LibreOffice安装 | 
|---|
|  |  |  | checkLibreOffice(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 2. 检查和安装字体 | 
|---|
|  |  |  | installFonts(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 3. 配置字体 | 
|---|
|  |  |  | configureFonts(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 4. 验证环境变量 | 
|---|
|  |  |  | checkEnvironment(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } catch (Exception e) { | 
|---|
|  |  |  | throw new RuntimeException("环境设置失败: " + e.getMessage(), e); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private static void checkLibreOffice() throws IOException, InterruptedException { | 
|---|
|  |  |  | Process process = Runtime.getRuntime().exec("which libreoffice"); | 
|---|
|  |  |  | if (process.waitFor() != 0) { | 
|---|
|  |  |  | throw new RuntimeException("LibreOffice未安装"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private static void installFonts() throws IOException, InterruptedException { | 
|---|
|  |  |  | // 创建字体安装脚本 | 
|---|
|  |  |  | String scriptContent = | 
|---|
|  |  |  | "#!/bin/bash\n" + | 
|---|
|  |  |  | "apt-get update\n" + | 
|---|
|  |  |  | "apt-get install -y fonts-wqy-zenhei fonts-wqy-microhei fonts-arphic-ukai fonts-arphic-uming\n" + | 
|---|
|  |  |  | "fc-cache -fv\n"; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | File script = new File("/tmp/install_fonts.sh"); | 
|---|
|  |  |  | Files.write(script.toPath(), scriptContent.getBytes()); | 
|---|
|  |  |  | script.setExecutable(true); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 执行脚本 | 
|---|
|  |  |  | Process process = Runtime.getRuntime().exec("sudo /tmp/install_fonts.sh"); | 
|---|
|  |  |  | process.waitFor(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 清理脚本 | 
|---|
|  |  |  | script.delete(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private static void configureFonts() throws IOException { | 
|---|
|  |  |  | // 创建字体配置文件 | 
|---|
|  |  |  | String fontConfig = | 
|---|
|  |  |  | "<?xml version=\"1.0\"?>\n" + | 
|---|
|  |  |  | "<!DOCTYPE fontconfig SYSTEM \"fonts.dtd\">\n" + | 
|---|
|  |  |  | "<fontconfig>\n" + | 
|---|
|  |  |  | "  <match target=\"pattern\">\n" + | 
|---|
|  |  |  | "    <test name=\"family\"><string>serif</string></test>\n" + | 
|---|
|  |  |  | "    <edit name=\"family\" mode=\"prepend\">\n" + | 
|---|
|  |  |  | "      <string>WenQuanYi Zen Hei</string>\n" + | 
|---|
|  |  |  | "    </edit>\n" + | 
|---|
|  |  |  | "  </match>\n" + | 
|---|
|  |  |  | "  <match target=\"pattern\">\n" + | 
|---|
|  |  |  | "    <test name=\"family\"><string>sans-serif</string></test>\n" + | 
|---|
|  |  |  | "    <edit name=\"family\" mode=\"prepend\">\n" + | 
|---|
|  |  |  | "      <string>WenQuanYi Zen Hei</string>\n" + | 
|---|
|  |  |  | "    </edit>\n" + | 
|---|
|  |  |  | "  </match>\n" + | 
|---|
|  |  |  | "</fontconfig>"; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // 写入配置文件 | 
|---|
|  |  |  | File configFile = new File(System.getProperty("user.home") + "/.fonts.conf"); | 
|---|
|  |  |  | Files.write(configFile.toPath(), fontConfig.getBytes()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private static void checkEnvironment() { | 
|---|
|  |  |  | // 检查环境变量 | 
|---|
|  |  |  | String[] requiredVars = {"LANG", "LC_ALL", "LANGUAGE"}; | 
|---|
|  |  |  | for (String var : requiredVars) { | 
|---|
|  |  |  | String value = System.getenv(var); | 
|---|
|  |  |  | if (value == null || !value.contains("zh_CN")) { | 
|---|
|  |  |  | System.err.println("警告: " + var + " 环境变量未正确设置"); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public static MultipartFile convertToMultipartFile(ByteArrayOutputStream baos, String fileName) throws IOException { | 
|---|
|  |  |  | // 创建一个临时文件 | 
|---|
|  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public String test(String fileName){ | 
|---|
|  |  |  | String url = "file:///E:\\"+fileName; | 
|---|
|  |  |  | //        String url = "file:///usr/local/project/file/"+fileName; | 
|---|
|  |  |  | //        String filePath = "E:\\qiyeweixin\\WXWork\\1688855207501340\\Cache\\File\\2024-09"; | 
|---|
|  |  |  | //        String fileName = "专业技术工作总结.docx";4 | 
|---|
|  |  |  | String filePath = "E:\\"; | 
|---|
|  |  |  | String filePath = "/usr/local/project/file/"; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | String s = wordToPdf(url, filePath, fileName); | 
|---|
|  |  |  | String s = wordToPdf(filePath, fileName); | 
|---|
|  |  |  | System.err.println(s); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | return s; | 
|---|