下面我将为您详细介绍几种主流的实现方法,从最简单到最功能强大的,并提供详细的代码示例和优缺点分析。

核心思路
无论使用哪个库,其基本工作流程都相似:
- 准备 HTML 内容:可以是一个 HTML 字符串,也可以是一个指向本地或远程 HTML 文件的 URL。
- 配置转换选项:设置页面大小、边距、页眉页脚、字体、图片处理等。
- 执行转换:调用库的 API,将 HTML 输入流转换为 PDF 输出流。
- 处理输出:将生成的 PDF 输出到文件、字节数组或响应流中。
使用 Flying Saucer (xhtmlrenderer) - 纯 Java 方案
这是最经典、最知名的纯 Java HTML 到 PDF 转换库,它不依赖任何浏览器或本地环境,可以在任何支持 Java 的平台上运行。
添加 Maven 依赖
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf</artifactId>
<version>9.1.22</version> <!-- 请使用最新版本 -->
</dependency>
核心代码示例
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 内容
String htmlContent = """
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body { font-family: Arial, sans-serif; }
h1 { color: #333; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<h1>我的第一个 PDF 报告</h1>
<p>这是使用 Flying Saucer 生成的 PDF 文件。</p>
<table>
<tr>
<th>产品</th>
<th>价格</th>
</tr>
<tr>
<td>Java 编程</td>
<td>¥99.00</td>
</tr>
<tr>
<td>Spring Boot 实战</td>
<td>¥129.00</td>
</tr>
</table>
</body>
</html>
""";
// 2. 创建输出文件
File outputFile = new File("output_flying_saucer.pdf");
try (OutputStream os = new FileOutputStream(outputFile)) {
// 3. 创建 ITextRenderer 实例
ITextRenderer renderer = new ITextRenderer();
// 4. 设置 HTML 内容
renderer.setDocumentFromString(htmlContent);
// 5. (可选)处理相对路径的 CSS 和图片
// renderer.setDocumentBaseURL("file:/path/to/your/resources/");
// 6. 执行渲染
renderer.layout();
// 7. 生成 PDF
renderer.createPDF(os);
System.out.println("PDF 文件生成成功: " + outputFile.getAbsolutePath());
} catch (Exception e) {
e.printStackTrace();
}
}
}
优缺点分析
-
优点:
- 纯 Java: 无需安装浏览器,跨平台性好。
- 开源免费: 遵循 Mozilla Public License。
- 成熟稳定: 使用广泛,社区支持好。
- 支持 CSS: 对 CSS 2.1 有很好的支持,支持大部分常用样式。
-
缺点:
(图片来源网络,侵删)- CSS 支持有限: 不支持所有现代 CSS 特性(如 Flexbox, Grid, 部分 CSS3 动画)。
- JavaScript 不支持: 无法执行页面中的 JavaScript 代码。
- 性能: 对于非常复杂的 HTML,性能可能不如基于浏览器的方案。
- 中文支持需要额外配置: 默认可能不支持中文字体,需要手动配置。
使用 iText 5 / iText 7 - 商业库
iText 是一个非常强大的 PDF 操作库,它也提供了 HTML 转换的功能,iText 5 是较老的版本,iText 7 是更新的版本,架构更现代化。
添加 Maven 依赖 (iText 7)
iText 7 采用模块化设计,需要引入 html2pdf 模块。
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>html2pdf</artifactId>
<version>4.0.3</version> <!-- 请使用最新版本 -->
</dependency>
注意: iText 7 有 AGPL 许可证,如果你的项目是商业闭源项目,你需要购买商业许可证,AGPL 允许免费用于开源项目。
核心代码示例 (iText 7)
import com.itextpdf.html2pdf.HtmlConverter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class IText7Example {
public static void main(String[] args) {
// 1. 准备 HTML 内容 (与上面相同)
String htmlContent = """
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body { font-family: Arial, sans-serif; }
h1 { color: #333; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<h1>使用 iText 7 生成的 PDF</h1>
<p>这是使用 iText 7 的 html2pdf 模块生成的 PDF 文件。</p>
<table>
<tr><th>产品</th><th>价格</th></tr>
<tr><td>Java 编程</td><td>¥99.00</td></tr>
<tr><td>Spring Boot 实战</td><td>¥129.00</td></tr>
</table>
</body>
</html>
""";
// 2. 创建输出文件
File outputFile = new File("output_itext7.pdf");
try (OutputStream os = new FileOutputStream(outputFile)) {
// 3. 直接调用 HtmlConverter 进行转换
HtmlConverter.convertToPdf(htmlContent, os);
System.out.println("PDF 文件生成成功: " + outputFile.getAbsolutePath());
} catch (Exception e) {
e.printStackTrace();
}
}
}
优缺点分析
-
优点:
(图片来源网络,侵删)- 功能强大: iText 本身就是业界顶级的 PDF 库,转换后可以轻松对 PDF 进行复杂操作(加密、签名、表单等)。
- CSS 支持较好: 基于 Flying Saucer,但进行了优化和增强。
- 文档和 API 完善: 官方文档非常详细。
-
缺点:
- 许可证问题: AGPL 许可证对商业项目不友好,需要付费。
- 性能: 对于复杂页面,性能可能不是最优。
使用 wkhtmltopdf - 基于浏览器的方案
wkhtmltopdx 是一个开源命令行工具,它使用 WebKit 渲染引擎(也就是 Chrome 和 Safari 使用的核心)来将 HTML 转换成 PDF,Java 通过调用其命令行接口来使用它。
下载并安装
你需要从 wkhtmltopdf 官网 下载并安装对应你操作系统的版本,确保 wkhtmltopdf.exe (Windows) 或 wkhtmltopdf (Linux/Mac) 的路径在系统的环境变量 PATH 中,或者在 Java 代码中指定其完整路径。
添加 Java 封装库 (可选)
直接使用 Runtime.exec() 调用命令行比较繁琐,可以使用一些封装库来简化操作,com.github.jhonnymertz:java-wkhtmltopdf。
<dependency>
<groupId>com.github.jhonnymertz</groupId>
<artifactId>java-wkhtmltopdf</artifactId>
<version>1.1.0</version>
</dependency>
核心代码示例
import com.github.jhonnymertz.wkhtmltopdf.WkhtmltopdfExecutor;
import com.github.jhonnymertz.wkhtmltopdf.output.OutputType;
import com.github.jhonnymertz.wkhtmltopdf.parameter.Param;
import com.github.jhonnymertz.wkhtmltopdf.resource.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class WkhtmltopdfExample {
public static void main(String[] args) {
// 1. 准备 HTML 内容
String htmlContent = """
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body { font-family: Arial, sans-serif; }
h1 { color: #333; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<h1>使用 wkhtmltopdf 生成的 PDF</h1>
<p>这是使用 wkhtmltopdf 生成的 PDF 文件,它能完美支持现代 CSS。</p>
<table>
<tr><th>产品</th><th>价格</th></tr>
<tr><td>Vue.js 实战</td><td>¥89.00</td></tr>
<tr><td>React 完全指南</td><td>¥109.00</td></tr>
</table>
</body>
</html>
""";
// 2. 创建临时 HTML 文件
File htmlFile = new File("temp.html");
try (OutputStream os = new FileOutputStream(htmlFile)) {
os.write(htmlContent.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
// 3. 创建输出 PDF 文件
File outputFile = new File("output_wkhtmltopdf.pdf");
// 4. 创建 WkhtmltopdfExecutor
WkhtmltopdfExecutor executor = new WkhtmltopdfExecutor();
// 5. 配置转换参数
executor.addParam(Param.DISABLE_SMART_SHRINKING); // 禁用智能缩放
executor.addParam(Param.NOBACKGROUND); // 不渲染背景
executor.addParam(new Param("--orientation", "Landscape")); // 设置为横向
// 6. 添加输入资源 (HTML文件)
executor.addResource(new Resource(htmlFile));
// 7. 设置输出文件
executor.setOutputFile(outputFile);
executor.setOutputType(OutputType.FILE);
// 8. 执行转换
try {
executor.execute();
System.out.println("PDF 文件生成成功: " + outputFile.getAbsolutePath());
} catch (Exception e) {
e.printStackTrace();
} finally {
// 9. 清理临时文件
htmlFile.delete();
}
}
}
优缺点分析
-
优点:
- 极高的 CSS/JS 兼容性: 因为使用的是真实的浏览器内核,所以几乎支持所有现代 CSS 和 JavaScript 功能。
- 渲染效果逼真: 生成的 PDF 外观与在浏览器中看到的一模一样。
- 开源免费: 软件本身是开源的。
-
缺点:
- 依赖本地环境: 必须在目标服务器上安装
wkhtmltopdf,增加了部署的复杂性和服务器依赖。 - 性能问题: 启动一个进程来转换每个请求,会消耗较多 CPU 和内存,不适合高并发场景。
- 稳定性: 在某些服务器环境下(如无头模式、权限问题)可能会遇到问题。
- 依赖本地环境: 必须在目标服务器上安装
如何选择?
| 特性 | Flying Saucer (纯Java) | iText 7 (商业库) | wkhtmltopdf (基于浏览器) |
|---|---|---|---|
| CSS 支持 | 一般 (CSS 2.1) | 较好 | 极佳 (现代 CSS) |
| JavaScript 支持 | 无 | 无 | 支持 |
| 依赖性 | 无 | 无 (但许可证有商业限制) | 需要安装本地工具 |
| 性能 | 中等 | 中等 | 较差 (启动进程开销大) |
| 易用性 | 简单 | 简单 | 中等 (需要配置环境) |
| 成本 | 开源免费 | 商业项目需付费 | 开源免费 |
| 适用场景 | 简单报表、静态文档、无复杂样式 | 需要深度 PDF 操作(加密/签名) | 需要高度还原网页样式的场景 |
总结建议:
- 如果需求简单,对 CSS 要求不高,且希望部署简单:首选 Flying Saucer,它是纯 Java 解决方案,部署零烦恼。
- 如果你的项目是开源的,或者愿意为 PDF 功能付费,并且需要后续对 PDF 进行复杂操作:可以考虑 iText 7。
- 如果你的 HTML 页面使用了非常现代的 CSS (如 Flexbox, Grid) 或 JavaScript,PDF 的视觉效果必须和网页完全一致:wkhtmltopdf 是不二之选,但要接受其部署复杂性和性能开销。
对于大多数企业级应用,Flying Saucer 和 wkhtmltopdf 是最常用的两个方案。
