You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:如何将包含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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 04:20:16