一、添加 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文件内容如下。