杰瑞科技汇

Java POI如何同时操作Word与PDF?

Java POI 操作 Word 与 PDF 完全指南:从入门到精通,解决文档处理痛点

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

Java POI如何同时操作Word与PDF?-图1
(图片来源网络,侵删)

引言:为什么 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 WordJava PDF 两大核心,为你提供一条清晰的学习和实践路径,解决你在实际开发中遇到的各种难题。


第一部分:深入 Java POI Word 操作 (Apache POI)

Apache POI 对于 Word 的处理主要分为两类:针对旧版 .doc 格式的 HWPF,以及针对新版 .docx 格式的 XWPF。强烈建议使用 XWPF,因为 .docx 是目前的主流格式,且 HWPF 的功能相对有限。

Java POI如何同时操作Word与PDF?-图2
(图片来源网络,侵删)

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 对象可以设置字体、加粗、斜体、下划线、颜色、字号等。
  • 插入图片:使用 XWPFRunaddPicture() 方法,需要指定图片路径、类型(如 XWPFDocument.PICTURE_TYPE_PNG)和宽度/高度。
  • 处理列表:通过 XWPFParagraphsetNumID() 方法可以应用 Word 中预设的列表样式。

第二部分:Java PDF 处理实战 (iText & Flying Saucer)

由于 POI 不支持 PDF,我们选择业界标杆 iText(商业版功能强大,AGPL 开源版可用)和专注于 HTML 转 PDF 的 Flying Saucer

Java POI如何同时操作Word与PDF?-图3
(图片来源网络,侵删)

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 模块) 能完美实现这个需求。

步骤

  1. 准备一个 HTML 文件(template.html)。
  2. 使用 ConverterPropertiesHtmlConverter 将其转换为 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 模板,并导出。

解决方案

  1. 设计模板:在 Word 中创建模板,使用 ${变量名} 作为占位符(如 ${name}, ${amount})。
  2. 使用库:可以使用 docx4j 库,它对 Word 模板变量替换的支持比 POI 更为方便,如果必须用 POI,则需要遍历所有文本框、段落和表格单元格,通过正则表达式或字符串替换来实现,逻辑较为复杂。
  3. 填充数据:从数据库查询数据,替换模板中的占位符。
  4. 输出文件:将处理后的 XWPFDocument 对象写入输出流。

将多个 Word 合并为一个 PDF

需求:用户上传了多个 Word 文件,需要将它们合并成一个单一的 PDF 文件。

解决方案

  1. 读取所有 Word:使用 POI 的 XWPFDocument 逐个读取所有 .docx 文件。
  2. 创建新 PDF:使用 iText 7 创建一个新的 PdfDocument
  3. 逐页转换(这是一个难点,POI 和 iText 之间没有直接的转换桥梁)
    • 方法A (推荐,质量高):先将每个 Word 文档通过 HTML 中间格式 转换,即用 POI 读取 Word 内容,并将其结构化地转换成 HTML 字符串,然后使用 Flying Saucer 将 HTML 字符串渲染到 PDF 的不同页面中。
    • 方法B (复杂):分析 POI 的文档对象模型,用 iText 的绘图 API 在 PDF 画布上“模拟”绘制 Word 中的文本、图片和表格,这种方法工作量巨大,不推荐。
  4. 保存合并后的 PDF:将所有内容写入最终的 PDF 文件。

最佳实践总结

  1. 选择合适的工具

    • 纯 Word 操作:优先选择 Apache POI
    • 纯 PDF 操作:优先选择 iText
    • HTML 转 PDFFlying Saucer (iText html2pdf) 是不二之选。
    • Word 模板变量替换:考虑 docx4j,它更专注于此场景。
  2. 性能与内存管理:处理大文件时,POI 和 iText 都会占用较多内存,对于超大文件,可以考虑使用 SXSSF (POI 的流式 API) 或研究 iText 的 PdfReaderPdfStamper 进行流式处理,操作完成后,务必关闭所有资源(使用 try-with-resources 语句)。

  3. 字体问题:处理中文、日文、韩文等 CJK 字符时,必须加载对应的 TTF 字体文件,并在创建文档时设置好,否则会乱码,确保字体文件的使用符合其许可协议。

  4. 异常处理:文件操作是 I/O 密集型任务,务必做好 try-catch 异常处理,并向用户反馈友好的错误信息。


通过本文的详细讲解,相信你已经对如何使用 Java POI 操作 Word 以及如何结合 iText/Flying Saucer 处理 PDF 有了全面而深入的理解,从基础的读写,到复杂的样式设置、表格处理,再到 HTML 转 PDF 和合并导出等高级场景,你都掌握了应对之道。

技术之路,学无止境,文档处理的世界远不止于此,还有更多高级特性和第三方库等待你去探索,希望这篇文章能成为你解决实际问题的有力工具,让你在 Java 开发的道路上更加得心应手,就去动手实践,用代码创造出属于你的强大文档处理应用吧!


#Java #POI #ApachePOI #Word #PDF #iText #FlyingSaucer #Java开发 #文档处理 #报表生成 #教程

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