杰瑞科技汇

Java如何将HTML转为PDF?

核心原理

Java 本身并不能直接理解 HTML 并将其渲染成 PDF,我们需要借助第三方库,这些库的核心思想通常是:

Java如何将HTML转为PDF?-图1
(图片来源网络,侵删)
  1. 嵌入一个浏览器内核:最强大的方法,它们会集成一个真正的浏览器内核(如 Google Chrome 的 Blink 或 Firefox 的 Gecko),它们通过启动一个无头(Headless)浏览器实例,加载你的 HTML 文件,然后像浏览器一样渲染出页面,最后将渲染好的页面截图或直接打印成 PDF。
  2. 使用 HTML/CSS 渲染引擎:这种方法不依赖外部浏览器,而是自己实现一个 HTML/CSS 解析和渲染引擎,它们速度更快,资源消耗更少,但可能在处理现代 CSS(如 Flexbox, Grid、某些动画和字体)方面存在兼容性问题。

使用 Flying Saucer (xhtmlrenderer) - 纯 Java 解决方案

Flying Saucer 是一个开源的、纯 Java 实现的 XHTML/CSS 渲染器,它非常适合将静态的、样式简单的 HTML 转换为 PDF。

优点

  • 纯 Java:无需安装任何外部依赖(如浏览器),部署简单。
  • 轻量级:启动速度快,资源占用少。
  • 开源免费:基于 Apache 2.0 许可证。

缺点

  • CSS 支持有限:对现代 CSS3 的支持不完整,特别是复杂的布局(Flexbox, Grid)、部分 CSS3 选择器和伪类可能无法正确渲染。
  • JavaScript 支持:不支持 JavaScript。
  • 性能:对于非常复杂的 HTML 文档,性能可能不如基于浏览器的方案。

实现步骤

  1. 添加依赖 (Maven)

    <dependency>
        <groupId>org.xhtmlrenderer</groupId>
        <artifactId>flying-saucer-pdf</artifactId>
        <version>9.1.22</version> <!-- 请使用最新版本 -->
    </dependency>
  2. Java 代码示例

    import org.xhtmlrenderer.pdf.ITextRenderer;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.OutputStream;
    public class FlyingSaucerExample {
        public static void main(String[] args) {
            // 1. 准备 HTML 内容
            // 注意:Flying Saucer 期望的是 XHTML 格式,所以标签最好闭合
            String htmlContent = "<h1>Hello, Flying Saucer!</h1>" +
                                 "<p>This is a PDF generated from HTML using Flying Saucer.</p>" +
                                 "<table border='1'>" +
                                 "<tr><th>Name</th><th>Age</th></tr>" +
                                 "<tr><td>John Doe</td><td>30</td></tr>" +
                                 "</table>";
            // 2. 创建 ITextRenderer 实例
            ITextRenderer renderer = new ITextRenderer();
            // 3. 设置 HTML 内容
            renderer.setDocumentFromString(htmlContent);
            // 4. (可选)设置基础 URL,用于解析相对路径的 CSS 和图片
            renderer.getSharedContext().setBaseURL("file:/C:/path/to/your/resources/");
            // 5. 渲染 PDF
            try (OutputStream os = new FileOutputStream("output_flying_saucer.pdf")) {
                renderer.layout();
                renderer.createPDF(os);
                System.out.println("PDF generated successfully!");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

使用 iText - 功能强大的商业/开源方案

iText 是一个非常著名的 PDF 操作库,它有一个名为 iText HTMLWorker 的组件可以解析 HTML,但官方已不推荐使用,因为它对 CSS 的支持非常糟糕。

Java如何将HTML转为PDF?-图2
(图片来源网络,侵删)

取而代之的是 iText 7 的 html2pdf 模块,它基于 Flying Saucer,所以优缺点和 Flying Saucer 类似,但提供了更现代化的 API 和商业支持。

优点

  • 功能强大:除了 HTML 转 PDF,iText 本身在 PDF 创建、修改、加密等方面是业界标杆。
  • 商业支持:提供商业版本,可获得官方技术支持。

缺点

  • 开源版限制:iText 7 的 AGPL 开源许可证有商业限制,如果你的项目是商业闭源的,需要购买商业许可证。
  • CSS 支持同样有限:和 Flying Saucer 一样,对现代 CSS 的支持不是其强项。

实现步骤 (基于 iText 7)

  1. 添加依赖 (Maven)

    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>html2pdf</artifactId>
        <version>5.0.5</version> <!-- 请使用最新版本 -->
    </dependency>
  2. Java 代码示例

    import com.itextpdf.html2pdf.HtmlConverter;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.OutputStream;
    public class ITextHtml2PdfExample {
        public static void main(String[] args) {
            String htmlContent = "<h1>Hello, iText 7 html2pdf!</h1>" +
                                 "<p>This PDF was created with the iText 7 html2pdf add-on.</p>";
            try (OutputStream os = new FileOutputStream("output_itext_html2pdf.pdf")) {
                // 直接调用 HtmlConverter 的静态方法进行转换
                HtmlConverter.convertToPdf(htmlContent, os);
                System.out.println("PDF generated successfully with iText 7!");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    注意:这个例子和 Flying Saucer 的核心代码非常相似,因为 html2pdf 模块内部就封装了 Flying Saucer。

    Java如何将HTML转为PDF?-图3
    (图片来源网络,侵删)

使用 Selenium / Playwright - 功能最强大的方案

这种方法通过驱动一个真实的无头浏览器来渲染页面,因此能完美支持现代 HTML5、CSS3 和 JavaScript。

优点

  • 完美的兼容性:可以渲染任何现代网页,包括复杂的 CSS 布局、JavaScript 动态内容、SVG、Canvas 等。
  • 真实环境:模拟真实用户操作,适合生成需要交互或复杂 JS 计算后的页面截图/PDF。

缺点

  • 依赖外部环境:需要预先安装 Chrome、Firefox 或 Edge 浏览器。
  • 资源消耗大:启动浏览器进程需要较多内存和 CPU。
  • 速度慢:相比纯 Java 方案,启动和渲染过程要慢得多。

实现步骤 (以 Selenium + Chrome 为例)

  1. 安装 Chrome 浏览器 确保你的服务器或开发环境上已经安装了 Google Chrome。

  2. 添加依赖 (Maven)

    <!-- Selenium WebDriver for Chrome -->
    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-chrome-driver</artifactId>
        <version>4.10.0</version> <!-- 请使用与你的 Chrome 版本匹配的版本 -->
    </dependency>
    <!-- 一个更轻量的库,也可以选择 -->
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>31.1-jre</version>
    </dependency>
  3. Java 代码示例

    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.chrome.ChromeOptions;
    import org.openqa.selenium.OutputType;
    import org.openqa.selenium.Pdf; // 需要较新版本的 Selenium
    import java.io.File;
    import java.io.IOException;
    import org.apache.commons.io.FileUtils;
    public class SeleniumPdfExample {
        public static void main(String[] args) {
            // 1. 设置 ChromeDriver 路径
            // 如果你把 chromedriver.exe 放在系统 PATH 中,可以省略这步
            // System.setProperty("webdriver.chrome.driver", "path/to/your/chromedriver.exe");
            // 2. 配置 Chrome 选项为无头模式
            ChromeOptions options = new ChromeOptions();
            options.addArguments("--headless");
            options.addArguments("--no-sandbox");
            options.addArguments("--disable-dev-shm-usage");
            // 指定打印的背景颜色
            options.addArguments("--print-to-pdf-no-header");
            options.addArguments("--hide-scrollbars");
            // 3. 创建 WebDriver 实例
            WebDriver driver = null;
            try {
                driver = new ChromeDriver(options);
                // 4. 加载 HTML 文件
                // 你可以是一个本地文件,也可以是一个 URL
                // File htmlFile = new File("path/to/your/report.html");
                // driver.get("file:///" + htmlFile.getAbsolutePath());
                driver.get("https://www.google.com");
                // 5. 使用 Chrome 的打印 API 生成 PDF
                // 这是 Selenium 4+ 的新特性,比截图更精确
                Pdf pdf = driver.print(OutputType.FILE);
                File pdfFile = pdf.getAsFile();
                FileUtils.copyFile(pdfFile, new File("output_selenium.pdf"));
                System.out.println("PDF generated successfully with Selenium!");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 6. 关闭浏览器
                if (driver != null) {
                    driver.quit();
                }
            }
        }
    }

    注意:Selenium 4 开始原生支持 print 到 PDF,这是最佳方式,如果使用旧版本,你需要通过 driver.getScreenshotAs() 截图,但这无法生成完整的页面长 PDF,只能截取视口部分。


使用商业 API 服务 (如 PrinceXML, SelectPDF)

对于有高要求、高预算的企业,可以考虑商业 API 服务。

PrinceXML

  • 优点:业界公认的对 CSS 支持最好的渲染引擎,能将几乎所有符合标准的 XHTML 和 CSS 转换成精美的 PDF,质量极高。
  • 缺点:价格昂贵,是商业产品。

SelectPDF

  • 优点:提供 .NET 和 Java 库,对 CSS3 和 HTML5 有很好的支持,性价比比 PrinceXML 高。
  • 缺点:需要付费购买许可证,有免费版本但有页面数限制。

总结与选择建议

方法 核心原理 优点 缺点 适用场景
Flying Saucer / iText html2pdf 纯 Java 渲染引擎 轻量、快速、无外部依赖 CSS 支持有限,无 JS 支持 简单的、静态的报告、发票、标签等
Selenium / Playwright 驱动无头浏览器 完美支持现代 CSS/JS,功能最全 依赖浏览器、资源消耗大、速度慢 复杂的网页、需要执行 JS 的页面、高保真网页截图/PDF
商业 API (PrinceXML, SelectPDF) 专业商业引擎 CSS 支持顶尖,质量高 价格昂贵 对 PDF 质量、样式保真度有极高要求的企业级应用

如何选择?

  1. 如果只是简单的 HTML 转 PDF,样式不复杂:首选 Flying SauceriText 7 html2pdf,它们简单、快速、免费,足以满足大多数内部报表的需求。
  2. 如果需要生成高保真的网页,包含复杂布局、字体、甚至 JavaScript 动态内容:必须选择 SeleniumPlaywright,虽然慢一些,但效果是最好的。
  3. 如果项目预算充足,且 PDF 的视觉质量是第一要求:可以考虑 PrinceXML 等商业解决方案。

对于大多数 Java Flying SaucerSelenium 是最常用和最需要了解的两种方案。

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