杰瑞科技汇

Java POI如何高效写入Word文档?

.docx 是主流格式,所以我们重点介绍 XWPF 的使用。

核心概念

在开始编码前,先了解几个核心类:

  1. XWPFDocument: 代表一个 .docx 文档,它是所有操作的入口和容器。
  2. XWPFParagraph: 代表文档中的一个段落,你可以在段落中添加文本、图片、表格等。
  3. XWPFRun: 代表段落中具有相同格式(如字体、颜色、大小)的一组文本,一个段落可以包含多个 XWPFRun
  4. XWPFTable: 代表一个表格。
  5. XWPFTableRow: 代表表格中的一行。
  6. XWPFTableCell: 代表表格中的一个单元格。

添加 Maven 依赖

你需要在你的 pom.xml 文件中添加 POI 的依赖,为了支持 .docx,你需要 poi-ooxml

<dependencies>
    <!-- POI 核心 -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>5.2.5</version> <!-- 建议使用较新版本 -->
    </dependency>
    <!-- POI 用于处理 Office Open XML 格式 (.xlsx, .docx) -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>5.2.5</version>
    </dependency>
</dependencies>

基本操作(创建 Word 文档并写入内容)

下面是一个完整的示例,演示如何创建一个 .docx 文件,并向其中写入标题、段落、表格和图片。

import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import java.io.FileOutputStream;
import java.io.IOException;
public class WordWriterExample {
    public static void main(String[] args) {
        // 1. 创建一个空的 XWPFDocument 对象
        try (XWPFDocument document = new XWPFDocument()) {
            // 2. 写入标题
            // 创建一个段落
            XWPFParagraph titleParagraph = document.createParagraph();
            // 设置段落居中
            titleParagraph.setAlignment(ParagraphAlignment.CENTER);
            // 在段落中创建一个文本运行块
            XWPFRun titleRun = titleParagraph.createRun();
            // 设置文本内容
            titleRun.setText("Apache POI Word 文档生成示例");
            // 设置字体大小
            titleRun.setFontSize(18);
            // 设置加粗
            titleRun.setBold(true);
            // 3. 写入普通段落
            XWPFParagraph firstParagraph = document.createParagraph();
            XWPFRun firstRun = firstParagraph.createRun();
            firstRun.setText("这是一个使用 Apache POI 库生成的 Word 文档。");
            firstRun.setFontSize(12);
            firstRun.setBold(false);
            // 另一个段落,带换行
            XWPFParagraph secondParagraph = document.createParagraph();
            XWPFRun secondRun = secondParagraph.createRun();
            secondRun.setText("POI 是一个强大的 Java 库,用于操作微软 Office 格式文件。");
            secondRun.addBreak(); // 添加一个换行符
            secondRun.setText("除了文本,我们还可以添加表格和图片。");
            // 4. 写入表格
            // 创建一个 3行3列 的表格
            XWPFTable table = document.createTable(3, 3);
            table.setTableAlignment(TableRowAlign.CENTER); // 表格居中
            // 填充表头
            XWPFTableRow headerRow = table.getRow(0);
            headerRow.getCell(0).setText("姓名");
            headerRow.getCell(1).setText("年龄");
            headerRow.getCell(2).setText("城市");
            // 填充第一行数据
            XWPFTableRow row1 = table.getRow(1);
            row1.getCell(0).setText("张三");
            row1.getCell(1).setText("28");
            row1.getCell(2).setText("北京");
            // 填充第二行数据
            XWPFTableRow row2 = table.getRow(2);
            row2.getCell(0).setText("李四");
            row2.getCell(1).setText("32");
            row2.getCell(2).setText("上海");
            // 5. 写入图片
            // 准备一张图片,"logo.png" 放在项目根目录下
            String imagePath = "logo.png"; 
            try (FileOutputStream out = new FileOutputStream("output.docx")) {
                // 读取图片文件
                byte[] imageData = document.enhancedInsertPicture(imagePath, XWPFRelation.IMAGE_PNG, 300, 200);
                // 或者直接使用文件流插入
                // document.addPictureData(new FileInputStream(imagePath), XWPFDocument.PICTURE_TYPE_PNG);
                // XWPFPicture picture = ... // 获取图片对象并设置尺寸
                // 将文档写入输出流
                document.write(out);
                System.out.println("Word 文档 'output.docx' 生成成功!");
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

代码解释:

  1. new XWPFDocument(): 创建一个新的 Word 文档对象。
  2. document.createParagraph(): 创建一个新段落。
  3. paragraph.createRun(): 在段落中创建一个文本运行块,用于设置文本样式。
  4. run.setText("..."): 设置运行块中的文本。
  5. run.setFontSize(18), run.setBold(true): 设置字体大小和加粗样式。
  6. paragraph.setAlignment(ParagraphAlignment.CENTER): 设置段落对齐方式。
  7. document.createTable(3, 3): 创建一个指定行数和列数的表格。
  8. table.getRow(1).getCell(0).setText("..."): 定位到表格的特定单元格并写入内容。
  9. new FileOutputStream("output.docx"): 创建一个文件输出流,用于将生成的文档保存到磁盘。
  10. document.write(out): 将 XWPFDocument 对象的内容写入到输出流中。
  11. document.enhancedInsertPicture(...): (较新版本POI) 插入图片,可以指定宽度和高度。

常见操作与技巧

设置页面边距

CTDocumentProperties docProperties = document.getProperties().getExtendedProperties();
CTPageMar pageMar = docProperties.addNewPageMar();
pageMar.setLeft(720L); // 左边距,单位是 twip (1/20 点)
pageMar.setRight(720L);
pageMar.setTop(720L);
pageMar.setBottom(720L);

注意: 设置页面属性有时需要直接操作底层 XML 对象 (CT...),这比较繁琐,对于复杂样式,建议先创建一个模板文件,然后用 POI 去修改内容。

在指定位置插入内容(合并单元格)

// 创建一个 2x3 的表格
XWPFTable table = document.createTable(2, 3);
// 合并第一行的第2列和第3列
table.getRow(0).getCell(1).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
table.getRow(0).getCell(2).getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
table.getRow(0).getCell(0).setText("合并前");
table.getRow(0).getCell(1).setText("合并后的单元格");
table.getRow(1).getCell(0).setText("A");
table.getRow(1).getCell(1).setText("B");
table.getRow(1).getCell(2).setText("C");

读取现有 Word 文档并修改

POI 不仅可以创建,也可以读取和修改已有的 .docx 文件。

// 读取现有文档
try (XWPFDocument document = new XWPFDocument(new FileInputStream("template.docx"))) {
    // 修改第一个段落
    if (!document.getParagraphs().isEmpty()) {
        XWPFParagraph firstPara = document.getParagraphs().get(0);
        XWPFRun run = firstPara.createRun();
        run.setText("这是从模板修改后的内容。", 0); // 在位置0插入文本
    }
    // 修改表格内容
    for (XWPFTable table : document.getTables()) {
        for (XWPFTableRow row : table.getRows()) {
            for (XWPFTableCell cell : row.getTableCells()) {
                for (XWPFParagraph para : cell.getParagraphs()) {
                    for (XWPFRun r : para.getRuns()) {
                        String text = r.getText(0);
                        if (text != null && text.contains("${name}")) {
                            r.setText(text.replace("${name}", "王五"), 0);
                        }
                    }
                }
            }
        }
    }
    // 保存修改后的文档
    try (FileOutputStream out = new FileOutputStream("modified_template.docx")) {
        document.write(out);
        System.out.println("文档修改并保存成功!");
    }
} catch (IOException e) {
    e.printStackTrace();
}
任务 关键 API
创建文档 new XWPFDocument()
创建段落 document.createParagraph()
创建文本块 paragraph.createRun()
设置文本 run.setText("...")
设置样式 run.setBold(true), run.setFontSize(12), run.setColor("FF0000")
设置段落对齐 paragraph.setAlignment(ParagraphAlignment.CENTER)
创建表格 document.createTable(rows, cols)
操作表格单元格 table.getRow(i).getCell(j).setText("...")
插入图片 document.enhancedInsertPicture(path, type, width, height)
保存文档 document.write(new FileOutputStream("..."))

使用 POI 操作 Word 非常灵活,但对于复杂的版式控制(如页眉页脚、页码、复杂图文混排)可能会比较繁琐,在这种情况下,使用 Word 模板(.docx 文件) 是一个更推荐的实践,即先在 Word 中设计好版式,用 ${placeholder} 这样的标记作为变量,然后用 Java 代码读取模板,找到这些标记并替换成实际数据,这样可以大大提高效率和文档的美观度。

分享:
扫描分享到社交APP
上一篇
下一篇