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

使用OpenPDF生成PDF时如何添加HTML模板定义的全局页眉页脚?

OpenPDF 使用 HTML 模板生成每页页眉/页脚的实现方案

你的需求完全可以实现,结合你已经在使用 Thymeleaf 生成内容的技术栈,推荐的实现流程如下:


核心实现思路

你可以先用 Thymeleaf 把页眉、页脚的 HTML 模板字符串渲染为最终的 HTML 片段,再通过 HTML 解析工具将片段转换为 OpenPDF 可识别的元素对象,最后在 PdfPageEventHelper 的 onEndPage 回调中把元素渲染到页面指定位置即可。

前置依赖

除了你已有的 OpenPDF、Thymeleaf 依赖外,还需要引入 HTML 转 PDF 元素的工具,推荐使用 Flying Saucer,和 OpenPDF 兼容性较好。

具体实现步骤

  • 第一步:封装 Thymeleaf 渲染 HTML 片段的方法,用于将模板字符串+参数转换为最终的 HTML 代码
// Thymeleaf 渲染工具示例
public String renderHtml(String templateStr, Map<String, Object> params) {
    Context context = new Context();
    context.setVariables(params);
    return templateEngine.process(templateStr, context);
}
  • 第二步:封装 HTML 片段转 OpenPDF 元素的方法
import org.xhtmlrenderer.pdf.ITextRenderer;
import com.lowagie.text.Element;
import java.io.ByteArrayInputStream;
import java.util.List;

public List<Element> htmlToElements(String html) throws Exception {
    ITextRenderer renderer = new ITextRenderer();
    renderer.setDocument(new ByteArrayInputStream(html.getBytes("UTF-8")), null);
    renderer.layout();
    return renderer.getRootBox().getChildren();
}
  • 第三步:改造你的页面事件回调逻辑
// 提前计算好页眉、页脚高度,初始化Document时设置对应的上下边距,避免和正文重叠
float headerHeight = 50f;
float footerHeight = 30f;
Document document = new Document(PageSize.A4, 36, 36, headerHeight + 10, footerHeight + 10);

writer.setPageEvent(new PdfPageEventHelper() {
    @Override
    public void onEndPage(PdfWriter writer, Document document) {
        try {
            PdfContentByte cb = writer.getDirectContent();
            // 渲染页眉HTML模板,可传入动态参数比如发票号、当前页码、总页数等
            Map<String, Object> headerParams = new HashMap<>();
            headerParams.put("invoiceNo", "XXX20240001");
            String headerHtml = renderHtml(headerTemplateStr, headerParams);
            List<Element> headerElements = htmlToElements(headerHtml);
            // 把页眉元素渲染到页面顶部指定位置
            float y = document.top() + headerHeight;
            for (Element element : headerElements) {
                cb.beginText();
                cb.setTextMatrix(document.left(), y);
                // 元素渲染逻辑可根据实际需要调整坐标
                element.process(writer, cb, document.left(), document.right(), y);
                y -= element.getTotalHeight();
                cb.endText();
            }

            // 页脚渲染逻辑和页眉一致,坐标调整到页面底部即可
            Map<String, Object> footerParams = new HashMap<>();
            footerParams.put("pageNum", writer.getPageNumber());
            String footerHtml = renderHtml(footerTemplateStr, footerParams);
            List<Element> footerElements = htmlToElements(footerHtml);
            y = document.bottom() - footerHeight;
            for (Element element : footerElements) {
                cb.beginText();
                cb.setTextMatrix(document.left(), y);
                element.process(writer, cb, document.left(), document.right(), y);
                y -= element.getTotalHeight();
                cb.endText();
            }
        } catch (Exception e) {
            throw new RuntimeException("页眉页脚渲染失败", e);
        }
    }
});

注意事项

  • 页眉页脚的 HTML 模板建议使用行内样式定义格式,Flying Saucer 对行内样式的兼容性远高于外部样式表
  • 模板中的HTML标签要严格闭合,否则会解析失败
  • 如果不需要复用HTML模板,也可以直接使用OpenPDF原生API拼接页眉页脚元素,性能会更高,但调整样式需要修改代码,灵活性更低

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.09 12:27:03