|
|
@@ -1,20 +1,19 @@
|
|
|
-package com.hotent.util.wordexcelutils;/**
|
|
|
- * @program: cbjs-mvue-master
|
|
|
- * @description:
|
|
|
- * @author: zhao yue yue
|
|
|
- * @create: 2025-11-27 15:34
|
|
|
- */
|
|
|
+package com.hotent.util.wordexcelutils;
|
|
|
|
|
|
import com.hotent.base.util.StringUtil;
|
|
|
import lombok.Data;
|
|
|
import lombok.Getter;
|
|
|
import org.apache.poi.xwpf.usermodel.*;
|
|
|
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
|
|
|
+
|
|
|
+import java.math.BigInteger;
|
|
|
import java.util.*;
|
|
|
-import java.io.*;
|
|
|
|
|
|
/**
|
|
|
- *@author: zhao yue yue
|
|
|
- *@create: 2025-11-27 15:34
|
|
|
+ * 完整处理模板:替换占位符 + 填充表格数据,支持内容自适应高度
|
|
|
+ *
|
|
|
+ * @author: zhao yue yue
|
|
|
+ * @create: 2025-11-27 15:34
|
|
|
*/
|
|
|
public class CompleteTemplateProcessor {
|
|
|
|
|
|
@@ -37,18 +36,14 @@ public class CompleteTemplateProcessor {
|
|
|
System.out.println("生成日期: " + generateDate);
|
|
|
|
|
|
// 2. 替换文档中的占位符
|
|
|
- //replaceDocumentPlaceholders(document, organizationName, totalDocuments, totalPages, generateDate);
|
|
|
- // 替换映射
|
|
|
Map<String, String> replacements = new HashMap<>();
|
|
|
replacements.put("{价格主管部门或成本监审机构}", organizationName);
|
|
|
replacements.put("{材料件数}", String.valueOf(totalDocuments));
|
|
|
replacements.put("{材料页数}", String.valueOf(totalPages));
|
|
|
replacements.put("{登记表生成日期}", generateDate);
|
|
|
- replacements.put("{序号}", "1");
|
|
|
- replacements.put("{资料名称}", rowDataList.get(0).getDocumentName());
|
|
|
- replacements.put("{页数}", String.valueOf(rowDataList.get(0).getPageCount()));
|
|
|
- replacements.put("{备注}", rowDataList.get(0).getRemark());
|
|
|
- SmartTemplateWriter.writeToTemplate(document,replacements);
|
|
|
+
|
|
|
+ // 注意:这里不替换表格内的占位符,因为表格数据会在processTableData中单独处理
|
|
|
+ SmartTemplateWriter.writeToTemplate(document, replacements);
|
|
|
|
|
|
// 3. 处理表格数据
|
|
|
processTableData(document, rowDataList);
|
|
|
@@ -64,33 +59,6 @@ public class CompleteTemplateProcessor {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 替换文档中的占位符
|
|
|
- */
|
|
|
- private static void replaceDocumentPlaceholders(XWPFDocument document,
|
|
|
- String organizationName,
|
|
|
- int totalDocuments,
|
|
|
- int totalPages,
|
|
|
- String generateDate) {
|
|
|
-
|
|
|
- // 替换映射
|
|
|
- Map<String, String> replacements = new HashMap<>();
|
|
|
- replacements.put("{价格主管部门或成本监审机构}", organizationName);
|
|
|
- replacements.put("{材料件数}", String.valueOf(totalDocuments));
|
|
|
- replacements.put("{材料页数}", String.valueOf(totalPages));
|
|
|
- replacements.put("{登记表生成日期}", generateDate);
|
|
|
-
|
|
|
- // 在文档中查找并替换
|
|
|
- for (Map.Entry<String, String> entry : replacements.entrySet()) {
|
|
|
- boolean found = replaceTextInDocument(document, entry.getKey(), entry.getValue());
|
|
|
- if (!found) {
|
|
|
- System.out.println("警告: 未找到占位符 " + entry.getKey());
|
|
|
- } else {
|
|
|
- System.out.println("成功替换: " + entry.getKey() + " → " + entry.getValue());
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
* 处理表格数据
|
|
|
*/
|
|
|
private static void processTableData(XWPFDocument document, List<TableRowData> rowDataList) {
|
|
|
@@ -101,19 +69,20 @@ public class CompleteTemplateProcessor {
|
|
|
}
|
|
|
|
|
|
XWPFTable table = tables.get(0);
|
|
|
- System.out.println("找到表格,行数: " + table.getRows().size());
|
|
|
+ System.out.println("找到表格,原始行数: " + table.getRows().size());
|
|
|
|
|
|
// 找到模板行(包含占位符的行)
|
|
|
- //int templateRowIndex = findTemplateRow(table);
|
|
|
- /* if (templateRowIndex == -1) {
|
|
|
+ int templateRowIndex = findTemplateRow(table);
|
|
|
+ if (templateRowIndex == -1) {
|
|
|
System.err.println("错误: 未找到包含占位符的模板行");
|
|
|
return;
|
|
|
- }*/
|
|
|
+ }
|
|
|
|
|
|
- System.out.println("模板行索引: " + 1);
|
|
|
+ System.out.println("模板行索引: " + templateRowIndex);
|
|
|
+ System.out.println("需要处理的数据行数: " + rowDataList.size());
|
|
|
|
|
|
// 处理表格数据
|
|
|
- processTableRows(table, 1, rowDataList);
|
|
|
+ processTableRows(table, templateRowIndex, rowDataList);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -152,25 +121,60 @@ public class CompleteTemplateProcessor {
|
|
|
private static void processTableRows(XWPFTable table, int templateRowIndex, List<TableRowData> rowDataList) {
|
|
|
XWPFTableRow templateRow = table.getRows().get(templateRowIndex);
|
|
|
|
|
|
- // 1. 首先替换模板行(第一行数据)
|
|
|
- /* if (rowDataList.size() > 0) {
|
|
|
- replaceTemplateRow(templateRow, rowDataList.get(0), 1);
|
|
|
- System.out.println("替换模板行完成");
|
|
|
- }*/
|
|
|
+ System.out.println("开始处理表格行,模板行索引: " + templateRowIndex);
|
|
|
+ System.out.println("数据列表大小: " + rowDataList.size());
|
|
|
|
|
|
- // 2. 添加额外的数据行
|
|
|
- for (int i = 1; i < rowDataList.size(); i++) {
|
|
|
- addDataRow(table, templateRow, rowDataList.get(i), i + 1, templateRowIndex + i);
|
|
|
- System.out.println("添加数据行: " + (i + 1));
|
|
|
+ // 1. 先清理模板行之后的所有行(保留汇总行)
|
|
|
+ int summaryRowIndex = findSummaryRow(table);
|
|
|
+ if (summaryRowIndex == -1) {
|
|
|
+ System.err.println("警告: 未找到汇总行");
|
|
|
+ summaryRowIndex = table.getRows().size();
|
|
|
}
|
|
|
|
|
|
- // 3. 清理多余的空行(保留汇总行)
|
|
|
- cleanupEmptyRows(table, templateRowIndex + rowDataList.size());
|
|
|
+ System.out.println("汇总行索引: " + summaryRowIndex);
|
|
|
+
|
|
|
+ // 从汇总行的前一行开始删除,直到模板行之后
|
|
|
+ for (int i = summaryRowIndex - 1; i > templateRowIndex; i--) {
|
|
|
+ if (i < table.getRows().size()) {
|
|
|
+ table.removeRow(i);
|
|
|
+ System.out.println("删除行: " + i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 如果数据列表不为空,首先处理第一条数据
|
|
|
+ if (!rowDataList.isEmpty()) {
|
|
|
+ System.out.println("处理第一条数据: " + rowDataList.get(0).getDocumentName());
|
|
|
+ replaceTemplateRow(templateRow, rowDataList.get(0), 1);
|
|
|
+
|
|
|
+ // 3. 添加额外的数据行(从第二条数据开始)
|
|
|
+ for (int i = 1; i < rowDataList.size(); i++) {
|
|
|
+ System.out.println("添加数据行 " + (i+1) + ": " + rowDataList.get(i).getDocumentName());
|
|
|
+ addDataRow(table, templateRow, rowDataList.get(i), i + 1, templateRowIndex + i);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 如果没有数据,清理模板行
|
|
|
+ clearTemplateRow(templateRow);
|
|
|
+ }
|
|
|
|
|
|
System.out.println("表格处理完成,最终行数: " + table.getRows().size());
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * 清理模板行(当没有数据时)
|
|
|
+ */
|
|
|
+ private static void clearTemplateRow(XWPFTableRow row) {
|
|
|
+ List<XWPFTableCell> cells = row.getTableCells();
|
|
|
+ if (cells.size() < 4) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ setCellTextWithAutoHeight(cells.get(0), "", false);
|
|
|
+ setCellTextWithAutoHeight(cells.get(1), "", false);
|
|
|
+ setCellTextWithAutoHeight(cells.get(2), "", false);
|
|
|
+ setCellTextWithAutoHeight(cells.get(3), "", true);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
* 替换模板行
|
|
|
*/
|
|
|
private static void replaceTemplateRow(XWPFTableRow row, TableRowData data, int sequence) {
|
|
|
@@ -180,50 +184,51 @@ public class CompleteTemplateProcessor {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // 替换占位符
|
|
|
- //replaceInCell(cells.get(0), "[{序号}]", String.valueOf(sequence));
|
|
|
- // replaceInCell(cells.get(1), "[{资料名称}]", data.getDocumentName());
|
|
|
- // replaceInCell(cells.get(2), "[{页数}]", data.getPageCount() > 0 ? String.valueOf(data.getPageCount()) : "");
|
|
|
- // replaceInCell(cells.get(3), "[{备注}]", data.getRemark() != null ? data.getRemark() : "");
|
|
|
+ System.out.println("替换模板行,序号: " + sequence + ", 资料名称: " + data.getDocumentName());
|
|
|
+
|
|
|
+ // 设置单元格内容,支持自适应高度
|
|
|
+ setCellTextWithAutoHeight(cells.get(0), String.valueOf(sequence), false);
|
|
|
+ setCellTextWithAutoHeight(cells.get(1), data.getDocumentName(), false);
|
|
|
+ setCellTextWithAutoHeight(cells.get(2), data.getPageCount() > 0 ? String.valueOf(data.getPageCount()) : "", false);
|
|
|
+
|
|
|
+ // 特别注意:备注内容要完整显示
|
|
|
+ String remark = data.getRemark() != null ? data.getRemark() : "";
|
|
|
+ System.out.println("备注内容长度: " + remark.length());
|
|
|
+ setCellTextWithAutoHeight(cells.get(3), remark, true);
|
|
|
+
|
|
|
+ // 设置行高自适应
|
|
|
+ setRowAutoHeight(row);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 添加数据行
|
|
|
*/
|
|
|
private static void addDataRow(XWPFTable table, XWPFTableRow templateRow, TableRowData data, int sequence, int insertIndex) {
|
|
|
+ System.out.println("添加新行到索引: " + insertIndex + ", 序列号: " + sequence);
|
|
|
+
|
|
|
// 创建新行
|
|
|
XWPFTableRow newRow = table.insertNewTableRow(insertIndex);
|
|
|
|
|
|
// 复制模板行的单元格结构
|
|
|
for (int i = 0; i < templateRow.getTableCells().size(); i++) {
|
|
|
XWPFTableCell newCell = newRow.addNewTableCell();
|
|
|
- // 复制单元格样式(简化)
|
|
|
+ // 复制单元格样式
|
|
|
copyCellStyle(templateRow.getTableCells().get(i), newCell);
|
|
|
}
|
|
|
|
|
|
- // 填充数据
|
|
|
+ // 填充数据,备注列支持自适应高度
|
|
|
List<XWPFTableCell> cells = newRow.getTableCells();
|
|
|
- setCellText(cells.get(0), String.valueOf(sequence));
|
|
|
- setCellText(cells.get(1), data.getDocumentName());
|
|
|
- setCellText(cells.get(2), data.getPageCount() > 0 ? String.valueOf(data.getPageCount()) : "");
|
|
|
- setCellText(cells.get(3), data.getRemark() != null ? data.getRemark() : "");
|
|
|
- }
|
|
|
+ setCellTextWithAutoHeight(cells.get(0), String.valueOf(sequence), false);
|
|
|
+ setCellTextWithAutoHeight(cells.get(1), data.getDocumentName(), false);
|
|
|
+ setCellTextWithAutoHeight(cells.get(2), data.getPageCount() > 0 ? String.valueOf(data.getPageCount()) : "", false);
|
|
|
|
|
|
- /**
|
|
|
- * 清理多余的空行
|
|
|
- */
|
|
|
- private static void cleanupEmptyRows(XWPFTable table, int startIndex) {
|
|
|
- // 找到汇总行
|
|
|
- int summaryRowIndex = findSummaryRow(table);
|
|
|
- if (summaryRowIndex == -1) return;
|
|
|
+ // 特别注意:备注内容要完整显示
|
|
|
+ String remark = data.getRemark() != null ? data.getRemark() : "";
|
|
|
+ System.out.println("添加行的备注内容长度: " + remark.length());
|
|
|
+ setCellTextWithAutoHeight(cells.get(3), remark, true);
|
|
|
|
|
|
- // 清理汇总行之前的空行
|
|
|
- for (int i = summaryRowIndex - 1; i >= startIndex; i--) {
|
|
|
- if (i < table.getRows().size() && isRowEmpty(table.getRows().get(i))) {
|
|
|
- table.removeRow(i);
|
|
|
- System.out.println("清理空行: " + i);
|
|
|
- }
|
|
|
- }
|
|
|
+ // 设置行高自适应
|
|
|
+ setRowAutoHeight(newRow);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -240,90 +245,92 @@ public class CompleteTemplateProcessor {
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
- // ========== 工具方法 ==========
|
|
|
-
|
|
|
/**
|
|
|
- * 替换文档中的文本
|
|
|
+ * 设置单元格文本,支持自适应高度
|
|
|
+ * @param cell 单元格
|
|
|
+ * @param text 文本内容
|
|
|
+ * @param isRemarksColumn 是否为备注列(需要特殊处理)
|
|
|
*/
|
|
|
- private static boolean replaceTextInDocument(XWPFDocument document, String findText, String replaceText) {
|
|
|
- boolean found = false;
|
|
|
+ private static void setCellTextWithAutoHeight(XWPFTableCell cell, String text, boolean isRemarksColumn) {
|
|
|
+ // 清除现有内容
|
|
|
+ for (int i = cell.getParagraphs().size() - 1; i >= 0; i--) {
|
|
|
+ cell.removeParagraph(i);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加新内容
|
|
|
+ XWPFParagraph paragraph = cell.addParagraph();
|
|
|
|
|
|
- // 在段落中查找
|
|
|
- for (XWPFParagraph paragraph : document.getParagraphs()) {
|
|
|
- if (replaceInParagraph(paragraph, findText, replaceText)) {
|
|
|
- found = true;
|
|
|
+ // 对于备注列,设置左对齐,允许自动换行
|
|
|
+ if (isRemarksColumn) {
|
|
|
+ paragraph.setAlignment(ParagraphAlignment.LEFT);
|
|
|
+ // 设置单元格垂直顶部对齐
|
|
|
+ CTTc ctTc = cell.getCTTc();
|
|
|
+ if (ctTc.getTcPr() == null) {
|
|
|
+ ctTc.addNewTcPr();
|
|
|
}
|
|
|
- }
|
|
|
+ ctTc.getTcPr().addNewVAlign().setVal(org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc.TOP);
|
|
|
|
|
|
- // 在表格中查找
|
|
|
- for (XWPFTable table : document.getTables()) {
|
|
|
- for (XWPFTableRow row : table.getRows()) {
|
|
|
- for (XWPFTableCell cell : row.getTableCells()) {
|
|
|
- for (XWPFParagraph paragraph : cell.getParagraphs()) {
|
|
|
- if (replaceInParagraph(paragraph, findText, replaceText)) {
|
|
|
- found = true;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ // 设置单元格宽度,确保备注列足够宽
|
|
|
+ if (ctTc.getTcPr().getTcW() == null) {
|
|
|
+ ctTc.getTcPr().addNewTcW().setW(BigInteger.valueOf(5000)); // 设置足够宽度
|
|
|
}
|
|
|
+ } else {
|
|
|
+ paragraph.setAlignment(ParagraphAlignment.CENTER);
|
|
|
}
|
|
|
|
|
|
- return found;
|
|
|
- }
|
|
|
+ XWPFRun run = paragraph.createRun();
|
|
|
+ run.setText(text);
|
|
|
|
|
|
- private static boolean replaceInParagraph(XWPFParagraph paragraph, String findText, String replaceText) {
|
|
|
- boolean found = false;
|
|
|
- for (XWPFRun run : paragraph.getRuns()) {
|
|
|
- String text = run.getText(0);
|
|
|
- if (text != null && text.contains(findText)) {
|
|
|
- run.setText(text.replace(findText, replaceText), 0);
|
|
|
- found = true;
|
|
|
+ // 设置字体
|
|
|
+ run.setFontFamily("宋体");
|
|
|
+ run.setFontSize(10); // 使用较小的字体确保内容完整显示
|
|
|
+
|
|
|
+ // 重要:确保换行符被正确处理
|
|
|
+ if (text != null && text.contains("\n")) {
|
|
|
+ String[] lines = text.split("\n");
|
|
|
+ run.setText(lines[0], 0);
|
|
|
+ for (int i = 1; i < lines.length; i++) {
|
|
|
+ run.addBreak(); // 添加换行
|
|
|
+ run.setText(lines[i]);
|
|
|
}
|
|
|
}
|
|
|
- return found;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 替换单元格中的文本
|
|
|
+ * 设置行高自适应
|
|
|
*/
|
|
|
- private static void replaceInCell(XWPFTableCell cell, String findText, String replaceText) {
|
|
|
- for (XWPFParagraph paragraph : cell.getParagraphs()) {
|
|
|
- for (XWPFRun run : paragraph.getRuns()) {
|
|
|
- String text = run.getText(0);
|
|
|
- if (text != null && text.contains(findText)) {
|
|
|
- run.setText(text.replace(findText, replaceText), 0);
|
|
|
- }
|
|
|
+ private static void setRowAutoHeight(XWPFTableRow row) {
|
|
|
+ try {
|
|
|
+ // 移除固定行高设置,允许自动调整
|
|
|
+ if (row.getCtRow().getTrPr() != null) {
|
|
|
+ row.getCtRow().getTrPr().getTrHeightList().forEach(trHeight -> {
|
|
|
+ trHeight.setHRule(org.openxmlformats.schemas.wordprocessingml.x2006.main.STHeightRule.AUTO);
|
|
|
+ });
|
|
|
}
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("设置行高自适应时出错: " + e.getMessage());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 设置单元格文本
|
|
|
- */
|
|
|
- private static void setCellText(XWPFTableCell cell, String text) {
|
|
|
- // 清除现有内容
|
|
|
- for (int i = cell.getParagraphs().size() - 1; i >= 0; i--) {
|
|
|
- cell.removeParagraph(i);
|
|
|
- }
|
|
|
-
|
|
|
- // 添加新内容
|
|
|
- XWPFParagraph paragraph = cell.addParagraph();
|
|
|
- XWPFRun run = paragraph.createRun();
|
|
|
- run.setText(text);
|
|
|
- paragraph.setAlignment(ParagraphAlignment.CENTER);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
* 复制单元格样式
|
|
|
*/
|
|
|
private static void copyCellStyle(XWPFTableCell source, XWPFTableCell target) {
|
|
|
try {
|
|
|
+ // 复制背景色
|
|
|
target.setColor(source.getColor());
|
|
|
- if (StringUtil.isNotEmpty(String.valueOf(source.getWidth()) )) {
|
|
|
- target.setWidth(String.valueOf(source.getWidth()));
|
|
|
+ String width =String.valueOf(source.getWidth());
|
|
|
+ if (StringUtil.isNotEmpty(width)) {
|
|
|
+ target.setWidth(width);
|
|
|
+ } else {
|
|
|
+ // 如果源单元格没有宽度,为备注列设置更宽
|
|
|
+ String cellText = getCellText(source);
|
|
|
+ if (cellText != null && cellText.contains("{备注}")) {
|
|
|
+ target.setWidth("5000"); // 备注列更宽
|
|
|
+ }
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
- // 忽略样式复制错误
|
|
|
+ System.err.println("复制单元格样式时出错: " + e.getMessage());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -377,11 +384,14 @@ public class CompleteTemplateProcessor {
|
|
|
private int pageCount;
|
|
|
private String remark;
|
|
|
|
|
|
- public TableRowData() {
|
|
|
+ public TableRowData(String documentName, int pageCount, String remark) {
|
|
|
this.documentName = documentName;
|
|
|
this.pageCount = pageCount;
|
|
|
this.remark = remark;
|
|
|
}
|
|
|
|
|
|
+ public TableRowData() {
|
|
|
+ // 默认构造函数
|
|
|
+ }
|
|
|
}
|
|
|
-}
|
|
|
+}
|