从 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天前
一款跳转警告HTML单页模板
一款跳转警告HTML单页模板
10 0
一款跳转警告HTML单页模板
|
5天前
|
移动开发 前端开发 数据可视化
分享63个Html后端模板,总有一款适合您
分享63个Html后端模板,总有一款适合您
16 3
|
5天前
|
移动开发 前端开发 HTML5
分享62个Html后端模板,总有一款适合您
分享62个Html后端模板,总有一款适合您
13 4
|
5天前
|
移动开发 前端开发 数据管理
分享83个Html后端模板,总有一款适合您
分享83个Html后端模板,总有一款适合您
13 2
|
5天前
|
移动开发 前端开发 HTML5
分享83个Html前端模板,总有一款适合您
分享83个Html前端模板,总有一款适合您
17 4
|
6天前
|
移动开发 前端开发 程序员
分享90个Html前端模板,总有一款适合您
分享90个Html前端模板,总有一款适合您
10 2
|
6天前
|
移动开发 前端开发 JavaScript
分享79个Html前端模板,总有一款适合您
分享79个Html前端模板,总有一款适合您
14 0
|
6天前
|
移动开发 开发框架 前端开发
分享78个Html前端模板,总有一款适合您
分享78个Html前端模板,总有一款适合您
9 0
|
6天前
|
移动开发 前端开发 JavaScript
分享76个Html前端模板,总有一款适合您
分享76个Html前端模板,总有一款适合您
16 5
|
7天前
|
移动开发 前端开发 新能源
分享80个Html前端模板,总有一款适合您
分享80个Html前端模板,总有一款适合您
10 0

热门文章

最新文章

相关产品

  • 云迁移中心