ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/TContractController.java
@@ -298,46 +298,46 @@ THouse tHouse = houseService.getById(contract.getHouseId()); Map<String, Object> templateParam = new HashMap<>(5); templateParam.put("partyOneName", contract.getPartyOneName()); templateParam.put("partyTwoName", contract.getPartyTwoName()); templateParam.put("houseAddress", tHouse.getHouseAddress()); templateParam.put("houseArea", tHouse.getHouseArea()+"m²"); templateParam.put("${partyOneName}", contract.getPartyOneName()); templateParam.put("${partyTwoName}", contract.getPartyTwoName()); templateParam.put("${houseAddress}", tHouse.getHouseAddress()); templateParam.put("${houseArea}", tHouse.getHouseArea()+"m²"); long between = ChronoUnit.DAYS.between(contract.getStartTime(), contract.getStartPayTime())+1; templateParam.put("day", between); templateParam.put("endTimeFree", DateUtils.localDateTimeToStringYear(contract.getStartPayTime().plusDays(1))); templateParam.put("startPayTime", DateUtils.localDateTimeToStringYear(contract.getStartPayTime())); templateParam.put("startTime", DateUtils.localDateTimeToStringYear(contract.getStartTime())); templateParam.put("endTime", DateUtils.localDateTimeToStringYear(contract.getEndTime())); templateParam.put("monthRent", "¥¥"+contract.getMonthRent()+"元"); templateParam.put("monthRentString", "人民币"+NumberToChineseUtils.numberToChinese(contract.getMonthRent().setScale(2, BigDecimal.ROUND_DOWN).doubleValue())); templateParam.put("${day}", between); templateParam.put("${endTimeFree}", DateUtils.localDateTimeToStringYear(contract.getStartPayTime().plusDays(1))); templateParam.put("${startPayTime}", DateUtils.localDateTimeToStringYear(contract.getStartPayTime())); templateParam.put("${startTime}", DateUtils.localDateTimeToStringYear(contract.getStartTime())); templateParam.put("${endTime}", DateUtils.localDateTimeToStringYear(contract.getEndTime())); templateParam.put("${monthRent}", "¥"+contract.getMonthRent()+"元"); templateParam.put("${monthRentString}", "人民币"+NumberToChineseUtils.numberToChinese(contract.getMonthRent().setScale(2, BigDecimal.ROUND_DOWN).doubleValue())); String totalYear = Objects.nonNull(contract.getTotalYear())?contract.getTotalYear().toString():""; templateParam.put("totalYear", "¥¥"+totalYear+"元"); templateParam.put("${totalYear}", "¥"+totalYear+"元"); String totalYearString = StringUtils.isNotEmpty(totalYear)?NumberToChineseUtils.numberToChinese(contract.getTotalYear().setScale(2, BigDecimal.ROUND_DOWN).doubleValue()):""; templateParam.put("totalYearString", "人民币"+totalYearString); templateParam.put("payType", contract.getPayType().equals("1")?"月":contract.getPayType().equals("2")?"季":"年"); templateParam.put("${totalYearString}", "人民币"+totalYearString); templateParam.put("${payType}", contract.getPayType().equals("1")?"月":contract.getPayType().equals("2")?"季":"年"); if(firstBill!=null){ templateParam.put("firstRent", "¥"+(firstBill.getPayableFeesMoney())+"元"); templateParam.put("${firstRent}", "¥"+(firstBill.getPayableFeesMoney())+"元"); }else{ templateParam.put("firstRent", ""); templateParam.put("${firstRent}", ""); } templateParam.put("firstRentString", "人民币"+NumberToChineseUtils.numberToChinese((contract.getPayType().equals("1")?contract.getMonthRent():contract.getPayType().equals("2")?contract.getMonthRent().multiply(new BigDecimal("3")):contract.getMonthRent().multiply(new BigDecimal("12")).setScale(2,BigDecimal.ROUND_DOWN)).doubleValue())); templateParam.put("nextPayTime", contract.getPayType().equals("1")?"月":contract.getPayType().equals("2")?"季":"年"); templateParam.put("deposit", "¥"+contract.getDeposit()+"元"); templateParam.put("depositString", NumberToChineseUtils.numberToChinese(contract.getDeposit().setScale(2, BigDecimal.ROUND_DOWN).doubleValue())); templateParam.put("partyOnePerson", contract.getPartyOnePerson()); templateParam.put("partyOnePhone", contract.getPartyOnePhone()); templateParam.put("partyTwoPerson", contract.getPartyTwoPerson()); templateParam.put("partyTwoPhone", contract.getPartyTwoPhone()); templateParam.put("${firstRentString}", "人民币"+NumberToChineseUtils.numberToChinese((contract.getPayType().equals("1")?contract.getMonthRent():contract.getPayType().equals("2")?contract.getMonthRent().multiply(new BigDecimal("3")):contract.getMonthRent().multiply(new BigDecimal("12")).setScale(2,BigDecimal.ROUND_DOWN)).doubleValue())); templateParam.put("${nextPayTime}", contract.getPayType().equals("1")?"月":contract.getPayType().equals("2")?"季":"年"); templateParam.put("${deposit}", "¥"+contract.getDeposit()+"元"); templateParam.put("${depositString}", NumberToChineseUtils.numberToChinese(contract.getDeposit().setScale(2, BigDecimal.ROUND_DOWN).doubleValue())); templateParam.put("${partyOnePerson}", contract.getPartyOnePerson()); templateParam.put("${partyOnePhone}", contract.getPartyOnePhone()); templateParam.put("${partyTwoPerson}", contract.getPartyTwoPerson()); templateParam.put("${partyTwoPhone}", contract.getPartyTwoPhone()); // 验收时间 TCheckAcceptRecord tCheckAcceptRecord = checkAcceptRecordService.lambdaQuery().eq(TCheckAcceptRecord::getContractId, contract.getId()).last("limit 1").one(); if (tCheckAcceptRecord!=null &&tCheckAcceptRecord.getCheckTime()!=null ){ templateParam.put("checkTime", DateUtils.localDateTimeToStringYear(tCheckAcceptRecord.getCheckTime())); templateParam.put("${checkTime}", DateUtils.localDateTimeToStringYear(tCheckAcceptRecord.getCheckTime())); }else{ templateParam.put("checkTime", ""); templateParam.put("${checkTime}", ""); } String url = wordUtil.generatePdf("/template", "1_yzj_租赁合同.xml", templateParam, "租赁合同", "E:\\"); String url = wordUtil.generatePdf("/usr/local/project/file/", "1_yzj_租赁合同.docx", templateParam, "租赁合同", "/usr/local/project/file/"); res.add(url); } ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/PdfUtils.java
@@ -4,6 +4,7 @@ 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; @@ -11,7 +12,11 @@ import java.io.*; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @Slf4j @@ -22,7 +27,6 @@ /** * word 转 pdf * * @param url */ // public String wordToPdf(String url,String filePath, String fileName) { // try { @@ -62,48 +66,192 @@ // return null; // } public String wordToPdf(String url, String filePath, String fileName) { public String wordToPdf(String filePath, String fileName) { try { DocumentType documentType = DocumentType.DOC; if (url.contains(".docx")) { documentType = DocumentType.DOCX; } else if (url.contains(".doc")) { documentType = DocumentType.DOC; } else if (url.contains(".xlsx")) { documentType = DocumentType.XLSX; } else if (url.contains(".xls")) { documentType = DocumentType.XLS; } // 1. 首先确保输入文件是UTF-8编码 String inputFile = filePath + fileName; String outputDir = filePath + "/pdf"; String outputFileName = fileName.substring(0, fileName.lastIndexOf(".")) + ".pdf"; // Ensure the URL has a protocol part if (!url.startsWith("file://") && !url.startsWith("http://") && !url.startsWith("https://")) { url = "file://" + url; } // 2. 创建临时文件用于转换 String tempDocx = createTempFileWithEncoding(inputFile); // 使用LibreOffice进行转换 ProcessBuilder pb = new ProcessBuilder( "soffice", "--headless", "--convert-to", "pdf", "--outdir", new File(filePath+ "/pdf"+fileName.substring(0, fileName.lastIndexOf(".")) + ".pdf").getParent(), filePath+fileName ); // 3. 使用更详细的LibreOffice转换参数 List<String> command = new ArrayList<>(); command.add("/usr/bin/soffice"); command.add("--headless"); command.add("--convert-to"); command.add("pdf:writer_pdf_Export:PDFExport{'EmbedStandardFonts':true}"); command.add("--outdir"); command.add(outputDir); command.add(tempDocx); ProcessBuilder pb = new ProcessBuilder(command); // 4. 设置更完整的环境变量 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"); env.put("PYTHONIOENCODING", "utf8"); env.put("JAVA_TOOL_OPTIONS", "-Dfile.encoding=UTF-8"); // 5. 执行转换 Process process = pb.start(); // 等待转换完成 int exitCode = process.waitFor(); if (exitCode == 0) { System.out.println("PDF转换成功!"); } else { System.out.println("PDF转换失败!"); // 6. 读取输出 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"); } } return ""; // 7. 等待进程完成 int exitCode = process.waitFor(); // 8. 清理临时文件 new File(tempDocx).delete(); if (exitCode == 0) { return outputDir + "/" + outputFileName; } else { throw new RuntimeException("转换失败: " + output.toString()); } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("Failed to generate PDF: " + e.getMessage(), e); throw new RuntimeException("PDF转换失败: " + e.getMessage(), e); } } private static String createTempFileWithEncoding(String inputFile) { try { // 1. 读取原始文档 XWPFDocument doc = new XWPFDocument(new FileInputStream(inputFile)); // 2. 修改文档字体和编码 for (XWPFParagraph paragraph : doc.getParagraphs()) { for (XWPFRun run : paragraph.getRuns()) { // 设置中文字体 run.setFontFamily("WenQuanYi Zen Hei"); run.setFontFamily("WenQuanYi Zen Hei", XWPFRun.FontCharRange.eastAsia); // 确保文本是UTF-8编码 String text = run.getText(0); if (text != null) { text = new String(text.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8); run.setText(text, 0); } } } // 3. 处理表格中的文本 for (XWPFTable table : doc.getTables()) { for (XWPFTableRow row : table.getRows()) { for (XWPFTableCell cell : row.getTableCells()) { for (XWPFParagraph paragraph : cell.getParagraphs()) { for (XWPFRun run : paragraph.getRuns()) { run.setFontFamily("WenQuanYi Zen Hei"); run.setFontFamily("WenQuanYi Zen Hei", XWPFRun.FontCharRange.eastAsia); String text = run.getText(0); if (text != null) { text = new String(text.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8); run.setText(text, 0); } } } } } } // 4. 保存为临时文件 String tempFile = inputFile + ".temp.docx"; try (FileOutputStream out = new FileOutputStream(tempFile)) { doc.write(out); } return tempFile; } catch (Exception e) { throw new RuntimeException("处理文档编码失败: " + e.getMessage(), e); } } // 在转换之前执行的环境检查 private static void preConversionCheck() { try { // 1. 检查并安装必要的字体 installRequiredFonts(); // 2. 验证LibreOffice安装 verifyLibreOfficeInstallation(); // 3. 设置字体配置 setupFontConfig(); } catch (Exception e) { throw new RuntimeException("环境检查失败: " + e.getMessage(), e); } } private static void installRequiredFonts() { try { ProcessBuilder pb = new ProcessBuilder( "sudo", "apt-get", "install", "-y", "fonts-wqy-zenhei", "fonts-wqy-microhei", "fonts-arphic-ukai", "fonts-arphic-uming" ); pb.inheritIO(); Process p = pb.start(); p.waitFor(); } catch (Exception e) { System.err.println("警告: 安装字体失败 - " + e.getMessage()); } } private static void verifyLibreOfficeInstallation() { try { Process p = Runtime.getRuntime().exec("soffice --version"); try (BufferedReader reader = new BufferedReader( new InputStreamReader(p.getInputStream()))) { String version = reader.readLine(); if (version == null || !version.contains("LibreOffice")) { throw new RuntimeException("LibreOffice未正确安装"); } } } catch (Exception e) { throw new RuntimeException("LibreOffice检查失败: " + e.getMessage()); } } private static void setupFontConfig() { try { String fontConfig = "<?xml version='1.0'?>\n" + "<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>\n" + "<fontconfig>\n" + " <match target=\"pattern\">\n" + " <test name=\"family\"><string>SimSun</string></test>\n" + " <edit name=\"family\" mode=\"assign\" binding=\"same\">\n" + " <string>WenQuanYi Zen Hei</string>\n" + " </edit>\n" + " </match>\n" + "</fontconfig>"; String userHome = System.getProperty("user.home"); File fontConfigFile = new File(userHome + "/.fonts.conf"); try (FileWriter writer = new FileWriter(fontConfigFile)) { writer.write(fontConfig); } } catch (Exception e) { System.err.println("警告: 设置字体配置失败 - " + e.getMessage()); } } public static MultipartFile convertToMultipartFile(ByteArrayOutputStream baos, String fileName) throws IOException { // 创建一个临时文件 @@ -251,12 +399,12 @@ } public String test(String fileName){ String url = "file:///usr/local/project/file/"+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 = "/usr/local/project/file/"; String s = wordToPdf(url, filePath, fileName); String s = wordToPdf(filePath, fileName); System.err.println(s); return s; ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/WordTemplateProcessor.java
New file @@ -0,0 +1,87 @@ package com.ruoyi.web.controller.tool; import org.apache.poi.xwpf.usermodel.*; import java.io.*; import java.util.*; public class WordTemplateProcessor { public static void fillTemplate(String templatePath, String outputPath,Map<String, String> dataMap) { try { // 读取模板文件 FileInputStream fis = new FileInputStream(templatePath); XWPFDocument document = new XWPFDocument(fis); // 替换段落中的标记 for (XWPFParagraph paragraph : document.getParagraphs()) { replaceParagraph(paragraph, dataMap); } // 替换表格中的标记 for (XWPFTable table : document.getTables()) { for (XWPFTableRow row : table.getRows()) { for (XWPFTableCell cell : row.getTableCells()) { for (XWPFParagraph paragraph : cell.getParagraphs()) { replaceParagraph(paragraph, dataMap); } } } } // 保存文件 FileOutputStream fos = new FileOutputStream(outputPath); document.write(fos); // 关闭资源 fos.close(); fis.close(); document.close(); System.out.println("模板填充完成!文件保存在: " + outputPath); } catch (Exception e) { e.printStackTrace(); } } private static void replaceParagraph(XWPFParagraph paragraph, Map<String, String> dataMap) { String paragraphText = paragraph.getText(); for (Map.Entry<String, String> entry : dataMap.entrySet()) { if (paragraphText.contains(entry.getKey())) { List<XWPFRun> runs = paragraph.getRuns(); TextSegment found = paragraph.searchText(entry.getKey(), new PositionInParagraph()); if (found != null) { // 替换文本 int beginRun = found.getBeginRun(); int endRun = found.getEndRun(); if (beginRun >= 0 && endRun >= 0) { // 删除原有runs for (int runPos = beginRun; runPos <= endRun; runPos++) { paragraph.removeRun(runPos); } // 创建新run XWPFRun newRun = paragraph.insertNewRun(beginRun); newRun.setText(entry.getValue()); // 复制原有格式 if (runs.size() > 0 && runs.get(0) != null) { XWPFRun styleRun = runs.get(0); newRun.setFontFamily(styleRun.getFontFamily()); newRun.setFontSize(styleRun.getFontSize()); newRun.setBold(styleRun.isBold()); newRun.setItalic(styleRun.isItalic()); } } } } } } public static void main(String[] args) { String templatePath = "/path/to/template.docx"; String outputPath = "/path/to/output.docx"; // fillTemplate(templatePath, outputPath, user); } } ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/WordUtil.java
@@ -6,6 +6,7 @@ import freemarker.template.TemplateException; import lombok.extern.slf4j.Slf4j; import org.apache.poi.xwpf.usermodel.*; import org.springframework.mock.web.MockMultipartFile; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; @@ -15,7 +16,9 @@ import java.io.*; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @Slf4j @Component @@ -110,35 +113,38 @@ } public String generatePdf(String basePackagePath, String templateFileName, Object templateParam, String fileName, String saveDirectory) { public String generatePdf(String basePackagePath, String templateFileName, Map<String,Object> templateParam, String fileName, String saveDirectory) { try { fillTemplate(basePackagePath+templateFileName, saveDirectory+fileName+".docx", templateParam); // 创建 Freemarker 的 Configuration 对象,设置默认的不兼容改进选项 Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); configuration.setDefaultEncoding("utf-8"); // 设置模板加载器,加载模板文件 configuration.setTemplateLoader(new ClassTemplateLoader(getClass(), basePackagePath)); Template t = configuration.getTemplate(templateFileName, "utf-8"); // 使用 URLEncoder 对文件名进行编码,以防止中文文件名在不同浏览器和操作系统下出现乱码问题 // String encodedFileName = URLEncoder.encode(fileName + "_" + System.currentTimeMillis(), "utf-8"); String encodedFileName =fileName ; // 定义保存文件的路径 File saveDir = new File(saveDirectory); if (!saveDir.exists()) { saveDir.mkdirs(); } // 定义文件名 String filePath = saveDir.getAbsolutePath() + File.separator + encodedFileName + ".doc"; // 创建 Writer 对象,用于将生成的文档写到文件中,缓存区大小设为 10KB Writer out = new BufferedWriter(new FileWriter(filePath), 10240); // 将模型数据与模板结合生成 Word 文档,写入到 Writer 对象中 t.process(templateParam, out); out.close(); // Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); // configuration.setDefaultEncoding("utf-8"); // // 设置模板加载器,加载模板文件 // configuration.setTemplateLoader(new ClassTemplateLoader(getClass(), basePackagePath)); // Template t = configuration.getTemplate(templateFileName, "utf-8"); // // // 使用 URLEncoder 对文件名进行编码,以防止中文文件名在不同浏览器和操作系统下出现乱码问题 //// String encodedFileName = URLEncoder.encode(fileName + "_" + System.currentTimeMillis(), "utf-8"); // String encodedFileName =fileName ; // // // 定义保存文件的路径 // File saveDir = new File(saveDirectory); // if (!saveDir.exists()) { // saveDir.mkdirs(); // } // // // 定义文件名 // String filePath = saveDir.getAbsolutePath() + File.separator + encodedFileName + ".doc"; // // // 创建 Writer 对象,用于将生成的文档写到文件中,缓存区大小设为 10KB // Writer out = new BufferedWriter(new FileWriter(filePath), 10240); // // // 将模型数据与模板结合生成 Word 文档,写入到 Writer 对象中 // t.process(templateParam, out); // out.close(); String filePath = saveDirectory + File.separator + fileName + ".docx"; File file = new File(filePath); // 检查文件是否存在 @@ -152,16 +158,263 @@ fis.read(fileContent); } String test = pdfUtils.test(encodedFileName + ".doc"); String test = pdfUtils.test(fileName + ".docx"); // MultipartFile mockMultipartFile = new MockMultipartFile(encodedFileName+".doc", fileContent); // String s = ObsUploadUtil.obsUpload(mockMultipartFile); return test; } catch (IOException | TemplateException e) { } catch (IOException e) { log.error("生成pdf异常,异常原因:{}", e.getMessage(), e); throw new RuntimeException("生成pdf异常,异常原因:" + e.getMessage()); } } public static void fillTemplate(String templatePath, String outputPath,Map<String, Object> dataMap) { try (FileInputStream fis = new FileInputStream(templatePath)) { // 设置默认编码为UTF-8 System.setProperty("file.encoding", "UTF-8"); XWPFDocument document = new XWPFDocument(fis); // 处理段落 for (XWPFParagraph paragraph : document.getParagraphs()) { replaceParagraph(paragraph, dataMap); } // 处理表格 for (XWPFTable table : document.getTables()) { for (XWPFTableRow row : table.getRows()) { for (XWPFTableCell cell : row.getTableCells()) { for (XWPFParagraph paragraph : cell.getParagraphs()) { replaceParagraph(paragraph, dataMap); } } } } // 使用UTF-8编码保存文件 try (FileOutputStream fos = new FileOutputStream(outputPath)) { document.write(fos); } System.out.println("模板填充完成!文件保存在: " + outputPath); } catch (Exception e) { e.printStackTrace(); } } private static void replaceParagraph(XWPFParagraph paragraph, Map<String, Object> dataMap) { // 获取段落中所有runs List<XWPFRun> runs = paragraph.getRuns(); if (runs == null || runs.isEmpty()) return; // 首先合并所有runs的文本,以便正确识别占位符 StringBuilder fullText = new StringBuilder(); for (XWPFRun run : runs) { String text = run.getText(0); if (text != null) { fullText.append(text); } } String paragraphText = fullText.toString(); // 使用正则表达式查找所有占位符,包括括号内的 Pattern pattern = Pattern.compile("\\$\\{[^}]+\\}|\\([^)]*\\$\\{[^}]+\\}[^)]*\\)"); Matcher matcher = pattern.matcher(paragraphText); List<ReplacementInfo> replacements = new ArrayList<>(); // 收集所有需要替换的信息 while (matcher.find()) { String matched = matcher.group(); int start = matcher.start(); int end = matcher.end(); // 找出涉及到的runs int startRun = -1; int endRun = -1; int currentPos = 0; for (int i = 0; i < runs.size(); i++) { XWPFRun run = runs.get(i); String runText = run.getText(0); if (runText == null) continue; int runLength = runText.length(); if (startRun == -1 && currentPos + runLength > start) { startRun = i; } if (currentPos + runLength >= end) { endRun = i; break; } currentPos += runLength; } if (startRun != -1 && endRun != -1) { // 处理括号内的占位符 String replacement = processPlaceholder(matched, dataMap); replacements.add(new ReplacementInfo(startRun, endRun, matched, replacement)); } } // 从后向前替换,避免位置变化影响 Collections.sort(replacements, (a, b) -> b.startRun - a.startRun); for (ReplacementInfo info : replacements) { replaceRunRange(paragraph, info); } } private static String processPlaceholder(String text, Map<String, Object> dataMap) { // 处理括号内的占位符 Pattern placeholderPattern = Pattern.compile("\\$\\{([^}]+)\\}"); Matcher matcher = placeholderPattern.matcher(text); StringBuffer result = new StringBuffer(); while (matcher.find()) { String placeholder = matcher.group(0); // 完整的占位符 String key = matcher.group(1); // 占位符中的键 String replacement = Objects.nonNull(dataMap.get("${" + key + "}"))?String.valueOf(dataMap.get("${" + key + "}")):""; if (replacement != null) { // 如果在括号内,保留括号 if (text.startsWith("(") && text.endsWith(")")) { matcher.appendReplacement(result, replacement); } else { matcher.appendReplacement(result, Matcher.quoteReplacement(replacement)); } } } matcher.appendTail(result); return result.toString(); } private static class ReplacementInfo { int startRun; int endRun; String originalText; String replacementText; ReplacementInfo(int startRun, int endRun, String originalText, String replacementText) { this.startRun = startRun; this.endRun = endRun; this.originalText = originalText; this.replacementText = replacementText; } } private static void replaceRunRange(XWPFParagraph paragraph, ReplacementInfo info) { List<XWPFRun> runs = paragraph.getRuns(); // 保存第一个run的样式 XWPFRun styleRun = runs.get(info.startRun); RunStyle style = new RunStyle(styleRun); // 删除范围内的所有runs for (int i = info.endRun; i >= info.startRun; i--) { paragraph.removeRun(i); } // 创建新的run并设置文本 XWPFRun newRun = paragraph.insertNewRun(info.startRun); newRun.setText(info.replacementText); // 应用样式 style.applyStyle(newRun); } // 用于保存和恢复运行样式的辅助类 private static class RunStyle { String fontFamily; int fontSize; boolean bold; boolean italic; String color; UnderlinePatterns underline; RunStyle(XWPFRun run) { this.fontFamily = run.getFontFamily(); this.fontSize = run.getFontSize(); this.bold = run.isBold(); this.italic = run.isItalic(); this.color = run.getColor(); this.underline = run.getUnderline(); } void applyStyle(XWPFRun run) { if (fontFamily != null) { run.setFontFamily(fontFamily); run.setFontFamily(fontFamily, XWPFRun.FontCharRange.eastAsia); } if (fontSize != -1) { run.setFontSize(fontSize); } run.setBold(bold); run.setItalic(italic); if (color != null) { run.setColor(color); } if (underline != null) { run.setUnderline(underline); } } } // public String generatePdf(String basePackagePath, String templateFileName, Object templateParam, String fileName, String saveDirectory) { // try { // // 创建 Freemarker 的 Configuration 对象,设置默认的不兼容改进选项 // Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); // configuration.setDefaultEncoding("utf-8"); // // 设置模板加载器,加载模板文件 // configuration.setTemplateLoader(new ClassTemplateLoader(getClass(), basePackagePath)); // Template t = configuration.getTemplate(templateFileName, "utf-8"); // // // 使用 URLEncoder 对文件名进行编码,以防止中文文件名在不同浏览器和操作系统下出现乱码问题 //// String encodedFileName = URLEncoder.encode(fileName + "_" + System.currentTimeMillis(), "utf-8"); // String encodedFileName =fileName ; // // // 定义保存文件的路径 // File saveDir = new File(saveDirectory); // if (!saveDir.exists()) { // saveDir.mkdirs(); // } // // // 定义文件名 // String filePath = saveDir.getAbsolutePath() + File.separator + encodedFileName + ".doc"; // // // 创建 Writer 对象,用于将生成的文档写到文件中,缓存区大小设为 10KB // Writer out = new BufferedWriter(new FileWriter(filePath), 10240); // // // 将模型数据与模板结合生成 Word 文档,写入到 Writer 对象中 // t.process(templateParam, out); // out.close(); // // File file = new File(filePath); // // // 检查文件是否存在 // if (!file.exists()) { // throw new FileNotFoundException("文件不存在: " + filePath); // } // // // 读取文件内容 // byte[] fileContent = new byte[(int) file.length()]; // try (FileInputStream fis = new FileInputStream(file)) { // fis.read(fileContent); // } // // String test = pdfUtils.test(encodedFileName + ".doc"); //// MultipartFile mockMultipartFile = new MockMultipartFile(encodedFileName+".doc", fileContent); //// String s = ObsUploadUtil.obsUpload(mockMultipartFile); // return test; // } catch (IOException | TemplateException e) { // log.error("生成pdf异常,异常原因:{}", e.getMessage(), e); // throw new RuntimeException("生成pdf异常,异常原因:" + e.getMessage()); // } // } ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TCheckAcceptRecordServiceImpl.java
@@ -17,6 +17,7 @@ import com.ruoyi.system.vo.TCheckAcceptRecordVO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import java.util.List; @@ -40,10 +41,10 @@ PageInfo<TCheckAcceptRecordVO> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize()); List<TCheckAcceptRecordVO> list = this.baseMapper.pageList(query,pageInfo); list.forEach(item -> { item.setCleanSituation(item.getCleanSituation()!=null?(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CHECK_SITUATION,item.getCleanSituation())):""); item.setOverallSituation(item.getOverallSituation()!=null?(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CHECK_SITUATION,item.getOverallSituation())):""); item.setDeviceSituation(item.getDeviceSituation()!=null?(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CHECK_SITUATION,item.getDeviceSituation())):""); item.setFurnitureSituation(item.getDeviceSituation()!=null?(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CHECK_SITUATION,item.getFurnitureSituation())):""); item.setCleanSituation(StringUtils.hasLength(item.getCleanSituation()) ?(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CHECK_SITUATION,item.getCleanSituation())):""); item.setOverallSituation(StringUtils.hasLength(item.getOverallSituation())?(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CHECK_SITUATION,item.getOverallSituation())):""); item.setDeviceSituation(StringUtils.hasLength(item.getDeviceSituation())?(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CHECK_SITUATION,item.getDeviceSituation())):""); item.setFurnitureSituation(StringUtils.hasLength(item.getDeviceSituation())?(DictUtils.getDictLabel(DictConstants.DICT_TYPE_CHECK_SITUATION,item.getFurnitureSituation())):""); }); pageInfo.setRecords(list);