学习笔记:使用 Apache POI 导出 Word 并动态替换占位符

依赖准备
确保 Maven 依赖包含以下库:

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>5.2.3</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.2.3</version>
</dependency>

核心实现步骤

模板准备
创建 Word 模板文档(.docx),使用 ${placeholder} 格式标记需要替换的占位符。例如:

尊敬的${name}:
您的订单编号为${orderId}。

代码实现

import org.apache.poi.xwpf.usermodel.*;
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class WordTemplateProcessor {
    public static void processTemplate(String inputPath, String outputPath, 
                                     Map<String, String> replacements) throws IOException {
        try (XWPFDocument doc = new XWPFDocument(new FileInputStream(inputPath))) {
            
            // 替换段落占位符
            for (XWPFParagraph p : doc.getParagraphs()) {
                replacePlaceholders(p, replacements);
            }
            
            // 处理表格中的占位符
            for (XWPFTable tbl : doc.getTables()) {
                for (XWPFTableRow row : tbl.getRows()) {
                    for (XWPFTableCell cell : row.getTableCells()) {
                        for (XWPFParagraph p : cell.getParagraphs()) {
                            replacePlaceholders(p, replacements);
                        }
                    }
                }
            }
            
            // 动态添加段落(基于最后一段样式)
            if (!doc.getParagraphs().isEmpty()) {
                XWPFParagraph lastParagraph = doc.getParagraphs().get(doc.getParagraphs().size()-1);
                XWPFParagraph newPara = doc.createParagraph();
                newPara.createRun().setText("动态生成的新内容");
                newPara.setStyle(lastParagraph.getStyle());
            }
            
            try (FileOutputStream out = new FileOutputStream(outputPath)) {
                doc.write(out);
            }
        }
    }
    
    private static void replacePlaceholders(XWPFParagraph p, Map<String, String> replacements) {
        String text = p.getText();
        if (text != null && text.contains("${")) {
            for (Map.Entry<String, String> entry : replacements.entrySet()) {
                text = text.replace("${" + entry.getKey() + "}", entry.getValue());
            }
            p.removeRun(0);
            p.createRun().setText(text);
        }
    }
}

动态段落生成扩展

克隆段落样式
当需要根据模板段落动态生成新内容时,可通过以下方式保持格式一致:

XWPFParagraph templatePara = doc.getParagraphs().get(0);
XWPFParagraph newPara = doc.createParagraph();

// 复制段落样式
newPara.setStyle(templatePara.getStyle());
newPara.setAlignment(templatePara.getAlignment());
newPara.setSpacingBetween(templatePara.getSpacingBetween());

// 复制文本样式
XWPFRun templateRun = templatePara.getRuns().get(0);
XWPFRun newRun = newPara.createRun();
newRun.setFontFamily(templateRun.getFontFamily());
newRun.setFontSize(templateRun.getFontSize());
newRun.setBold(templateRun.isBold());

处理复杂替换场景

多行内容替换
对于需要换行的替换内容,使用 \n 并设置 run 的换行属性:

String multiLineText = "第一行\n第二行";
XWPFRun run = paragraph.createRun();
run.setText(multiLineText);
run.addBreak(BreakType.TEXT_WRAPPING);

条件性段落生成
根据业务逻辑决定是否添加段落:

if (needAdditionalContent) {
    XWPFParagraph newPara = doc.createParagraph();
    newPara.createRun().setText("条件性生成的内容");
    // 复制之前段落的样式...
}

注意事项

  • POI 操作 Word 文档时会保留原有样式,但直接替换文本可能影响格式复杂度
  • 对于表格中的占位符,需要递归处理每个单元格
  • 动态生成的段落应考虑文档的分节符(Section)和页面布局影响
  • 大量文本替换时建议使用 StringBuilder 优化性能

完整示例可扩展为支持循环生成表格行、条件性插入图片等复杂场景,原理类似通过定位模板标记位置后进行动态内容操作。

使用 Apache POI 导出 Excel 模板时,集合占位符可用于动态填充表格数据。以下是使用集合占位符的一般步骤和示例代码: #### 步骤 1. **准备 Excel 模板**:在 Excel 模板中设置占位符,例如 `{list.name}`、`{list.age}` 等,这里的 `list` 代表集合,`name` 和 `age` 是集合元素的属性。 2. **读取 Excel 模板**:使用 Apache POI 读取模板文件。 3. **数据准备**:准备一个包含数据的集合。 4. **替换占位符**:遍历集合,将占位符替换为实际数据。 5. **保存新文件**:将替换后的内容保存为新的 Excel 文件。 #### 示例代码 ```java import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class ExcelTemplateFiller { public static void main(String[] args) { try { // 读取 Excel 模板 FileInputStream fis = new FileInputStream("template.xlsx"); Workbook workbook = new XSSFWorkbook(fis); Sheet sheet = workbook.getSheetAt(0); // 准备数据集合 List<Map<String, Object>> dataList = new ArrayList<>(); Map<String, Object> data1 = new HashMap<>(); data1.put("name", "John"); data1.put("age", 25); dataList.add(data1); Map<String, Object> data2 = new HashMap<>(); data2.put("name", "Jane"); data2.put("age", 30); dataList.add(data2); // 替换占位符 for (int rowIndex = 0; rowIndex <= sheet.getLastRowNum(); rowIndex++) { Row row = sheet.getRow(rowIndex); if (row != null) { for (int cellIndex = 0; cellIndex < row.getLastCellNum(); cellIndex++) { Cell cell = row.getCell(cellIndex); if (cell != null && cell.getCellType() == CellType.STRING) { String cellValue = cell.getStringCellValue(); for (Map<String, Object> data : dataList) { for (Map.Entry<String, Object> entry : data.entrySet()) { String placeholder = "{list." + entry.getKey() + "}"; if (cellValue.contains(placeholder)) { cellValue = cellValue.replace(placeholder, entry.getValue().toString()); cell.setCellValue(cellValue); } } } } } } } // 保存新文件 FileOutputStream fos = new FileOutputStream("output.xlsx"); workbook.write(fos); fos.close(); workbook.close(); fis.close(); } catch (IOException e) { e.printStackTrace(); } } } ``` ### 代码解释 1. **读取模板**:使用 `FileInputStream` 和 `XSSFWorkbook` 读取 Excel 模板文件。 2. **数据准备**:创建一个包含 `Map` 的 `List`,每个 `Map` 代表一个数据对象。 3. **替换占位符**:遍历 Excel 表格的每一行和每一列,检查单元格中是否包含占位符,如果包含则替换为实际数据。 4. **保存文件**:使用 `FileOutputStream` 将替换后的内容保存为新的 Excel 文件。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值