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

使用iText生成含大PdfPTable及总页码页脚的PDF问题求助

我来帮你理清楚这个逻辑!其实带总页码的页脚核心在于总页数得等整个文档都生成完才知道,所以没法一开始就直接写死,得用「先占位、后补值」的思路来实现。结合你的代码,我给你一套完整的可运行方案:

第一步:实现页脚事件处理器

我们需要继承PdfPageEventHelper,重写几个关键方法来处理页脚的绘制和总页数的填充:

class PageFooter extends PdfPageEventHelper {
    private PdfTemplate totalPageTemplate;
    private BaseFont baseFont;

    @Override
    public void onOpenDocument(PdfWriter writer, Document document) {
        try {
            // 初始化字体,这里用中文宋体避免乱码,英文场景可以换成BaseFont.HELVETICA
            baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            // 创建一个空白模板,用来后续填充总页数
            totalPageTemplate = writer.getDirectContent().createTemplate(50, 15);
        } catch (Exception e) {
            throw new RuntimeException("初始化页脚资源失败", e);
        }
    }

    @Override
    public void onEndPage(PdfWriter writer, Document document) {
        PdfContentByte contentByte = writer.getDirectContent();
        contentByte.saveState();

        // 拼接当前页文本:"第X页,共"
        String currentPageText = "第" + writer.getPageNumber() + "页,共";
        float textWidth = baseFont.getWidthPoint(currentPageText, 12);
        // 页脚位置:页面左边缘,底部下方15个单位(可以自己调整)
        float x = document.left();
        float y = document.bottom() - 15;

        // 绘制当前页号部分
        contentByte.beginText();
        contentByte.setFontAndSize(baseFont, 12);
        contentByte.setTextMatrix(x, y);
        contentByte.showText(currentPageText);
        contentByte.endText();

        // 把总页数模板放在当前页文本的右侧,占位置
        contentByte.addTemplate(totalPageTemplate, x + textWidth, y);

        contentByte.restoreState();
    }

    @Override
    public void onCloseDocument(PdfWriter writer, Document document) {
        // 文档全部生成完毕,现在可以拿到总页数了,把它写入之前的模板
        try {
            totalPageTemplate.beginText();
            totalPageTemplate.setFontAndSize(baseFont, 12);
            totalPageTemplate.setTextMatrix(0, 0);
            // writer.getPageNumber()就是最终的总页数
            totalPageTemplate.showText(String.valueOf(writer.getPageNumber()));
            totalPageTemplate.endText();
        } catch (Exception e) {
            throw new RuntimeException("填充总页数失败", e);
        }
    }
}

第二步:主代码整合你的表格逻辑

把页脚事件注册到PdfWriter上,然后正常添加你的大表格即可(iText会自动处理表格分页,每页都会触发页脚事件):

ByteArrayOutputStream baos = new ByteArrayOutputStream();
Document document = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.getInstance(document, baos);

// 注册我们写的页脚事件
PageFooter pageFooter = new PageFooter();
writer.setPageEvent(pageFooter);

document.open();

// 初始化你的10列大表格
PdfPTable table = new PdfPTable(10);
// 这里替换成你填充表格的实际代码,比如循环添加大量行
for (int row = 0; row < 100; row++) {
    for (int col = 0; col < 10; col++) {
        table.addCell("单元格 " + (row + 1) + "-" + (col + 1));
    }
}

// 把表格添加到文档,iText会自动处理分页
document.add(table);

// 关闭文档和writer,这一步会触发onCloseDocument方法填充总页数
document.close();
writer.close();

// 后续你可以把baos中的内容输出为PDF文件,比如:
// FileOutputStream fos = new FileOutputStream("带页脚的表格.pdf");
// baos.writeTo(fos);
// fos.close();

关键逻辑说明

  1. PdfTemplate的作用:相当于一个“动态占位符”,因为总页数只有在文档完全生成后才能确定,所以先在每页页脚放这个模板,等文档写完再把总页数填进去。
  2. PageEvent的三个方法:
    • onOpenDocument:初始化字体和模板,确保整个文档生命周期内可用。
    • onEndPage:每一页结束时触发,绘制当前页号并放置总页数模板。
    • onCloseDocument:文档关闭前触发,此时已经知道总页数,把它写入模板。
  3. 大表格自动分页:PdfPTable会自动拆分跨页的内容,不需要你手动处理,每页都会自动触发页脚事件,所以所有页面都会有正确的页脚。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:00:54