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

使用Flying Saucer与Thymeleaf生成PDF时静态图片无法显示

解决Flying Saucer生成PDF时无法加载classpath静态图片的问题

我之前也遇到过一模一样的问题!Flying Saucer对资源的加载逻辑和Spring Boot的静态资源管理不太兼容,直接用相对路径或者默认的绝对路径它根本找不到。下面给你几个亲测有效的解决方案:

方法一:配置ResourceResolver+Thymeleaf标准URL语法

这是最常用的方案,既能保持模板的简洁性,又能让Flying Saucer正确定位资源:

  • 先修改Thymeleaf模板里的img标签,用Thymeleaf的@{}语法生成标准化路径:
<img th:src="@{/images/logo_black.png}" />

这个语法会自动适配应用路径,但关键是要让Flying Saucer学会从classpath加载资源。

  • 在生成PDF的代码中,给ITextRenderer配置自定义的资源解析器:
ITextRenderer renderer = new ITextRenderer();

// 配置资源解析器,让Flying Saucer能读取classpath下的静态资源
renderer.getSharedContext().setResourceResolver(new ResourceResolver() {
    @Override
    public Resource getResource(String uri) throws IOException {
        // 去掉路径开头的斜杠,classpath资源不需要前置斜杠
        if (uri.startsWith("/")) {
            uri = uri.substring(1);
        }
        // 从classpath加载资源,假设图片放在src/main/resources/static/images/下
        InputStream resourceStream = getClass().getClassLoader().getResourceAsStream("static/" + uri);
        if (resourceStream == null) {
            return null; // 找不到资源时返回null即可
        }
        return new InputStreamResource(resourceStream);
    }
});

// 渲染HTML并生成PDF
renderer.setDocumentFromString(processedHtml); // processedHtml是Thymeleaf渲染后的HTML内容
renderer.layout();
renderer.createPDF(outputStream);

方法二:直接使用Base64嵌入图片(适合小图片)

如果你的图片体积不大,直接把它转成Base64字符串嵌入HTML是最省心的,完全不用纠结路径问题:

  • 先写一个工具类负责读取图片并转换为Base64:
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
import java.util.Base64;

@Component
public class ImageBase64Util {
    public String getImageAsBase64(String imageFileName) throws IOException {
        // 路径对应src/main/resources/static/images/下的文件
        InputStream inputStream = getClass().getClassLoader().getResourceAsStream("static/images/" + imageFileName);
        if (inputStream == null) {
            throw new IOException("图片不存在:" + imageFileName);
        }
        byte[] imageBytes = IOUtils.toByteArray(inputStream);
        return "data:image/png;base64," + Base64.getEncoder().encodeToString(imageBytes);
    }
}
  • 然后在Thymeleaf模板里调用这个工具类:
<img th:src="${@imageBase64Util.getImageAsBase64('logo_black.png')}" />

几个需要注意的坑

  • 检查编译后的资源:确认target/classes/static/images/下存在你的logo_black.png,Maven/Gradle默认会把src/main/resources下的文件复制到这里,如果找不到,大概率是路径写错了。
  • 严格的XHTML格式:Flying Saucer对HTML格式要求很严格,模板开头一定要加上正确的DOCTYPE声明:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
  • 注意大小写:Linux/Unix环境下文件名和路径是区分大小写的,别把logo_black.png写成Logo_Black.png!

内容的提问来源于stack exchange,提问作者user7307131

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:43:15