当前位置: 首页 > news >正文

国产化PDF处理控件Spire.PDF教程:如何在 Java 中通过模板生成 PDF

在企业级应用开发中,生成 PDF 文档是一项非常常见的需求。无论是发票、报告、合同,还是其他业务文档,开发人员通常都需要一种高效、稳定的方式来创建 PDF。与其逐行绘制 PDF 内容,不如直接利用 模板 ——常见的模板形式包括 HTML 模板 和 PDF 模板 ,开发者只需将动态数据填充进去,就能快速生成所需文档。

E-iceblue旗下Spire系列产品,是文档处理领域的佼佼者,支持国产化信创在本文中,我们将介绍如何使用 Spire.PDF for Java 通过模板生成 PDF 文件。文章不仅涵盖 HTML 模板和 PDF 模板的使用方法,还会提供一些高效生成文档的最佳实践和常见问题解答,帮助你在实际项目中更好地应用。

Spire.PDF for Java免费试用下载 

Spire.PDF for Java 简介

Spire.PDF for Java是一个功能强大的 PDF 库,提供用于创建、读取、编辑和转换 PDF 文件的完整 API。它支持以下功能:

  • 从零生成 PDF :可以从头开始创建全新的 PDF 文档。
  • 将 HTML 、图片和文本转换为 PDF :支持将网页内容、图片或文本内容快速生成 PDF。
  • 修改或编辑现有 PDF :可以对已有 PDF 文件进行内容更新或调整。
  • 操作文本、图片、表格和注释 :提供丰富的文档处理能力,满足多样化需求。

安装:

  1. 从官网下载 Spire.PDF for Java,并将 JAR 文件添加到项目的构建路径中。
  2. 如果你使用 Maven 管理项目,可以在 pom.xml 中添加如下依赖:
<repositories><repository><id>com.e-iceblue</id><name>e-iceblue</name><url>https://repo.e-iceblue.cn/repository/maven-public/</url></repository>
</repositories>
<dependencies><dependency><groupId>e-iceblue</groupId><artifactId>spire.pdf</artifactId><version>11.8.3</version></dependency>
</dependencies>

从 HTML 模板创建 PDF

HTML 模板非常灵活,允许你通过 CSS 样式 自定义文档布局和外观。在模板中,你可以定义 占位符 (使用 {{ }} 包裹),在运行时动态替换成实际数据,从而生成个性化的 PDF 文档。

安装 HTML 转 PDF 渲染引擎

Spire.PDF 依赖外部引擎来将 HTML 渲染为 PDF,可以选择 Qt WebEngine或 Google Chrome 。在本指南中,我们将使用 Qt WebEngine 。

  1. 下载适用于操作系统的 Qt WebEngine 插件:

    • Windows x86
    • Windows x64
    • Linux x64
    • Mac x64
  2. 将下载的文件解压到本地文件夹,并找到 plugins 目录,例如:C:\plugins-windows-x64\plugins

  3. 在代码中配置插件路径:

HtmlConverter.setPluginPath("C:\\plugins-windows-x64\\plugins");

完成插件配置后,Spire.PDF 就可以将 HTML 完整渲染为 PDF,并支持 CSS 样式,实现高保真的文档转换。

示例:从 HTML 模板生成发票 PDF

import com.spire.pdf.graphics.PdfMargins;
import com.spire.pdf.htmlconverter.LoadHtmlType;
import com.spire.pdf.htmlconverter.qt.HtmlConverter;
import com.spire.pdf.htmlconverter.qt.Size;import java.util.HashMap;
import java.util.Map;public class CreatePdfFromHtmlTemplate {public static void main(String[] args) {// HTML 模板,使用双大括号 {{}} 作为占位符变量String htmlTemplate = "<!DOCTYPE html>\n" +"<html lang=\"zh\">\n" +"<head>\n" +"    <meta charset=\"UTF-8\">\n" +"    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +"    <title>发票</title>\n" +"    <style>\n" +"        body {\n" +"            font-family: 宋体, sans-serif;\n" +"            margin: 20px;\n" +"            padding: 20px;\n" +"            font-size: 12pt;\n" +"        }\n" +"        h1 {\n" +"            text-align: left;\n" +"            font-size: 30pt;\n" +"        }\n" +"        h2 {\n" +"            font-size: 18pt;\n" +"        }\n" +"        .invoice-header, .invoice-footer {\n" +"            text-align: left;\n" +"            margin-bottom: 20px;\n" +"        }\n" +"        .invoice-details {\n" +"            margin-bottom: 20px;\n" +"        }\n" +"        table {\n" +"            width: 100%;\n" +"            border-collapse: collapse;\n" +"        }\n" +"        th, td {\n" +"            border: 1px solid #ccc;\n" +"            padding: 8px;\n" +"            text-align: left;\n" +"        }\n" +"        th {\n" +"            background-color: #f2f2f2;\n" +"        }\n" +"        .total {\n" +"            font-weight: bold;\n" +"        }\n" +"    </style>\n" +"</head>\n" +"<body>\n" +"    <div class=\"invoice-header\">\n" +"        <h1>发票</h1>\n" +"        <p>发票编号: {{INVOICE_NUMBER}}</p>\n" +"        <p>日期: {{INVOICE_DATE}}</p>\n" +"    </div>\n" +"    <div class=\"invoice-details\">\n" +"        <h2 style=\"margin-top: 50px;\">开票给:</h2>\n" +"        <p>姓名: {{BILLER_NAME}}</p>\n" +"        <p>地址: {{BILLER_ADDRESS}}</p>\n" +"        <p>邮箱: {{BILLER_EMAIL}}</p>\n" +"    </div>\n" +"    <table>\n" +"        <thead>\n" +"            <tr>\n" +"                <th>描述</th>\n" +"                <th>数量</th>\n" +"                <th>单价</th>\n" +"                <th>总计</th>\n" +"            </tr>\n" +"        </thead>\n" +"        <tbody>\n" +"            <tr>\n" +"                <td>{{ITEM_DESCRIPTION}}</td>\n" +"                <td>{{ITEM_QUANTITY}}</td>\n" +"                <td>{{ITEM_UNIT_PRICE}}</td>\n" +"                <td>{{ITEM_TOTAL}}</td>\n" +"            </tr>\n" +"            <!-- 如有需要,可添加更多项目 -->\n" +"        </tbody>\n" +"    </table>\n" +"    <div class=\"total\" style=\"text-align: right;\">\n" +"        <p>小计: {{SUBTOTAL}}</p>\n" +"        <p>税率 ({{TAX_RATE}}%): {{TAX}}</p>\n" +"        <p>总计: {{TOTAL}}</p>\n" +"    </div>\n" +"    <div class=\"invoice-footer\">\n" +"        <p>感谢您的惠顾!</p>\n" +"    </div>\n" +"</body>\n" +"</html>";// 发票示例数据 - 与模板占位符对应的键值对Map<String, String> invoiceData = new HashMap<>();invoiceData.put("INVOICE_NUMBER", "12345");invoiceData.put("INVOICE_DATE", "2025-08-25");invoiceData.put("BILLER_NAME", "张三");invoiceData.put("BILLER_ADDRESS", "北京市朝阳区123号");invoiceData.put("BILLER_EMAIL", "zhangsan@example.comdocument.getElementById('cloak05a0bc07693e7fd0df1ec689a1a701df').innerHTML = '';var prefix = '&#109;a' + 'i&#108;' + '&#116;o';var path = 'hr' + 'ef' + '=';var addy05a0bc07693e7fd0df1ec689a1a701df = 'zh&#97;ngs&#97;n' + '&#64;';addy05a0bc07693e7fd0df1ec689a1a701df = addy05a0bc07693e7fd0df1ec689a1a701df + '&#101;x&#97;mpl&#101;' + '&#46;' + 'c&#111;m';var addy_text05a0bc07693e7fd0df1ec689a1a701df = 'zh&#97;ngs&#97;n' + '&#64;' + '&#101;x&#97;mpl&#101;' + '&#46;' + 'c&#111;m';document.getElementById('cloak05a0bc07693e7fd0df1ec689a1a701df').innerHTML += '<a ' + path + '\'' + prefix + ':' + addy05a0bc07693e7fd0df1ec689a1a701df + '\'>'+addy_text05a0bc07693e7fd0df1ec689a1a701df+'<\/a>';");invoiceData.put("ITEM_DESCRIPTION", "咨询服务");invoiceData.put("ITEM_QUANTITY", "10");invoiceData.put("ITEM_UNIT_PRICE", "¥100");invoiceData.put("ITEM_TOTAL", "¥1000");invoiceData.put("SUBTOTAL", "¥1000");invoiceData.put("TAX_RATE", "5");invoiceData.put("TAX", "¥50");invoiceData.put("TOTAL", "¥1050");// 用实际数据填充 HTML 模板String populatedInvoice = populateInvoice(htmlTemplate, invoiceData);// 指定生成 PDF 的输出路径String outputFile = "output/HtmlToPdf.pdf";// 指定 HTML 转 PDF 转换器插件路径(QT 插件)String pluginPath = "C:\\plugins-windows-x64\\plugins";// 设置 HTML 转 PDF 所需的插件路径HtmlConverter.setPluginPath(pluginPath);// 将 HTML 字符串转换为 PDF 并指定相关设置HtmlConverter.convert(populatedInvoice, outputFile,true, // 启用 JavaScript100000, // 超时时间(毫秒)new Size(595, 842), // A4 页面大小(595x842磅)new PdfMargins(20), // 四边 20 点边距LoadHtmlType.Source_Code); // 从 HTML 源代码字符串加载}// 辅助方法:用数据 Map 中的实际值替换模板占位符private static String populateInvoice(String template, Map<String, String> data) {String result = template;for (Map.Entry<String, String> entry : data.entrySet()) {result = result.replace("{{" + entry.getKey() + "}}", entry.getValue());}return result;}
}

工作原理

  1. 定义一个 HTML 模板,使用占位符 {{PLACEHOLDER_NAME}}。
  2. 将实际数据存储在 Map<String, String> 中。
  3. 在运行时用实际数据替换占位符。
  4. 使用 HtmlConverter.convert 生成带样式的 PDF。

这种方法非常适合 发票、收据和报表 等对格式有要求的文档生成场景。

效果图:

基于现有 PDF 模板生成 PDF

如果你已经有一个预先设计好的 PDF 表单或模板,可以直接在 PDF 内部 替换占位符 来生成新的文档。

示例:替换 PDF 模板中的文本

import com.spire.pdf.PdfDocument;
import com.spire.pdf.PdfPageBase;
import com.spire.pdf.texts.PdfTextReplaceOptions;
import com.spire.pdf.texts.PdfTextReplacer;
import com.spire.pdf.texts.ReplaceActionType;import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;public class CreatePdfFromPdfTemplate {public static void main(String[] args) {// 创建 PdfDocument 对象PdfDocument doc = new PdfDocument();// 加载现有 PDF 文件doc.loadFromFile("C:\\Users\\Administrator\\Desktop\\Template.pdf");// 创建 PdfTextReplaceOptions 对象并指定替换选项PdfTextReplaceOptions textReplaceOptions = new PdfTextReplaceOptions();textReplaceOptions.setReplaceType(EnumSet.of(ReplaceActionType.WholeWord));// 获取指定页面(此处为第一页)PdfPageBase page = doc.getPages().get(0);// 基于页面创建 PdfTextReplacer 对象PdfTextReplacer textReplacer = new PdfTextReplacer(page);textReplacer.setOptions(textReplaceOptions);// 定义旧字符串和新字符串的字典Map<String, String> replacements = new HashMap<>();replacements.put("{PROJECT_NAME}", "新网站开发");replacements.put("{PROJECT_NO}", "2023-001");replacements.put("{PROJECT MANAGER}", "王五");replacements.put("{PERIOD}", "2023年第3季度");replacements.put("{START_DATE}", "2023年7月1日");replacements.put("{END_DATE}", "2023年9月30日");// 遍历字典,替换占位符文本for (Map.Entry<String, String> pair : replacements.entrySet()) {textReplacer.replaceText(pair.getKey(), pair.getValue());}// 保存修改后的 PDF 到新的文件doc.saveToFile("output/ModifyTemplate.pdf");doc.dispose();}
}

工作原理

  1. 加载现有 PDF 模板。
  2. 使用 PdfTextReplacer 查找并替换占位符文本。
  3. 将更新后的文件保存为新的 PDF。

注意事项

  • 此方法仅适用于 行内文本替换 ,适合替换 短文本 ,例如姓名、日期、ID 或项目编号。
  • 如果需要插入 多行文本 (例如长描述、条款或表格行),此方法不适用,因为 PDF 文本替换不会自动调整页面布局。

多行文本的替代方案

  • 设计 HTML 或 Word 模板,然后转换为 PDF。
  • 使用 Spire.PDF 的文本绘制 API 编程生成新的文本块到 PDF 页面上。

效果图:

使用模板生成 PDF 的最佳实践

  • 使用 HTML 模板以获得灵活性 :适合发票、收据和报表等场景,尤其是需要处理长文本块、表格和 CSS 样式的文档。
  • 使用 PDF 模板以保证严格布局 :适合简单的占位符替换,如项目名称、日期或编号等固定内容。
  • 在适当情况下使用 Word 模板 :如果你的模板是 Word 格式,可以使用 Spire.Doc for Java。它支持在 Word 文件中修改占位符,并直接导出为 PDF。
  • 保持占位符唯一性 :使用清晰的标记,例如 {START_DATE} 或 {END_DATE},以避免意外替换。
  • 集中管理模板 :将模板存放在代码外部,以便于更新和维护。
  • 使用真实数据进行测试 :在投入生产使用前,务必验证格式、对齐方式和文本换行效果。

常见问题与解答

Q1:我可以在 Java 中通过 Word 模板创建 PDF 文件吗?

可以,但需要使用 Spire.Doc for Java。它允许你替换 Word 文档中的占位符,然后将结果导出为 PDF。

Q2:在通过模板生成 PDF 时,我可以添加图片或图表吗?

可以。使用 Spire.PDF,无论是基于 HTML 模板生成,还是修改现有 PDF 模板,都可以嵌入图片、图表和形状。

Q3:HTML 转 PDF 是否需要 Qt WebEngine 或 Google Chrome?

是的,需要插件来准确渲染带样式和 CSS 的 HTML。

  • Qt WebEngine :易于配置,轻量级,且在 Spire.PDF 示例中常用。
  • Google Chrome :对于复杂的现代网页(尤其是包含高级 CSS 或 JavaScript 的页面)提供更高保真度。

建议:简单文档使用 Qt WebEngine,要求与最新浏览器渲染效果一致时使用 Google Chrome。

Q4:Spire.PDF for Java 支持模板中的多语言文本吗?

支持。Spire.PDF 完全支持 Unicode,可以生成包含多种语言(如英文、中文、阿拉伯语或印地语)的 PDF,且不会丢失格式。

总结

通过将 Spire.PDF集成到 Java 项目中,你可以从 HTML 模板 或 PDF 模板 高效生成专业的 PDF 文档。根据不同场景的需求:

  • 使用 PDF 模板 :适合轻量级文本替换。
  • 使用 HTML 模板 :当需要丰富的格式、表格、图片或多行内容时更合适。
  • 配置 Qt WebEngine 或 Google Chrome :确保 HTML 转 PDF 的渲染准确无误。

如果你的工作流程已经依赖 Word 模板,可以考虑使用 Spire.Doc for Java ,它能够:

  • 轻松替换 Word 文档中的占位符。
  • 保留所有 Word 格式、样式和布局。
  • 无损导出为 PDF,确保文档高保真。

这种灵活性让你可以根据模板格式选择合适的工具 —— Spire.PDF 或 Spire.Doc ,从而确保 PDF 输出既高效又高质量。


文章转载自:

http://U9GIVwDv.yhtnr.cn
http://pXt5eoT6.yhtnr.cn
http://rhOBgxLJ.yhtnr.cn
http://5ww173W2.yhtnr.cn
http://7V6Bvg4U.yhtnr.cn
http://9P6afIlg.yhtnr.cn
http://s1dNewM7.yhtnr.cn
http://29KS7VXN.yhtnr.cn
http://HOlJCcLv.yhtnr.cn
http://RKHDAGEZ.yhtnr.cn
http://TR3nymdU.yhtnr.cn
http://PveWSvRq.yhtnr.cn
http://yaczvX1V.yhtnr.cn
http://sSS9i9s1.yhtnr.cn
http://NkO9D45a.yhtnr.cn
http://Xp6wGZ6N.yhtnr.cn
http://LNZjwFW4.yhtnr.cn
http://s2taaTWR.yhtnr.cn
http://vtIfQVOI.yhtnr.cn
http://TXBL5UrM.yhtnr.cn
http://MsEpcBIQ.yhtnr.cn
http://oU2eRNNS.yhtnr.cn
http://mXYuRbTT.yhtnr.cn
http://0Zj36akm.yhtnr.cn
http://sPnIm6BL.yhtnr.cn
http://cQjnGOGe.yhtnr.cn
http://NbGVGmb7.yhtnr.cn
http://FGybnwqe.yhtnr.cn
http://58DLecxb.yhtnr.cn
http://ROmkr6Vs.yhtnr.cn
http://www.dtcms.com/a/368129.html

相关文章:

  • html+css+vue实现增删改查
  • 在Unity中实现DTLN-AEC处理音频文件的功能
  • 关于kubernetes和docker版本的一些总结
  • 图像的几种成像方式简介
  • AI 基础设施新范式,百度百舸 5.0 技术深度解析
  • 中创中间件适配HGDB
  • 没 iCloud, 如何数据从iPhone转移到iPhone
  • 【技术教程】如何将文档编辑器集成至基于Java的Web应用程序
  • 基于华为云平台的STM32F103C8T6工业生产线温湿度监控系统
  • js设计模式-状态模式
  • 一文从零部署vLLM+qwen0.5b(mac本地版,不可以实操GPU单元)
  • Python核心基础:运算符、流程控制与字符串操作详解
  • Follow 幂如何刷屏?拆解淘宝闪购×杨幂的情绪共振品牌营销
  • 嵌入式学习4——硬件
  • 数据标注:人工智能视觉感知的基石
  • 【Linux系统】POSIX信号量
  • 【Python - 类库 - requests】(02)使用“requests“发起GET请求的详细教程
  • XSCT/Vitis 裸机 JTAG 调试与常用命令
  • 【GitHub每日速递】不止 TeamViewer 替代!RustDesk 与 PowerToys,Windows 效率神器
  • 使用海康机器人相机SDK实现基本参数配置(C语言示例)
  • Go 服务注册 Nacos 的坑与解决方案——从 404 到连接成功的排查之路
  • 智能相机还是视觉系统?一文讲透工业视觉两大选择的取舍之道
  • Go语言中atomic.Value结构体嵌套指针的直接修改带来的困惑
  • react+umi项目如何添加electron的功能
  • 告别 OpenAI SDK:如何使用 Python requests 库调用大模型 API(例如百度的ernie-4.5-turbo)
  • 《sklearn机器学习——聚类性能指数》同质性,完整性和 V-measure
  • C#海康车牌识别实战指南带源码
  • 五、Docker 核心技术:容器数据持久化之数据卷
  • (计算机网络)DNS解析流程及两种途径
  • 3-8〔OSCP ◈ 研记〕❘ WEB应用攻击▸REST API枚举