Java HTML 转 PDF终极指南:5种主流方案对比与代码实战(2025最新版)
** 在现代Web应用开发中,将HTML内容转换为PDF是一个高频需求,无论是生成报表、合同、发票还是电子书,PDF因其格式固定、易于打印和分享的特性而备受青睐,本文作为2025年最新版Java HTML转PDF终极指南,将深入剖析5种主流实现方案,从纯Java库到云端API,手把手带你从零到一掌握核心技术,并提供可直接运行的代码示例,助你轻松应对项目中的各种转换挑战。

引言:为什么你的项目需要Java HTML转PDF功能?
想象一下以下场景:
- 电商系统: 用户下单后,需要生成一份包含商品详情、价格、订单号的电子发票并发送到邮箱。
- SaaS平台: 用户需要将配置好的个性化报告页面导出为PDF,以便离线查阅或打印。
- 内容管理系统: 编辑发布了一篇图文并茂的文章,需要提供一键下载PDF版本的功能。
这些场景的共同点都是:将动态的、样式丰富的HTML页面,转化为一个静态的、跨平台一致的PDF文档。 使用Java作为后端语言来实现这一功能,是Java Web开发者的必备技能之一。
这个过程并非一帆风顺,如何完美保留HTML的CSS样式(特别是Flexbox、Grid等现代布局)?如何处理中文、特殊符号的字体问题?如何高效地处理大量并发转换请求?这些都是我们需要面对和解决的挑战。
本文将为你逐一拆解,并提供最实用的解决方案。

Flying Saucer (xhtmlrenderer) - Java原生方案的王者
定位: 纯Java实现,无外部依赖,适用于需要高度可控、服务器端渲染的场景。
核心原理: Flying Saucer(基于其核心项目xhtmlrenderer)是一个纯Java实现的HTML/CSS渲染引擎,它的工作原理是:将HTML文件作为输入,在内存中模拟一个浏览器环境,解析HTML和CSS,然后将其“绘制”到一个PDF文档的画布上。
优点:
- 纯Java: 无需安装额外的系统软件(如浏览器或Headless Chrome),部署简单。
- 成熟稳定: 项目历史悠久,被广泛使用,社区支持良好。
- 高度可控: 所有逻辑都在JVM内部,便于集成和调试。
缺点:

- CSS支持有限: 对现代CSS(如CSS3、Flexbox、Grid、部分CSS动画)的支持不完全,可能与浏览器渲染效果有差异。
- 性能瓶颈: 对于复杂页面,渲染速度相对较慢,内存消耗较大。
实战代码示例:
在pom.xml中添加依赖:
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf</artifactId>
<version>9.1.22</version> <!-- 请使用最新版本 -->
</dependency>
核心转换代码:
import org.xhtmlrenderer.pdf.ITextRenderer;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class FlyingSaucerExample {
public static void main(String[] args) {
String htmlContent = "<h1>Hello, Flying Saucer!</h1>" +
"<p>This is a paragraph generated from HTML to PDF.</p>" +
"<table border='1'><tr><th>Header 1</th><th>Header 2</th></tr>" +
"<tr><td>Data 1</td><td>Data 2</td></tr></table>";
try (OutputStream os = new FileOutputStream("output_flying_saucer.pdf")) {
ITextRenderer renderer = new ITextRenderer();
// 如果HTML中引用了外部CSS或图片,需要设置基础路径
// renderer.setDocumentFromString(htmlContent, "file:///path/to/your/resources/");
renderer.setDocumentFromString(htmlContent);
// 渲染并生成PDF
renderer.layout();
renderer.createPDF(os);
System.out.println("PDF generated successfully using Flying Saucer!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用技巧:
- 对于中文,务必在HTML中指定字体,并在代码中加载字体文件,避免乱码。
- 使用
@pageCSS规则来控制PDF的页面大小、边距等。
iText - 老牌PDF库的HTML支持
定位: 强大的PDF操作库,其HTML支持是作为其核心PDF生成功能的补充。
核心原理: iText 7引入了Html2Pdf模块,它内部集成了一个HTML解析器(基于jsoup和cssparser),将HTML解析后,再利用iText强大的PDF布局引擎进行渲染。
优点:
- PDF功能强大: iText本身就是业界顶级的PDF操作库,除了转HTML,还能进行PDF的创建、修改、加密等复杂操作。
- 对iText用户友好: 如果项目已经在使用iText,那么无缝集成HTML转PDF功能非常方便。
缺点:
- HTML/CSS支持同样有局限: 和Flying Saucer类似,它并非一个完整的浏览器内核,对复杂CSS的支持是“尽力而为”。
- 商业许可: iText 7的AGPLv3许可对商业项目可能存在限制,需要购买商业许可才能避免法律风险。
实战代码示例:
添加pom.xml依赖:
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>html2pdf</artifactId>
<version>4.0.3</version> <!-- 请使用最新版本 -->
</dependency>
核心转换代码:
import com.itextpdf.html2pdf.HtmlConverter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class ITextExample {
public static void main(String[] args) {
String htmlContent = "<h1>Hello, iText 7!</h1>" +
"<p>This PDF is created with iText's HTML2PDF module.</p>";
try {
// 直接从字符串转换
HtmlConverter.convertToPdf(htmlContent, new File("output_itext.pdf"));
System.out.println("PDF generated successfully using iText!");
// 也可以从HTML文件转换
// HtmlConverter.convertToPdf(new FileInputStream("source.html"), new File("output_from_file.pdf"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
Apache PDFBox - Apache基金会的全能选手
定位: Apache开源的PDF工具库,功能全面,HTML转PDF是其功能之一。
核心原理: PDFBox的HTML转PDF功能也是通过解析HTML并映射到其内部的PDF对象模型来实现,它提供了一个相对简单的API。
优点:
- 完全开源: 使用Apache License 2.0,商业友好,无任何后顾之忧。
- 功能全面: 除了HTML转PDF,还支持PDF的创建、解析、提取文本、签名等。
- 社区活跃: 作为Apache项目,拥有强大的社区支持。
缺点:
- HTML支持较弱: 相较于前两者,PDFBox对HTML和CSS的支持更为基础,适合结构简单的HTML文档。
- API可能不如iText直观: 对于某些复杂操作,API设计可能略显繁琐。
实战代码示例:
添加pom.xml依赖:
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.27</version> <!-- 请使用最新版本 -->
</dependency>
核心转换代码:
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
public class PDFBoxExample {
public static void main(String[] args) {
String htmlContent = "<h1>Hello, PDFBox!</h1><p>This is a simple example.</p>";
try (PDDocument document = new PDDocument()) {
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);
// 注意:PDFBox本身不提供直接的HTML解析器,
// 通常需要结合Jsoup等库来解析HTML,然后手动绘制到PDF上。
// 这是一个简化版的思路,实际项目会更复杂。
Document doc = Jsoup.parse(htmlContent);
PDPageContentStream contentStream = new PDPageContentStream(document, page);
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 12);
contentStream.beginText();
contentStream.newLineAtOffset(50, 750);
Element h1 = doc.selectFirst("h1");
if (h1 != null) {
contentStream.showText(h1.text());
}
contentStream.newLineAtOffset(0, -20);
Element p = doc.selectFirst("p");
if (p != null) {
contentStream.setFont(PDType1Font.HELVETICA, 12);
contentStream.showText(p.text());
}
contentStream.endText();
contentStream.close();
document.save("output_pdfbox.pdf");
System.out.println("PDF generated successfully using PDFBox!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
重要提示: 上面的PDFBox示例仅作概念演示,实际HTML到PDF的转换逻辑非常复杂,对于生产环境,如果选择PDFBox,通常需要自己构建一个相对完善的HTML解析和布局引擎,或者寻找其社区中更高级的封装库。
Headless Chrome + Selenium - 效果最逼真的“浏览器方案”
定位: 追求100%还原页面显示效果,对复杂CSS和JavaScript有要求的场景。
核心原理: 这不是纯Java方案,而是“Java调用外部工具”的方案,我们通过Java代码(使用Selenium库)控制一个无头(Headless)的Chrome浏览器,让它加载指定的HTML URL或HTML字符串,然后将其当前渲染的页面截图或直接打印为PDF。
优点:
- 效果完美: 因为是真实的浏览器内核,所以能完美支持所有现代CSS、JavaScript、Canvas、SVG等,生成的PDF与用户在浏览器中看到的一模一样。
- 功能强大: 可以处理任何动态加载的内容,非常灵活。
缺点:
- 依赖外部环境: 必须在服务器上安装Chrome浏览器及其驱动(如
chromedriver),增加了部署的复杂度。 - 资源消耗大: 每个转换实例都会启动一个浏览器进程,对服务器CPU和内存要求较高,不适合高并发场景。
- 性能最慢: 启动浏览器、加载页面、渲染的过程耗时较长。
实战代码示例:
-
准备工作:
- 服务器上安装Chrome浏览器。
- 下载与Chrome版本匹配的
chromedriver,并将其所在目录加入系统PATH。
-
添加
pom.xml依赖:<dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>4.9.1</version> <!-- 请使用最新版本 --> </dependency> -
核心转换代码:
import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; import java.io.File; import java.io.IOException; public class HeadlessChromeExample { public static void main(String[] args) { // 设置ChromeDriver路径 (如果未在PATH中) // System.setProperty("webdriver.chrome.driver", "/path/to/your/chromedriver"); ChromeOptions options = new ChromeOptions(); options.addArguments("--headless"); // 无头模式 options.addArguments("--disable-gpu"); options.addArguments("--no-sandbox"); WebDriver driver = null; try { driver = new ChromeDriver(options); // 1. 从URL转换 driver.get("https://www.example.com"); // driver.quit(); // 注意:打印PDF后不能立即quit,否则PDF可能为空 ((ChromeDriver) driver).getDevTools().createSession().getPrintPdf().print(new File("output_from_url.pdf")); System.out.println("PDF generated from URL using Headless Chrome!"); // 2. 从HTML字符串转换 (需要将HTML保存为临时文件或提供data URL) String htmlContent = "<html><head><title>Test</title></head><body><h1>HTML from String</h1></body></html>"; // 一个简单的方法是将其写入一个临时文件,然后通过file://协议加载 File tempHtml = File.createTempFile("temp", ".html"); java.nio.file.Files.write(tempHtml.toPath(), htmlContent.getBytes()); driver.get("file://" + tempHtml.getAbsolutePath()); ((ChromeDriver) driver).getDevTools().createSession().getPrintPdf().print(new File("output_from_string.pdf")); System.out.println("PDF generated from HTML String using Headless Chrome!"); } catch (IOException e) { e.printStackTrace(); } finally { if (driver != null) { driver.quit(); } } } }
云端API服务 - 开发者最省心的选择
定位: 追求极致开发效率、高可用性和弹性扩展的企业级应用。
核心原理: 将转换工作外包给专业的第三方服务,你的Java应用只需通过HTTP请求(REST API)将HTML内容发送给云端服务,服务处理完成后,将生成的PDF文件URL或二进制数据返回给你。
优点:
- 高可用与高并发: 云服务通常有分布式架构,能轻松应对高并发请求,且SLA(服务等级协议)有保障。
- 免运维: 无需关心服务器、浏览器驱动等任何底层环境,专注于业务逻辑。
- 效果优异: 专业的云服务通常使用最新的浏览器引擎,渲染效果有保障。
- 功能丰富: 除了转PDF,还可能提供加水印、添加页眉页脚、设置权限等增值服务。
缺点:
- 成本: 对于高流量的应用,API调用会产生持续的费用。
- 数据隐私: HTML数据需要传输到第三方服务器,可能涉及数据隐私和合规性问题。
- 依赖网络: 服务质量受网络状况影响。
知名服务商:
- Adobe PDF Services API: 行业标杆,功能强大,但价格较高。
- Apitrary, DocRaptor, PDFShift: 专注于HTML转PDF,提供灵活的定价方案。
Java调用API的伪代码示例:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class CloudApiExample {
public static void main(String[] args) {
String apiKey = "YOUR_API_KEY";
String htmlContent = "<h1>Hello from Cloud API!</h1>";
String apiUrl = "https://api.pdfshift.io/v2/convert"; // 以PDFshift为例
try {
URL url = new URL(apiUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Authorization", "Basic " + java.util.Base64.getEncoder().encodeToString(apiKey.getBytes()));
conn.setDoOutput(true);
String jsonInputString = "{\"source\": \"" + htmlContent.replace("\"", "\\\"") + "\", \"format\": \"pdf\"}";
try (OutputStream os = conn.getOutputStream()) {
byte[] input = jsonInputString.getBytes("utf-8");
os.write(input, 0, input.length);
}
if (conn.getResponseCode() == 200) {
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
response.append(line);
}
br.close();
// 解析响应,获取PDF的URL或下载PDF
System.out.println("Conversion successful! Response: " + response.toString());
} else {
System.out.println("Error: " + conn.getResponseCode());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
方案对比与选型建议
| 特性 | Flying Saucer | iText | PDFBox | Headless Chrome | 云端API |
|---|---|---|---|---|---|
| CSS支持 | 一般 | 较好 | 较弱 | 完美 | 完美 |
| JS支持 | 无 | 无 | 无 | 完美 | 完美 |
| 部署复杂度 | 极低 | 低 | 低 | 高 | 极低 |
| 性能 | 中等 | 中等 | 中等 | 慢 | 快(服务端) |
| 并发能力 | 中等 | 中等 | 中等 | 差 | 强 |
| 功能扩展性 | 一般 | 强 | 强 | 强 | 非常强 |
| 成本 | 免费 | 开源版免费,商业需授权 | 免费 | 需服务器/运维成本 | 按需付费 |
| 适用场景 | 简单报告、无复杂样式的文档 | 已使用iText的项目、对PDF操作要求高的场景 | 简单PDF生成、需要Apache生态支持 | 对视觉效果要求极高的场景、有动态内容 | 企业级应用、追求效率、高并发 |
如何选择?问自己三个问题:
-
我的HTML页面有多复杂?
- 简单(表格、基本样式): 首选 Flying Saucer 或 PDFBox。
- 复杂(Flexbox、Grid、JS渲染): 必须选择 Headless Chrome 或 云端API。
-
我的服务器环境和性能要求如何?
- 资源有限、追求简单部署: 选 Flying Saucer。
- 有资源、能处理复杂环境、追求最佳效果: 选 Headless Chrome。
- 追求高可用、高并发、不想运维: 选 云端API。
-
我的项目预算有多少?
- 零预算: 在 Flying Saucer 和 Headless Chrome 之间做权衡。
- 有预算,且追求效率和稳定性: 云端API 是最省心的选择。
最佳实践与常见陷阱
-
字体问题(中文乱码):
- 问题: 服务器上没有安装HTML中使用的字体。
- 解决:
- 方案一(推荐): 在HTML中使用Web安全字体(如
Arial, sans-serif)或通过@font-face嵌入字体文件(Base64编码或外部链接)。 - 对于Java库,手动加载TTF字体文件,在Flying Saucer中:
renderer.getFontResolver().addFont("path/to/your/simhei.ttf", "UTF-8", true);
- 方案一(推荐): 在HTML中使用Web安全字体(如
-
资源路径问题(图片、CSS不显示):
- 问题: Java库无法找到HTML中引用的本地图片或CSS文件。
- 解决: 设置基础URL(Base URL),告诉渲染器,所有相对路径都相对于哪个目录。
// Flying Saucer 示例 renderer.setDocumentFromString(htmlContent, "file:///C:/projects/myapp/src/main/resources/static/");
-
分页与长文本处理:
- 问题: 超长的HTML内容被渲染到一页PDF上,导致内容被截断或排版混乱。
- 解决:
- 使用
page-break-after,page-break-before,page-break-inside等CSS属性来控制分页逻辑。 - 在Java代码中,可以监听分页事件,在合适的位置插入新的PDPage对象(对于iText等库)。
- 使用
-
性能优化:
- 缓存: 对于不常变化的HTML,缓存生成的PDF文件,避免重复转换。
- 异步处理: 对于耗时的转换任务(尤其是Headless Chrome),使用消息队列(如RabbitMQ, Kafka)进行异步处理,避免阻塞用户请求。
- 连接池: 如果使用Headless Chrome,考虑使用Selenium Grid或浏览器管理工具(如Browserless.io)来管理浏览器实例,提高资源利用率。
Java HTML转PDF是一个看似简单实则蕴含诸多技术细节的课题,本文为你梳理了从经典到前沿的5种主流方案,并提供了详细的对比和选型指南。
- 对于追求简单、快速、无依赖的中小型项目,Flying Saucer 是一个可靠的起点。
- 如果你的项目已经深度使用iText,那么其内置的HTML转PDF功能值得考虑。
- 当你遇到复杂CSS和JS,对视觉效果有“像素级”要求时,Headless Chrome 是不二之选,尽管它会带来一些运维成本。
- 对于追求极致效率、高可用性和弹性扩展的企业级应用,将转换任务交给云端API服务,是让你从繁杂的运维工作中解放出来的最佳策略。
希望这篇详尽的指南能帮助你做出最适合自己项目的技术选型,并成功攻克Java HTML转PDF的挑战,选择最适合你的方案,开始你的高效开发之旅吧!
