From ac4bf3bccb266666a60fd0addb73bce125d43758 Mon Sep 17 00:00:00 2001 From: xuhy <3313886187@qq.com> Date: 星期四, 06 三月 2025 19:15:26 +0800 Subject: [PATCH] bug修改 --- ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/WordUtil.java | 313 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 283 insertions(+), 30 deletions(-) diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/WordUtil.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/WordUtil.java index ce14b96..60d821a 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/WordUtil.java +++ b/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()); +// } +// } + -- Gitblit v1.7.1