Java POI 操作 Word 与 PDF 完全指南:从入门到精通,解决文档处理痛点
(文章描述/ 还在为 Java 环境下批量处理 Word 文档和 PDF 文件而烦恼吗?本文将带你深入掌握 Apache POI 及其相关生态,全面解析如何使用 Java 高效操作 Word(.docx)和 PDF,涵盖内容读取、写入、样式设置、复杂表格处理以及 PDF 生成与合并等核心场景,无论你是需要生成报表、自动化办公文档,还是处理用户上传的文件,本指南都将提供详尽的代码示例和最佳实践,助你轻松搞定 Java 文档处理,成为团队里的文档处理专家!

引言:为什么 Java POI 是文档处理的“瑞士军刀”?
在当今的企业级应用开发中,文档处理是一项不可或缺的功能,无论是生成动态报表、批量导出合同模板,还是处理用户上传的简历、发票,我们都需要一种强大、可靠的方式来操作 Word 和 PDF 格式的文件。
Apache POI(Poor Obfuscation Implementation)作为 Java 领域最著名的操作 Office 格式文件的库,就像一把“瑞士军刀”,功能强大且应用广泛,它不仅支持 Word(.doc 和 .docx),还支持 Excel 和 PowerPoint,POI 本身并不直接支持 PDF,这就需要我们引入其他优秀的库,如 iText 或 Flying Saucer (XML Worker),来实现与 PDF 的无缝对接。
本文将聚焦于 Java POI Word 和 Java PDF 两大核心,为你提供一条清晰的学习和实践路径,解决你在实际开发中遇到的各种难题。
第一部分:深入 Java POI Word 操作 (Apache POI)
Apache POI 对于 Word 的处理主要分为两类:针对旧版 .doc 格式的 HWPF,以及针对新版 .docx 格式的 XWPF。强烈建议使用 XWPF,因为 .docx 是目前的主流格式,且 HWPF 的功能相对有限。

1 准备工作:添加 Maven 依赖
在你的 pom.xml 文件中添加 POI 的核心依赖,为了减少包大小,我们可以只引入必要的模块。
<!-- POI Core -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.3</version>
</dependency>
<!-- POI OOXML for .docx format -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version>
</dependency>
<!-- For parsing HTML (optional, useful for rich text) -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>5.2.3</version>
</dependency>
2 读取 Word 文档内容
读取是操作的第一步,我们可以轻松获取文档中的段落、表格和图片。
import org.apache.poi.xwpf.usermodel.*;
import java.io.FileInputStream;
import java.io.IOException;
public class ReadWordExample {
public static void main(String[] args) {
String filePath = "example.docx";
try (XWPFDocument document = new XWPFDocument(new FileInputStream(filePath))) {
// 1. 读取所有段落
System.out.println("--- 段落内容 ---");
for (XWPFParagraph paragraph : document.getParagraphs()) {
System.out.println(paragraph.getText());
}
// 2. 读取所有表格
System.out.println("\n--- 表格内容 ---");
for (XWPFTable table : document.getTables()) {
for (XWPFTableRow row : table.getRows()) {
for (XWPFTableCell cell : row.getTableCells()) {
System.out.print(cell.getText() + "\t");
}
System.out.println();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
3 创建与写入 Word 文档
生成新文档是 POI 更常见的应用场景。
import org.apache.poi.xwpf.usermodel.*;
import java.io.FileOutputStream;
import java.io.IOException;
public class CreateWordExample {
public static void main(String[] args) {
XWPFDocument document = new XWPFDocument();
// 创建段落
XWPFParagraph titleParagraph = document.createParagraph();
titleParagraph.setAlignment(ParagraphAlignment.CENTER); // 居中
XWPFRun titleRun = titleParagraph.createRun();
titleRun.setBold(true);
titleRun.setFontSize(16);
titleRun.setText("Java POI Word 文档生成示例");
// 创建普通段落
XWPFParagraph paragraph = document.createParagraph();
XWPFRun run = paragraph.createRun();
run.setText("这是一个使用 Apache POI 生成的 Word 段落。");
run.addBreak(); // 换行
run.setText("支持设置字体、大小、颜色等样式。");
// 创建表格
XWPFTable table = document.createTable(3, 3); // 3行3列
table.setTableAlignment(TableAlignment.CENTER); // 表格居中
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
XWPFTableCell cell = table.getRow(i).getCell(j);
cell.setText("单元格 " + (i + 1) + "-" + (j + 1));
}
}
// 保存文档
try (FileOutputStream out = new FileOutputStream("created_example.docx")) {
document.write(out);
System.out.println("Word 文档创建成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
4 高级技巧:样式、图片与列表
- 样式设置:通过
XWPFRun对象可以设置字体、加粗、斜体、下划线、颜色、字号等。 - 插入图片:使用
XWPFRun的addPicture()方法,需要指定图片路径、类型(如XWPFDocument.PICTURE_TYPE_PNG)和宽度/高度。 - 处理列表:通过
XWPFParagraph的setNumID()方法可以应用 Word 中预设的列表样式。
第二部分:Java PDF 处理实战 (iText & Flying Saucer)
由于 POI 不支持 PDF,我们选择业界标杆 iText(商业版功能强大,AGPL 开源版可用)和专注于 HTML 转 PDF 的 Flying Saucer。

1 准备工作:添加 Maven 依赖
这里我们以 iText 7 为例,它采用模块化设计。
<!-- iText 7 Core -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>7.2.5</version>
<type>pom</type>
</dependency>
<!-- iText 7 PDF HTML (Flying Saucer integration) -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>html2pdf</artifactId>
<version>4.0.3</version>
</dependency>
2 使用 iText 7 从零开始创建 PDF
iText 7 的 API 设计非常现代和直观。
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.element.Cell;
import java.io.FileNotFoundException;
import java.io.IOException;
public class CreatePdfExample {
public static void main(String[] args) {
String dest = "created_example.pdf";
try {
// 1. 创建 PdfWriter 和 PdfDocument
PdfWriter writer = new PdfWriter(dest);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf);
// 2. 添加内容
// 设置中文字体 (非常重要!否则中文会显示为方块)
// 你需要一个中文字体文件,如 'simhei.ttf'
PdfFont font = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H", true);
document.setFont(font);
Paragraph title = new Paragraph("Java PDF 生成示例")
.setTextAlignment(com.itextpdf.layout.property.TextAlignment.CENTER)
.setFontSize(16)
.setBold();
document.add(title);
document.add(new Paragraph("这是一个使用 iText 7 生成的 PDF 文档。"));
document.add(new Paragraph("支持中文、表格、图片等多种元素。"));
// 3. 添加表格
float[] pointColumnWidths = {150F, 150F, 150F};
Table table = new Table(pointColumnWidths);
table.addCell(new Cell().add(new Paragraph("姓名")));
table.addCell(new Cell().add(new Paragraph("年龄")));
table.addCell(new Cell().add(new Paragraph("职业")));
table.addCell(new Cell().add(new Paragraph("张三")));
table.addCell(new Cell().add(new Paragraph("28")));
table.addCell(new Cell().add(new Paragraph("软件工程师")));
document.add(table);
// 4. 关闭文档
document.close();
System.out.println("PDF 文档创建成功!");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
关键点:处理中文等非 ASCII 字符时,必须加载相应的字体文件,否则会乱码。
3 高级技巧:HTML 转 PDF (Flying Saucer)
有时,我们更习惯用 HTML 来设计复杂的文档布局,Flying Saucer (iText 的 html2pdf 模块) 能完美实现这个需求。
步骤:
- 准备一个 HTML 文件(
template.html)。 - 使用
ConverterProperties和HtmlConverter将其转换为 PDF。
HTML 模板 (template.html) 示例:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body { font-family: 'SimSun', '宋体'; }
.header { text-align: center; color: red; }
table { border-collapse: collapse; width: 80%; margin: 20px auto; }
th, td { border: 1px solid black; padding: 8px; text-align: left; }
</style>
</head>
<body>
<h1 class="header">从 HTML 生成的 PDF 报告</h1>
<p>生成时间: ${currentDate}</p>
<table>
<tr>
<th>产品名称</th>
<th>数量</th>
<th>价格</th>
</tr>
<tr>
<td>Java 编程思想</td>
<td>1</td>
<td>¥108.00</td>
</tr>
<tr>
<td>深入理解 Java 虚拟机</td>
<td>1</td>
<td>¥119.00</td>
</tr>
</table>
</body>
</html>
Java 代码转换示例:
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.html2pdf.converter.ConverterProperties;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
public class HtmlToPdfExample {
public static void main(String[] args) {
String htmlPath = "template.html";
String destPdfPath = "from_html.pdf";
try {
// 1. 读取 HTML 文件内容
String htmlContent = new String(Files.readAllBytes(Paths.get(htmlPath)));
// 2. 准备数据 (模拟模板引擎)
Map<String, Object> data = new HashMap<>();
data.put("currentDate", "2025-10-27");
// 这里可以使用更复杂的模板引擎(如 Thymeleaf, FreeMarker)来替换变量
String finalHtml = htmlContent.replace("${currentDate}", data.get("currentDate").toString());
// 3. 设置转换器属性,如字体
ConverterProperties converterProperties = new ConverterProperties();
// 同样,需要处理中文字体
// converterProperties.setFontProvider(...);
// 4. 转换并保存
HtmlConverter.convertToPdf(new FileInputStream(new File(htmlPath)),
new FileOutputStream(destPdfPath),
converterProperties);
System.out.println("HTML 转 PDF 成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
第三部分:实战场景与最佳实践
动态生成并导出 Word 模板报表
需求:根据数据库中的数据,填充一个预先设计好的 Word 模板,并导出。
解决方案:
- 设计模板:在 Word 中创建模板,使用
${变量名}作为占位符(如${name},${amount})。 - 使用库:可以使用
docx4j库,它对 Word 模板变量替换的支持比 POI 更为方便,如果必须用 POI,则需要遍历所有文本框、段落和表格单元格,通过正则表达式或字符串替换来实现,逻辑较为复杂。 - 填充数据:从数据库查询数据,替换模板中的占位符。
- 输出文件:将处理后的
XWPFDocument对象写入输出流。
将多个 Word 合并为一个 PDF
需求:用户上传了多个 Word 文件,需要将它们合并成一个单一的 PDF 文件。
解决方案:
- 读取所有 Word:使用 POI 的
XWPFDocument逐个读取所有.docx文件。 - 创建新 PDF:使用 iText 7 创建一个新的
PdfDocument。 - 逐页转换:(这是一个难点,POI 和 iText 之间没有直接的转换桥梁)
- 方法A (推荐,质量高):先将每个 Word 文档通过 HTML 中间格式 转换,即用 POI 读取 Word 内容,并将其结构化地转换成 HTML 字符串,然后使用 Flying Saucer 将 HTML 字符串渲染到 PDF 的不同页面中。
- 方法B (复杂):分析 POI 的文档对象模型,用 iText 的绘图 API 在 PDF 画布上“模拟”绘制 Word 中的文本、图片和表格,这种方法工作量巨大,不推荐。
- 保存合并后的 PDF:将所有内容写入最终的 PDF 文件。
最佳实践总结
-
选择合适的工具:
- 纯 Word 操作:优先选择
Apache POI。 - 纯 PDF 操作:优先选择
iText。 - HTML 转 PDF:
Flying Saucer(iText html2pdf) 是不二之选。 - Word 模板变量替换:考虑
docx4j,它更专注于此场景。
- 纯 Word 操作:优先选择
-
性能与内存管理:处理大文件时,POI 和 iText 都会占用较多内存,对于超大文件,可以考虑使用
SXSSF(POI 的流式 API) 或研究 iText 的PdfReader和PdfStamper进行流式处理,操作完成后,务必关闭所有资源(使用 try-with-resources 语句)。 -
字体问题:处理中文、日文、韩文等 CJK 字符时,必须加载对应的 TTF 字体文件,并在创建文档时设置好,否则会乱码,确保字体文件的使用符合其许可协议。
-
异常处理:文件操作是 I/O 密集型任务,务必做好
try-catch异常处理,并向用户反馈友好的错误信息。
通过本文的详细讲解,相信你已经对如何使用 Java POI 操作 Word 以及如何结合 iText/Flying Saucer 处理 PDF 有了全面而深入的理解,从基础的读写,到复杂的样式设置、表格处理,再到 HTML 转 PDF 和合并导出等高级场景,你都掌握了应对之道。
技术之路,学无止境,文档处理的世界远不止于此,还有更多高级特性和第三方库等待你去探索,希望这篇文章能成为你解决实际问题的有力工具,让你在 Java 开发的道路上更加得心应手,就去动手实践,用代码创造出属于你的强大文档处理应用吧!
#Java #POI #ApachePOI #Word #PDF #iText #FlyingSaucer #Java开发 #文档处理 #报表生成 #教程
