使用 Apache POI 实现 Java Word 模板占位符替换功能

使用 Apache POI 实现 Java Word 模板占位符替换功能

在日常开发中,我们经常会遇到生成 Word 文档的需求,特别是在需要从模板导出 Word 文件时,比如生成合同、报告等。通过使用模板,开发者可以减少重复的工作,将预定义的占位符替换为实际的数据,生成定制化的 Word 文件。本文将介绍如何使用 Apache POI 库实现 Java 程序中的 Word 模板占位符替换功能,并最终导出定制化的 Word 文件。

1. 项目准备

在开始之前,你需要确保项目中引入了 Apache POI 依赖。这里假设你使用的是 Maven 项目,首先需要在 pom.xml 中添加 Apache POI 的依赖项:

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>5.2.3</version> <!-- 你可以使用最新版本 -->
    </dependency>
     <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>5.2.3</version>
     </dependency>
</dependencies>
2. 创建 Word 模板

首先,我们需要准备一个 Word 模板文件,里面包含一些占位符。假设我们有一个模板 template.docx,它位于 src/main/resources 目录下。模板内容如下:

bash 复制代码
尊敬的 {{name}} 先生/女士,

我们很高兴通知您,您的申请已成功。处理日期为:{{date}}。

感谢您的支持!

其中 {``{name}}{``{date}} 是占位符,我们希望在生成最终文档时将其替换为实际的数据。

3. Java 实现占位符替换

接下来,我们通过 Apache POI 库来加载 Word 模板,替换占位符,并输出一个新的 Word 文件。

完整的实现代码如下:

import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class WordTemplateExporter {

    public static void main(String[] args) {
        // 输出文件路径
        String outputPath = "output.docx";

        try {
            // 从 resources 中加载模板文件
            InputStream templateStream = WordTemplateExporter.class.getResourceAsStream("/template.docx");
            if (templateStream == null) {
                throw new RuntimeException("模板文件未找到!");
            }

            // 读取模板文件
            XWPFDocument document = new XWPFDocument(templateStream);

            // 替换模板中的占位符
            replacePlaceholder(document, "{{name}}", "张三");
            replacePlaceholder(document, "{{date}}", "2024-09-09");

            // 将替换后的内容写入新文件
            FileOutputStream fos = new FileOutputStream(outputPath);
            document.write(fos);

            // 关闭流
            fos.close();
            document.close();
            templateStream.close();

            System.out.println("Word 文件导出成功!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 替换 Word 文件中的占位符
     *
     * @param document   Word 文档对象
     * @param placeholder 占位符,例如 {{name}}
     * @param replacement 替换后的值,例如 "张三"
     */
    private static void replacePlaceholder(XWPFDocument document, String placeholder, String replacement) {
        // 遍历文档中的段落
        for (XWPFParagraph paragraph : document.getParagraphs()) {
            // 遍历段落中的文本部分
            for (XWPFRun run : paragraph.getRuns()) {
                String text = run.getText(0);
                if (text != null && text.contains(placeholder)) {
                    // 替换占位符
                    text = text.replace(placeholder, replacement);
                    run.setText(text, 0);  // 重新设置文本内容
                }
            }
        }
    }
}
4. 代码解析
  1. 加载模板 :我们使用 getResourceAsStream 方法从 resources 文件夹中加载 template.docx 文件,确保文件路径正确无误。这个文件会被打包进项目的 classpath 中,因此使用这种方法能够保证在不同环境下都能正确加载文件。
  2. 占位符替换逻辑
    • 使用 XWPFDocument 类读取 .docx 文件。
    • 遍历文档中的每个段落(XWPFParagraph),并且逐一遍历段落中的文本(XWPFRun)。
    • 在每个 run 中查找是否包含目标占位符,若包含则用实际数据替换。
  3. 写入输出文件 :占位符替换完成后,使用 FileOutputStream 将内容写入到一个新的 .docx 文件中,即最终生成的文档。
5. 运行结果

执行该程序后,将生成一个新的 Word 文件 output.docx,其中的占位符将被替换为实际数据:

bash 复制代码
复制代码尊敬的 张三 先生/女士,

我们很高兴通知您,您的申请已成功。处理日期为:2024-09-09。

感谢您的支持!
6. 注意事项
  1. 多线程环境:如果你在多线程环境中生成多个 Word 文件,需要确保流的安全性,避免并发问题。
  2. 复杂文档处理:如果你的模板包含复杂的结构(如表格、图片等),可能需要更多的代码来处理这些特殊元素。Apache POI 也提供了相应的 API 来处理这些场景。
  3. run 占位符问题 :在一些情况下,Word 文档中的一个占位符可能会分布在多个 XWPFRun 中。这种情况需要更加复杂的逻辑来拼接 run 并完成替换。
7. 总结

通过 Apache POI,Java 程序可以非常方便地处理 Word 文档的占位符替换问题。本文介绍了如何使用 Apache POI 读取 Word 模板、替换占位符并生成新的文档。对于一些简单的文档生成场景,这种方法非常直观且高效。但如果文档结构较为复杂(如需要动态插入表格或图片),则可能需要对代码进行更进一步的优化。

Apache POI 提供了对 Word 文件的细粒度控制能力,适合在复杂的办公文档生成场景下使用。

相关推荐
魔道不误砍柴功2 分钟前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2342 分钟前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
闲晨5 分钟前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
测开小菜鸟2 小时前
使用python向钉钉群聊发送消息
java·python·钉钉
P.H. Infinity3 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天3 小时前
java的threadlocal为何内存泄漏
java
caridle3 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
^velpro^3 小时前
数据库连接池的创建
java·开发语言·数据库
苹果醋33 小时前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx
秋の花3 小时前
【JAVA基础】Java集合基础
java·开发语言·windows