使用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
相关产品推荐
相关产品推荐

