求助:如何将包含Google Chart的Thymeleaf HTML转换为PDF?
解决方案:带Google Chart的Thymeleaf HTML转PDF
核心问题在于iText、传统模板引擎这类工具仅能解析静态HTML/CSS,不会执行JavaScript,而Google Chart是通过前端JS动态渲染的,因此直接转换会丢失图表。下面是几种可行的解决思路:
1. 用无头浏览器完整渲染页面后转PDF
通过无头浏览器(模拟真实浏览器环境执行JS)加载渲染后的HTML,待图表生成后再导出PDF,这是兼容性最好的方案。
Java环境示例(Selenium + Chrome Headless)
- 先引入Selenium依赖(Maven):
<dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-chrome-driver</artifactId> <version>4.15.0</version> </dependency>
- 核心代码:
import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.print.PrintOptions; import java.io.FileOutputStream; import java.nio.file.Files; import java.nio.file.Paths; public class ChartHtmlToPdf { public static void main(String[] args) { ChromeOptions options = new ChromeOptions(); options.addArguments("--headless=new"); // 启用无头模式 options.addArguments("--disable-gpu"); options.addArguments("--no-sandbox"); ChromeDriver driver = new ChromeDriver(options); try { // 加载Thymeleaf渲染完成的HTML文件(也可部署临时服务用URL访问) driver.get("file:///path/to/your/rendered-chart-page.html"); // 等待Google Chart渲染完成,根据图表复杂度调整等待时间 Thread.sleep(3000); PrintOptions printOptions = new PrintOptions(); printOptions.setPageRanges("1"); byte[] pdfBytes = driver.print(printOptions); // 将PDF字节流写入文件 Files.write(Paths.get("chart-output.pdf"), pdfBytes); } catch (Exception e) { e.printStackTrace(); } finally { driver.quit(); } } }
2. 预渲染Google Chart为静态图片嵌入HTML
利用Google Chart提供的静态图片API,直接在后端生成图表图片URL,替换模板中的JS渲染代码,再用iText等工具转PDF。
示例用法
把动态数据拼接成静态API请求URL,在Thymeleaf模板中用<img>标签引入:
<!-- 替换原有的Google Chart JS代码 --> <img th:src="|https://chart.googleapis.com/chart?cht=lc&chd=t:${dataList}&chs=600x300&chl=${labelList}|" />
参数说明:
cht=lc:指定图表类型为折线图(其他类型参考官方文档)chd=t:10,20,30:图表数据chs=600x300:图表尺寸chl=Jan|Feb|Mar:坐标轴标签
这种方案无需依赖浏览器,但仅支持Google Chart的基础图表类型,复杂交互类图表无法实现。
3. 使用支持JS渲染的PDF库(有限兼容)
部分PDF库支持基础JS执行,比如Flying Saucer(搭配OpenPDF),但对复杂JS的支持不如无头浏览器,适合简单场景。
核心代码示例
import org.xhtmlrenderer.pdf.ITextRenderer; import java.io.FileOutputStream; public class FlyingSaucerPdf { public static void main(String[] args) throws Exception { ITextRenderer renderer = new ITextRenderer(); // 启用JS支持 renderer.getSharedContext().getUserAgentCallback().setAllowScripting(true); // 加载渲染后的HTML文件 renderer.setDocument(new File("path/to/rendered-page.html")); renderer.layout(); // 生成PDF try (FileOutputStream os = new FileOutputStream("output.pdf")) { renderer.createPDF(os); } } }
方案选择建议
- 优先用无头浏览器方案,能完美还原所有浏览器渲染效果,支持复杂图表和交互;
- 若不想引入浏览器依赖,且图表逻辑简单,可选择静态图片API方案;
- Flying Saucer仅适合对JS需求极低的场景,不推荐用于Google Chart这类复杂JS渲染的图表。
内容的提问来源于stack exchange,提问作者Pain
相关产品推荐
相关产品推荐

