我目前正在尝试创建 PDF 格式的报告,并正在尝试使用 Thymeleaf 创建 HTML 模板,然后尝试使用 Flyingsaucer 将其转换为 PDF。它工作得相当好,除了由于某种原因,我可以声明我喜欢的所有 CSS 变量,在使用 CSS
var()
函数时,样式表实际上不会使用存储在变量中的颜色。举个小例子:
pom.xml
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf</artifactId>
<version>9.1.22</version>
</dependency>
模板.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<link th:href="@{/css/report.css}" rel="stylesheet" />
</head>
<body>
<div class="document-titles">
<h1 class="document-title">Baking report</h1><br />
<h2 class="document-date">September 2023</h2><br />
<h3 class="document-project-name">Project name: cake</h3>
</div>
<h1>Test h1</h1>
<h1>Test h1b (should be on next page (and it is!))</h1>
<ul>
<li>A</li>
<li>B</li>
</ul>
<ol>
<li>Cake</li>
<li>Pie</li>
</ol>
<table>
<tr>
<th>Name</th>
<th>Amount</th>
<th>Price</th>
</tr>
<tr>
<td>Eggs</td>
<td>4</td>
<td>€4</td>
</tr>
<tr>
<td>Flour</td>
<td>300 gr</td>
<td>€1</td>
</tr>
</table>
</body>
</html>
报告.css
:root {
/* Colors */
--blue: #00a8dc;
--grey: #9badbf;
--text-black: #212529;
--white: #fff;
}
@page {
size: a4;
orientation: portrait;
}
@page:first {
margin: 0;
background-image: url("../images/report-cover.jpg");
background-size: cover;
}
h1 {
page-break-before: always;
color: var(--blue); /* THIS IS COMPLETELY IGNORED; H1 REMAINS DEFAULT BLACK */
}
h1.document-title, h2.document-date, h3.document-project-name {
page-break-before: avoid;
margin: 0;
padding: 0;
}
PdfProofOfConcept.java
package com.acme.reports;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.context.IExpressionContext;
import org.thymeleaf.linkbuilder.StandardLinkBuilder;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
public class PdfProofOfConcept {
// https://www.baeldung.com/thymeleaf-generate-pdf
public static void main(String... args) throws IOException {
String template = parseThymeleafTemplate();
generatePdfFromHtml(template);
}
private static void generatePdfFromHtml(String html) throws IOException {
String outputFolder = System.getProperty("user.home") + File.separator + "thymeleaf_report.pdf";
OutputStream outputStream = new FileOutputStream(outputFolder);
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(html);
renderer.layout();
renderer.createPDF(outputStream);
outputStream.close();
}
private static String parseThymeleafTemplate() {
ClassLoaderTemplateResolver htmlTemplateResolver = new ClassLoaderTemplateResolver();
htmlTemplateResolver.setSuffix(".html");
htmlTemplateResolver.setTemplateMode(TemplateMode.HTML);
TemplateEngine templateEngine = new TemplateEngine();
templateEngine.setTemplateResolver(htmlTemplateResolver);
templateEngine.setLinkBuilder(new CustomLinkBuilder());
Context context = new Context();
context.setVariable("secretIngredient", "Chocolate chips");
return templateEngine.process("templates/report/thymeleaf_report", context);
}
}
// Needed for using relative links in an offline setting (e.g. without a webserver)
// https://stackoverflow.com/a/74511450
class CustomLinkBuilder extends StandardLinkBuilder {
@Override
protected String computeContextPath(IExpressionContext context, String base, Map<String, Object> parameters) {
return "./src/main/resources/static";
}
}
正如代码的最后一段所示,我遇到了一个问题,在 HTML 中加载样式表不起作用,因为 Thymeleaf 期望它从
HttpServletRequest
提供服务,而在我的情况下没有运行网络服务器,因此引用了资源和使用(例如样式表、javascript 和图像)需要构建自定义链接,因为它不是由网络服务器提供的。 (因此是 CustomLinkBuilder
。)我想 css var()
函数可能会发生类似的事情,通常必要的 CSS 预处理发生在浏览器或服务器上。我是否正确?如果是,我如何构建自己的预处理器? (至少对于 var()
函数。)或者是否有其他解释解释为什么原生 CSS 函数不能与 Thymeleaf 一起使用?
PDF 转换设置:检查用于将 Thymeleaf 模板转换为 PDF 的工具或库的设置和选项。某些 PDF 转换库可能具有与 CSS 处理相关的特定配置选项。确保 CSS 处理已启用并正确配置。
后备值:如果 PDF 渲染引擎不支持 CSS 变量,您可能需要直接在 CSS 规则中为使用变量的属性提供后备值。这样,即使不支持该变量,PDF 仍将以指定的样式呈现。
/* Fallback value in case the variable is not supported */
element {
property: var(--my-variable, #ff0000);
}