从 HTML 模板导出 PDF 文件

简介: 学习如何使用 Thymeleaf 和 Flying Saucer PDF 库从 HTML 模板文件中导出 .pdf 文件

一、添加 Thymeleaf 和 Flying Saucer PDF 库

要在 Gradle 构建项目中使用 Thymeleaf 和 Flying Saucer PDF 库,请将以下依赖项添加到 build.gradle 文件中。

implementation group: 'org.thymeleaf', name: 'thymeleaf', version: '3.0.13.RELEASE'
implementation group: 'org.xhtmlrenderer', name: 'flying-saucer-pdf', version: '9.1.22'

要在 Maven 构建项目中使用 Thymeleaf 和 Flying Saucer PDF 库,请将以下依赖项添加到 pom.xml 文件中。

<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf</artifactId>
    <version>3.0.13.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.xhtmlrenderer</groupId>
    <artifactId>flying-saucer-pdf</artifactId>
    <version>9.1.22</version>
</dependency>

二、实现 Exporter 类生成 PDF 文件

创建一个名为 PdfFileExporter 的新 Java 类,在该类中,我们使用 Thymeleaf 模板引擎从给定的模板文件名和方法 generateHtml() 中的数据填充 HTML 内容。然后我们实现 exportPdfFile() 方法从 HTML 内容写入 .pdf 文件。

PdfFileExporter.java

import com.lowagie.text.DocumentException;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.Map;
public class PdfFileExporter {
    public void exportPdfFile(String templateFileName, Map<String, Object> data, String pdfFileName) {
        String htmlContent = generateHtml(templateFileName, data);
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(pdfFileName);
            ITextRenderer renderer = new ITextRenderer();
            renderer.setDocumentFromString(htmlContent);
            renderer.layout();
            renderer.createPDF(fileOutputStream, false);
            renderer.finishPDF();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }
    private String generateHtml(String templateFileName, Map<String, Object> data) {
        TemplateEngine templateEngine = createTemplateEngine();
        Context context = new Context();
        context.setVariables(data);
        String htmlContent = templateEngine.process(templateFileName, context);
        return htmlContent;
    }
    private TemplateEngine createTemplateEngine() {
        ClassLoaderTemplateResolver pdfTemplateResolver = new ClassLoaderTemplateResolver();
        pdfTemplateResolver.setPrefix("pdf-templates/");
        pdfTemplateResolver.setSuffix(".html");
        pdfTemplateResolver.setTemplateMode("HTML5");
        pdfTemplateResolver.setCharacterEncoding("UTF-8");
        pdfTemplateResolver.setOrder(1);
        TemplateEngine templateEngine = new TemplateEngine();
        templateEngine.setTemplateResolver(pdfTemplateResolver);
        return templateEngine;
    }
}

三、将 HTML 模板文件添加到资源目录

例如,我们需要实现一个程序来将供应订单表格导出为 PDF 文件。

在这一步中,我们在 resources/pdf-templates 目录下创建新的 Thymeleaf 格式的 HTML 模板文件,文件名为 order-template.html,如下所示。

资源/pdf-templates/order-template.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <style>
        h1 {
            color: #25a7e7;
            text-align: center;
        }
        .order {
            width: 100%;
        }
        .order, .order th, .order td {
            border: 1px solid #25a7e7;
            border-collapse: collapse;
        }
        .order th {
            background-color: #25a7e7;
            color: white;
        }
        .total {
            text-align: right;
        }
    </style>
</head>
<body>
<table>
    <tr>
        <td>
            <img width="80" src="https://i-1-lanrentuku.52tup.com/2020/11/6/c31b2f7a-d84f-4340-b6fe-31a9271137e1.png?imageView2/2/w/1024/" />
        </td>
        <td>
            <h1>Supply Order Form</h1>
        </td>
    </tr>
</table>
<div>
    <table>
        <tr>
            <td th:text="'Date: ' + ${#dates.format(order.date, 'dd/MM/yyyy')}"></td>
        </tr>
        <tr>
            <td th:text="'Order #: ' + ${order.orderNo}"></td>
        </tr>
        <tr>
            <td th:text="'Request Date: ' + ${#dates.format(order.requestDate, 'dd/MM/yyyy')}"></td>
        </tr>
        <tr>
            <td th:text="'Order Date: ' + ${#dates.format(order.orderDate, 'dd/MM/yyyy')}"></td>
        </tr>
    </table>
</div>
<br />
<table class="order">
    <tr>
        <th>Item #</th>
        <th>Description</th>
        <th>Quantity</th>
        <th>Unit Price</th>
        <th>Total</th>
    </tr>
    <tr th:each="item, iterStat: ${orderItems}">
        <td th:text="${iterStat.index + 1}"></td>
        <td th:text="${item.description}"></td>
        <td th:text="${item.quantity}"></td>
        <td th:text="${item.unitPrice}"></td>
        <td th:text="${item.total}"></td>
    </tr>
    <tr>
        <td class="total" colspan="4"><b>Total</b></td>
        <td><b th:text="${#aggregates.sum(orderItems.{total})}"></b></td>
    </tr>
</table>
</body>
</html>

四、实现 DTO 类

为了处理上面的 HTML 模板文件,我们添加了名为 Order 和 OrderItem 的 DTO 类,如下所示。

订单.java

import java.util.Date;
public class Order {
    private String orderNo;
    private Date date;
    private Date requestDate;
    private Date orderDate;
    public String getOrderNo() {
        return orderNo;
    }
    public void setOrderNo(String orderNo) {
        this.orderNo = orderNo;
    }
    public Date getDate() {
        return date;
    }
    public void setDate(Date date) {
        this.date = date;
    }
    public Date getRequestDate() {
        return requestDate;
    }
    public void setRequestDate(Date requestDate) {
        this.requestDate = requestDate;
    }
    public Date getOrderDate() {
        return orderDate;
    }
    public void setOrderDate(Date orderDate) {
        this.orderDate = orderDate;
    }
}

订单项.java

public class OrderItem {
    private String description;
    private Integer quantity;
    private Double unitPrice;
    private Double total;
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public Integer getQuantity() {
        return quantity;
    }
    public void setQuantity(Integer quantity) {
        this.quantity = quantity;
    }
    public Double getUnitPrice() {
        return unitPrice;
    }
    public void setUnitPrice(Double unitPrice) {
        this.unitPrice = unitPrice;
    }
    public Double getTotal() {
        return total;
    }
    public void setTotal(Double total) {
        this.total = total;
    }
}

五、实现主类生成PDF文件

在这一步,我们实现一个 Main 类,创建一些测试数据并使用 PdfFileExporter 类导出 PDF 文件。

主.java

import java.util.*;
public class Main {
    public static void main(String... args) {
        PdfFileExporter pdfFileExporter = new PdfFileExporter();
        Map<String, Object> data = createTestData();
        String pdfFileName = "D:\\test\\order.pdf";
        pdfFileExporter.exportPdfFile("order-template", data, pdfFileName);
    }
    private static Map<String, Object> createTestData() {
        Map<String, Object> data = new HashMap<>();
        Order order = new Order();
        order.setOrderNo("ABC-12345");
        order.setDate(new Date());
        order.setOrderDate(new Date());
        order.setRequestDate(new Date());
        data.put("order", order);
        List<OrderItem> orderItems = new ArrayList<>();
        OrderItem orderItem1 = new OrderItem();
        orderItem1.setDescription("Test Order Item 1");
        orderItem1.setQuantity(1);
        orderItem1.setUnitPrice(100.0);
        orderItem1.setTotal(100.0);
        orderItems.add(orderItem1);
        OrderItem orderItem2 = new OrderItem();
        orderItem2.setDescription("Test Order 2");
        orderItem2.setQuantity(5);
        orderItem2.setUnitPrice(50.0);
        orderItem2.setTotal(250.0);
        orderItems.add(orderItem2);
        OrderItem orderItem3 = new OrderItem();
        orderItem3.setDescription("Test Order 3");
        orderItem3.setQuantity(2);
        orderItem3.setUnitPrice(200.0);
        orderItem3.setTotal(400.0);
        orderItems.add(orderItem3);
        data.put("orderItems", orderItems);
        return data;
    }
}

执行上面的Java 文件,PDF文件将导出到D:\test\order.pdf,然后用PDF软件打开文件,可以看到PDF文件内容如下。


相关文章
|
1月前
|
XML 缓存 JSON
为什么浏览器中有些图片、PDF等文件点击后有些是预览,有些是下载
为什么浏览器中有些图片、PDF等文件点击后有些是预览,有些是下载
124 0
|
8天前
|
JavaScript
vue导出pdf(接口)
vue导出pdf(接口)
|
1月前
|
缓存 Java 应用服务中间件
SpringMVC入门到实战------七、SpringMVC创建JSP页面的详细过程+配置模板+实现页面跳转+配置Tomcat。JSP和HTML配置模板的差异对比(二)
这篇文章详细介绍了在SpringMVC中创建JSP页面的全过程,包括项目的创建、配置、Tomcat的设置,以及如何实现页面跳转和配置模板解析器,最后还对比了JSP和HTML模板解析的差异。
SpringMVC入门到实战------七、SpringMVC创建JSP页面的详细过程+配置模板+实现页面跳转+配置Tomcat。JSP和HTML配置模板的差异对比(二)
|
23天前
|
移动开发 资源调度 JavaScript
Vue移动端网页(H5)预览pdf文件(pdfh5和vue-pdf)
这篇文章介绍了在Vue移动端网页中使用`pdfh5`和`vue-pdf`两个插件来实现PDF文件的预览,包括滚动查看、缩放、添加水印、分页加载、跳转指定页数等功能。
Vue移动端网页(H5)预览pdf文件(pdfh5和vue-pdf)
|
30天前
|
JavaScript 前端开发
vue导出pdf(大数量可能有问题)
vue导出pdf(大数量可能有问题)
|
1月前
|
JSON JavaScript 数据格式
打印插件 hiprint 使用、回单打印PDF保存本地、将列表数据打印成pdf文件保存到本地
这篇文章介绍了如何使用hiprint打印插件将列表数据打印成PDF文件并保存到本地,包括插件的配置、依赖安装、项目代码案例以及如何预览和打印数据。
打印插件 hiprint 使用、回单打印PDF保存本地、将列表数据打印成pdf文件保存到本地
|
21天前
|
C# 开发者 Windows
WPF与PDF文档:解锁创建和编辑PDF文件的新技能——从环境配置到代码实践,手把手教你如何在WPF应用中高效处理PDF,提升文档管理效率
【8月更文挑战第31天】随着数字文档的普及,PDF因跨平台兼容性和高保真度成为重要格式。WPF虽不直接支持PDF处理,但借助第三方库(如iTextSharp)可在WPF应用中实现PDF的创建与编辑。本文通过具体案例和示例代码,详细介绍了如何在WPF中集成PDF库,并展示了从设计用户界面到实现PDF创建与编辑的完整流程。不仅包括创建新文档的基本步骤,还涉及在现有PDF中添加页眉页脚等高级功能。通过这些示例,WPF开发者可以更好地掌握PDF处理技术,提升应用程序的功能性和实用性。
36 0
|
1月前
|
Java
JAVA PDF 截取N页,生成新文件,转图片,多个PDF 合并
JAVA PDF 截取N页,生成新文件,转图片,多个PDF 合并
66 0
|
3月前
|
JavaScript
VScode格式化vue文件--避免html属性换行
VScode格式化vue文件--避免html属性换行
272 0
|
12月前
|
JavaScript 前端开发
VSCode .vue 文件 html css 无智能提示
VSCode .vue 文件 html css 无智能提示
819 0