Spring Boot中用openhtmltopdf-pdfbox为PDF添加每页页眉页脚图片
为openhtmltopdf生成的PDF添加页眉页脚图片
方法一:使用CSS @page 结合运行元素(推荐)
openhtmltopdf支持CSS Paged Media规范,通过定义**运行元素(running elements)**和@page规则,可实现每页重复的页眉页脚。
步骤1:修改输入HTML,添加页眉页脚结构与样式
在你的inputHTMlString中插入以下内容(和原有HTML内容拼接):
<style> /* 定义运行元素,用于存储页眉页脚内容 */ .header-image { position: running(header); width: 100%; height: 50px; /* 根据实际图片尺寸调整 */ } .footer-image { position: running(footer); width: 100%; height: 40px; /* 根据实际图片尺寸调整 */ } /* 配置页面布局,预留页眉页脚空间 */ @page { size: A4; margin: 70px 20px 60px 20px; /* 上下边距需大于页眉页脚高度,避免内容重叠 */ /* 调用运行元素作为页眉 */ @top-center { content: element(header); } /* 调用运行元素作为页脚 */ @bottom-center { content: element(footer); } } body { margin: 0; } </style> <!-- 页眉图片容器(仅渲染一次,每页自动调用) --> <div class="header-image"> <img src="header-logo.png" alt="页眉图片" style="width: 100%; height: 100%; object-fit: contain;" /> </div> <!-- 页脚图片容器 --> <div class="footer-image"> <img src="footer-logo.png" alt="页脚图片" style="width: 100%; height: 100%; object-fit: contain;" /> </div> <!-- 原有业务HTML内容 --> <div class="content"> <!-- 这里放你从数据库获取的原有HTML内容 --> </div>
注意事项
- 图片路径需确保
baseUri可访问:你的代码中baseUri来自CORRESPONDANCE_PATH配置,需将图片放在该目录下,或使用绝对路径。 - 页边距设置必须足够大,防止主内容与页眉页脚重叠。
- 若需动态替换图片路径,可在拼接HTML时替换
src属性的值。
方法二:通过Java代码自定义PageSupplier
如果CSS方式无法满足需求,可直接通过Java代码控制每页的页眉页脚绘制。
步骤1:实现PageSupplier接口
创建自定义PageSupplier,在每页绘制时添加图片:
import com.openhtmltopdf.pdfboxout.PdfBoxPageSupplier; import com.openhtmltopdf.pdfboxout.PdfBoxRenderer; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; import java.io.File; import java.io.IOException; public class CustomPageSupplier implements PdfBoxPageSupplier { private final String headerImagePath; private final String footerImagePath; public CustomPageSupplier(String headerImagePath, String footerImagePath) { this.headerImagePath = headerImagePath; this.footerImagePath = footerImagePath; } @Override public PDPage createPage(PdfBoxRenderer renderer, int pageIndex) { return new PDPage(renderer.getDefaultPageSize()); } @Override public void drawPage(PdfBoxRenderer renderer, PDPage page, int pageIndex, PDDocument document) throws IOException { // 绘制页眉图片 PDImageXObject headerImage = PDImageXObject.createFromFile(headerImagePath, document); try (PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.PREPEND, true, true)) { float pageHeight = page.getMediaBox().getHeight(); // 调整坐标和缩放比例,适配你的图片尺寸和页面布局 contentStream.drawImage(headerImage, 20, pageHeight - 50 - 20, headerImage.getWidth() * 0.5f, 50); // 绘制页脚图片 PDImageXObject footerImage = PDImageXObject.createFromFile(footerImagePath, document); contentStream.drawImage(footerImage, 20, 20, footerImage.getWidth() * 0.5f, 40); } } }
步骤2:修改xhtmlToPdf方法,配置自定义PageSupplier
public void xhtmlToPdf(Document doc, String filePath) throws IOException { String str = applicationRepository.findByApplicationKey("CORRESPONDANCE_PATH").getApplicationValue(); String baseUri = FileSystems.getDefault().getPath(str).toUri().toString(); // 拼接图片路径,根据实际存储位置调整 String headerImgPath = str + File.separator + "header-logo.png"; String footerImgPath = str + File.separator + "footer-logo.png"; OutputStream os = new FileOutputStream(filePath); PdfRendererBuilder builder = new PdfRendererBuilder(); builder.toStream(os); builder.withW3cDocument(doc, baseUri); // 绑定自定义PageSupplier builder.usePageSupplier(new CustomPageSupplier(headerImgPath, footerImgPath)); builder.run(); os.close(); }
注意事项
- 确保程序对图片路径有读取权限。
- 绘制坐标需根据页面尺寸(A4默认宽595、高842)调整,避免位置偏移。
- 使用
AppendMode.PREPEND保证页眉页脚在内容底层,不会被覆盖。
常见问题排查
- CSS方式不生效:检查CSS Paged Media语法是否正确,openhtmltopdf对部分复杂CSS特性支持有限,尽量使用简洁的选择器和属性。
- 图片不显示:确认图片路径正确,
baseUri指向的目录包含目标图片,或直接使用绝对路径。 - 内容与页眉页脚重叠:调整@page的margin值,确保主内容区域处于页眉页脚之外。
内容的提问来源于stack exchange,提问作者swapnil skate
相关产品推荐
相关产品推荐

