.docx 是主流格式,所以我们重点介绍 XWPF 的使用。
核心概念
在开始编码前,先了解几个核心类:
- XWPFDocument: 代表一个
.docx文档,它是所有操作的入口和容器。 - XWPFParagraph: 代表文档中的一个段落,你可以在段落中添加文本、图片、表格等。
- XWPFRun: 代表段落中具有相同格式(如字体、颜色、大小)的一组文本,一个段落可以包含多个
XWPFRun。 - XWPFTable: 代表一个表格。
- XWPFTableRow: 代表表格中的一行。
- 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();
}
}
}
代码解释:
new XWPFDocument(): 创建一个新的 Word 文档对象。document.createParagraph(): 创建一个新段落。paragraph.createRun(): 在段落中创建一个文本运行块,用于设置文本样式。run.setText("..."): 设置运行块中的文本。run.setFontSize(18),run.setBold(true): 设置字体大小和加粗样式。paragraph.setAlignment(ParagraphAlignment.CENTER): 设置段落对齐方式。document.createTable(3, 3): 创建一个指定行数和列数的表格。table.getRow(1).getCell(0).setText("..."): 定位到表格的特定单元格并写入内容。new FileOutputStream("output.docx"): 创建一个文件输出流,用于将生成的文档保存到磁盘。document.write(out): 将XWPFDocument对象的内容写入到输出流中。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 代码读取模板,找到这些标记并替换成实际数据,这样可以大大提高效率和文档的美观度。
