杰瑞科技汇

Java如何实现Excel转PDF?

使用 Apache POI + iText (最常用、免费、开源)

这是最经典和灵活的组合,适用于绝大多数场景,它完全免费,且对功能有完全的控制权。

Java如何实现Excel转PDF?-图1
(图片来源网络,侵删)
  • Apache POI: 用于读取和操作 Excel 文件。
  • iText: 用于生成 PDF 文件。

核心思想:

  1. 使用 POI 加载 Excel 文件。
  2. 遍历 Excel 的每一个单元格,获取其内容(文本、数字、日期等)。
  3. 使用 iText 在 PDF 文档中创建相应的元素(段落、表格、单元格等),并将 Excel 的内容复制过去。
  4. 保存 PDF 文件。

优点:

  • 完全免费: 无需任何商业许可。
  • 功能强大: 可以对 PDF 的样式、布局进行精细控制。
  • 灵活: 可以只转换特定的 Sheet、Row 或 Cell。

缺点:

  • 代码复杂: 需要手动处理 Excel 到 PDF 的布局映射,代码量相对较大。
  • 样式还原困难: 完美还原 Excel 中的复杂样式(如合并单元格、复杂边框、背景色、字体、旋转等)非常具有挑战性。

实现步骤

添加 Maven 依赖

Java如何实现Excel转PDF?-图2
(图片来源网络,侵删)

在你的 pom.xml 文件中添加以下依赖:

<dependencies>
    <!-- Apache POI for Excel -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>5.2.3</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>5.2.3</version>
    </dependency>
    <!-- iText for PDF -->
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itextpdf</artifactId>
        <version>5.5.13.3</version>
    </dependency>
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itext-asian</artifactId>
        <version>5.2.0</version>
    </dependency>
</dependencies>

Java 代码示例

这个示例将一个简单的 Excel 文件转换为一个包含表格的 PDF 文件。

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import org.apache.poi.ss.usermodel.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class ExcelToPdfWithPOIAndIText {
    public static void main(String[] args) {
        String excelFilePath = "path/to/your/input.xlsx"; // 你的Excel文件路径
        String pdfFilePath = "path/to/your/output.pdf";   // 输出的PDF文件路径
        try {
            convertExcelToPdf(excelFilePath, pdfFilePath);
            System.out.println("转换成功!PDF 文件已保存至: " + pdfFilePath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void convertExcelToPdf(String excelFilePath, String pdfFilePath) throws Exception {
        // 1. 加载 Excel 文件
        FileInputStream excelFile = new FileInputStream(new File(excelFilePath));
        Workbook workbook = WorkbookFactory.create(excelFile);
        // 2. 创建 PDF 文档
        Document document = new Document(PageSize.A4);
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(pdfFilePath));
        document.open();
        // 3. 遍历 Excel 的每一个 Sheet
        for (int sheetNum = 0; sheetNum < workbook.getNumberOfSheets(); sheetNum++) {
            Sheet sheet = workbook.getSheetAt(sheetNum);
            // 如果不是第一页,添加新的一页
            if (sheetNum > 0) {
                document.newPage();
            }
            // 4. 创建 PDF 表格 (列数从第一行获取)
            Row firstRow = sheet.getRow(0);
            int columnCount = (firstRow != null) ? firstRow.getPhysicalNumberOfCells() : 0;
            PdfPTable pdfTable = new PdfPTable(columnCount);
            // 5. 遍历 Sheet 的每一行
            for (Row row : sheet) {
                // 6. 遍历每一行的每一个单元格
                for (Cell cell : row) {
                    PdfPCell pdfCell = new PdfPCell();
                    // 获取单元格内容并处理
                    switch (cell.getCellType()) {
                        case STRING:
                            pdfCell.addElement(new Paragraph(cell.getStringCellValue()));
                            break;
                        case NUMERIC:
                            // 处理日期
                            if (DateUtil.isCellDateFormatted(cell)) {
                                pdfCell.addElement(new Paragraph(cell.getDateCellValue().toString()));
                            } else {
                                pdfCell.addElement(new Paragraph(String.valueOf(cell.getNumericCellValue())));
                            }
                            break;
                        case BOOLEAN:
                            pdfCell.addElement(new Paragraph(String.valueOf(cell.getBooleanCellValue())));
                            break;
                        case FORMULA:
                            // 获取公式的计算结果
                            pdfCell.addElement(new Paragraph(cell.getCellFormula()));
                            break;
                        default:
                            pdfCell.addElement(new Paragraph(""));
                    }
                    // 设置单元格样式(简单示例)
                    pdfCell.setBorder(Rectangle.BOX);
                    pdfCell.setBorderWidth(1);
                    pdfTable.addCell(pdfCell);
                }
            }
            document.add(pdfTable);
        }
        // 7. 关闭文档和 Excel 文件
        document.close();
        workbook.close();
        excelFile.close();
    }
}

使用商业库 (最简单、效果最好、需付费)

如果你追求开发效率完美的样式还原,并且项目预算允许,使用商业库是最佳选择,这些库内部处理了所有复杂的布局和样式转换逻辑。

  • Aspose.Cells: 功能极其强大的 Java Excel 和 PDF 组件,业界口碑很好。
  • Spire.XLS: 另一款非常流行的商业组件,性能和效果同样出色。

核心思想: 只需几行代码,库会自动完成所有工作,包括样式、字体、图片、图表等。

优点:

  • 极其简单: 通常只需 3-5 行代码。
  • 高保真: 能完美还原 Excel 的所有样式和布局。
  • 功能丰富: 支持转换、加密、签名、打印等多种高级功能。

缺点:

  • 收费: 需要购买许可证,免费版本通常有功能或页数限制。

实现步骤 (以 Aspose.Cells 为例)

添加 Maven 依赖

Aspose 提供了官方的 Maven 仓库。

<dependencies>
    <dependency>
        <groupId>com.aspose</groupId>
        <artifactId>aspose-cells</artifactId>
        <version>23.8</version> <!-- 请使用最新版本 -->
    </dependency>
</dependencies>

Java 代码示例

import com.aspose.cells.*;
public class ExcelToPdfWithAspose {
    public static void main(String[] args) throws Exception {
        // 设置 Aspose.Cells 的许可证(如果使用付费版)
        // License license = new License();
        // license.setLicense("Aspose.Cells.Java.lic");
        String excelFilePath = "path/to/your/input.xlsx";
        String pdfFilePath = "path/to/your/output.pdf";
        // 1. 加载 Excel 工作簿
        Workbook workbook = new Workbook(excelFilePath);
        // 2. 创建 PdfSaveOptions 对象
        PdfSaveOptions pdfSaveOptions = new PdfSaveOptions();
        // (可选) 设置 PDF 保存选项,compliance, JPEG quality 等
        // pdfSaveOptions.setCompliance(PdfCompliance.PDF_A_1_A);
        // pdfSaveOptions.setJpegQuality(90);
        // 3. 直接调用 save 方法,指定格式为 PDF
        workbook.save(pdfFilePath, pdfSaveOptions);
        System.out.println("转换成功!PDF 文件已保存至: " + pdfFilePath);
    }
}

可以看到,使用 Aspose 的代码量非常少,而且转换效果是所有方法中最好的。


使用 OpenPDF (iText 的一个分支)

OpenPDF 是 iText 5 的一个分支,在 iText 宣布 AGPL 许可后,为了提供一个更友好的开源许可证而诞生,它的 API 与 iText 5 几乎完全相同。

优点:

  • 免费开源: 拥有更宽松的 Apache 2.0 许可证。
  • API 兼容: 如果你熟悉 iText 5,可以无缝迁移。

缺点:

  • 与 POI + iText 组合的缺点相同:代码复杂,样式还原困难。

实现步骤: 与 方法一 几乎完全相同,只需将 Maven 依赖从 com.itextpdf 换成 com.lowagie

<!-- OpenPDF 替代 iText -->
<dependency>
    <groupId>com.github.librepdf</groupId>
    <artifactId>openpdf</artifactId>
    <version>1.3.30</version>
</dependency>

代码无需修改,因为包名和类名在早期版本中是兼容的。


使用 UNO (基于 LibreOffice/OpenOffice)

这种方法非常特殊,它通过 Java 启动一个 LibreOffice 或 OpenOffice 的进程,然后利用其内置的转换功能来完成。

核心思想:

  1. Java 代码通过 UNO (Universal Network Objects) 协议连接到一个正在运行的 LibreOffice 实例。
  2. 将 Excel 文件加载到 LibreOffice 中。
  3. 调用 LibreOffice 的 API,执行“另存为 PDF”的操作。
  4. 关闭连接。

优点:

  • 转换质量高: 使用 LibreOffice 引擎,样式还原效果不错。
  • 免费: LibreOffice 本身是免费的。

缺点:

  • 依赖外部软件: 必须在服务器上安装并运行 LibreOffice 或 OpenOffice。
  • 性能和稳定性问题: 启动外部进程会增加开销,且需要处理进程的生命周期,在生产环境中可能不稳定。
  • 配置复杂: 需要配置 LibreOffice 的 headless 模式和端口。

适用场景: 通常用于桌面应用程序或一些特定的自动化脚本,不推荐用于高并发的 Web 服务器环境。


总结与如何选择

方法 优点 缺点 推荐场景
POI + iText/OpenPDF 完全免费、灵活、功能强大 代码复杂、样式还原困难、开发周期长 预算有限、对转换质量要求不高、需要精细控制转换过程、有足够开发时间的项目。
商业库 (Aspose/Spire) 极其简单高保真、功能丰富 收费 追求开发效率、对样式还原有严格要求、项目预算充足的企业级应用。
UNO (LibreOffice) 转换质量尚可、免费 依赖外部软件、性能不稳定、配置复杂 桌面应用、自动化脚本,或已有 LibreOffice 环境且无法安装其他库的环境。

给你的建议:

  1. 如果你是个人学习或小型项目,且预算为 0: 选择 方法一 (POI + iText/OpenPDF),虽然代码多,但能让你深入了解转换的原理。
  2. 如果你是商业项目,或对时间、质量有要求: 强烈推荐 方法二 (商业库),它能为你节省大量的开发和调试时间,避免因样式问题带来的客户投诉,通常这些库的投入是非常值得的。
  3. 如果你已经有一个运行中的 LibreOffice 环境: 可以尝试 方法四 (UNO) 作为一种备选方案,但务必先进行充分的性能和稳定性测试。
分享:
扫描分享到社交APP
上一篇
下一篇