iText实现表头固定功能


前言

我在用iText 5.5.13.3这个版本做报表导出功能,遇到了一张报表需要将表头进行固定。查询了一些资料,发现似乎没有官方的资料实现了这个功能。因此,只好自己来实现了。我之前有实现过页眉页脚功能,所以我就在想能否将表头固定到页眉中,这样便可以每页都有显示。
因此我的方案就是在页眉中放一个表,再将内容表放在下方。

一、效果

在这里插入图片描述
从图中可以看出,第2页依旧有相同的页眉表格。

二、代码

package com.mieasy.chilin.es.assess.system.java2pdf.measure;

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.mieasy.chilin.es.assess.module_common.dto.MeasureList;
import com.mieasy.chilin.es.assess.system.java2pdf.utils.CellUtil;
import com.mieasy.chilin.es.assess.system.java2pdf.utils.FontUtil;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * @author Youngpine
 * @create 2024/1/14
 * @description 导出成PDF
 */
public class MeasureList2PDF {
    public static final String DEST = "C:\\Users\\youngpine\\Desktop\\simple_table.pdf";
    public static BaseFont bfChinese;
    public static Map<String, Object> resident;

    static {
        bfChinese = FontUtil.generate();
    }

    public static void createPdf(String dest, Map<String, Object> para) throws IOException, DocumentException {
        resident = (Map<String, Object>)para.get("resident");
        List<MeasureList> list = (List<MeasureList>) para.get("list");
        Document document = new Document();
        // 这一步很关键,默认创建的document的边距都为36f,但是如果页眉表格占用太宽,
        // 就会内容和表头重叠,因此设定上边距为页眉表格headerTable的高度,即可以通
        // 过headerTable.getTotalheight()来获取
        document.setMargins(36f, 36f, 114f, 16f);
        document.setPageSize(PageSize.A4.rotate());

        // 获取文档的页大小
        Rectangle pageSize = document.getPageSize();

        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));

        // 添加页事件处理器
        HeaderFooterPageEvent event = new HeaderFooterPageEvent();
        writer.setPageEvent(event);

        // 打开文档,添加内容
        document.open();

		// 创建一个字体
        Font font = new Font(bfChinese, 11, Font.NORMAL, BaseColor.BLACK);

        // 创建表格
        PdfPTable table = new PdfPTable(14);
        table.setWidthPercentage(100);
        table.setTotalWidth(pageSize.getWidth() - document.leftMargin() - document.rightMargin()); // 计算出表的宽度,实际为了和页面中的headerTable宽度保持一直
        table.setSpacingBefore(10f); // 前间距
        table.setSpacingAfter(10f); // 后间距


        for (int i = 0; i < 100; i++) {
            table.addCell(generateTitle("test", 1, 1, font));
            table.addCell(generateTitle("test", 1, 1, font));
            table.addCell(generateTitle("test", 1, 1, font));
            table.addCell(generateTitle("test", 1, 1, font));
            table.addCell(generateTitle("test", 1, 1, font));
            table.addCell(generateTitle("test", 1, 1, font));
            table.addCell(generateTitle("test", 1, 1, font));
            table.addCell(generateTitle("test", 1, 1, font));
            table.addCell(generateTitle("test", 1, 1, font));
            table.addCell(generateTitle("test", 1, 1, font));
            table.addCell(generateTitle("", 1, 1, font));
            table.addCell(generateTitle("test", 1, 1, font));
            table.addCell(generateTitle("test", 1, 1, font));
            table.addCell(generateTitle("test", 1, 1, font));
        }

        document.add(table);

        document.close();
    }

	// 内部类,用于在PDF关闭时往里面加数据
    private static class HeaderFooterPageEvent extends PdfPageEventHelper{
        @Override
        public void onEndPage(PdfWriter writer, Document document) {
            // 获取文档的页大小
            Rectangle pageSize = document.getPageSize();

            // 创建页眉表格
            PdfPTable headerTable = new PdfPTable(14);
            headerTable.setWidthPercentage(100f);
            headerTable.setTotalWidth(pageSize.getWidth() - document.leftMargin() - document.rightMargin()); // 计算表格宽度

            Font font = new Font(bfChinese, 12, Font.NORMAL, BaseColor.BLACK);
            Font fontBold = new Font(bfChinese, 12, Font.BOLD, BaseColor.BLACK);

            headerTable.addCell(generateTitleNoBorder("服務", 1, 2, fontBold));
            headerTable.addCell(CellUtil.generateEmptyCell(10));
            headerTable.addCell(generateTitleNoBorder("資料", 1, 2, fontBold));

            headerTable.addCell(generateTitleNoBorder("(院)", 1, 2, font));
            headerTable.addCell(CellUtil.generateEmptyCell(4));
            headerTable.addCell(generateTitleNoBorder("記錄", 1, 2, fontBold));
            headerTable.addCell(CellUtil.generateEmptyCell(6));

            headerTable.addCell(CellUtil.generateTitleRightMiddle("姓名:", 2, font));
            headerTable.addCell(CellUtil.generateContent("123", 3, font));
            headerTable.addCell(CellUtil.generateTitleRightMiddle("性别:", 1, font));
            headerTable.addCell(CellUtil.generateContent("123", 1, font));
            headerTable.addCell(CellUtil.generateTitleRightMiddle("年龄:", 1, font));
            headerTable.addCell(CellUtil.generateContent("123", 2, font));
            headerTable.addCell(CellUtil.generateTitleRightMiddle("房號:", 2, font));
            headerTable.addCell(CellUtil.generateContent("123", 2, font));

            // 添加内容到表格(这里可以添加你需要的内容)
            headerTable.addCell(generateTitle("title", 2, 1, font));
            headerTable.addCell(generateTitle("title", 2, 1, font));
            headerTable.addCell(generateTitle("title", 1, 1, font));
            headerTable.addCell(generateTitle("title", 1, 1, font));
            headerTable.addCell(generateTitle("title", 1, 1, font));
            headerTable.addCell(generateTitle("title", 1, 1, font));
            headerTable.addCell(generateTitle("title", 1, 1, font));
            headerTable.addCell(generateTitle("title", 1, 1, font));
            headerTable.addCell(generateTitle("title", 1, 2, font));
            headerTable.addCell(generateTitle("title", 1, 2, font));
            headerTable.addCell(generateTitle("title", 1, 1, font));
            headerTable.addCell(generateTitle("title", 2, 1, font));

            headerTable.addCell(generateTitle("title", 1, 1, font));
            headerTable.addCell(generateTitle("title", 1, 1, font));
            headerTable.addCell(generateTitle("title", 1, 1, font));
            headerTable.addCell(generateTitle("title", 1, 1, font));
            headerTable.addCell(generateTitle("title", 1, 1, font));
            headerTable.addCell(generateTitle("title", 1, 1, font));
            headerTable.addCell(generateTitle("title", 1, 1, font));
            headerTable.addCell(generateTitle("title", 1, 1, font));
            headerTable.addCell(generateTitle("title", 1, 1, font));
            headerTable.addCell(generateTitle("title", 1, 1, font));
            headerTable.addCell(generateTitle("title", 1, 1, font));

			// 定位页眉表格的起始坐标
            float x = (pageSize.getLeft() + pageSize.getRight()) / 2 - headerTable.getTotalWidth() / 2;
            float y = pageSize.getTop() - 8f;

            // 将表格添加到文档
            headerTable.writeSelectedRows(0, -1, x, y, writer.getDirectContent());

            PdfContentByte cb = writer.getDirectContent();
            cb.beginText();
            cb.setFontAndSize(bfChinese, 12);
            // 页脚右侧写入页码
            Phrase pageNum = new Phrase(writer.getPageNumber() + "");
            cb.showTextAligned(Element.ALIGN_RIGHT, pageNum.getContent(), document.right(), document.bottom() - 10, 0);
            cb.endText();
        }
    }

	// 生成一个单元格内容的工具代码
    public static PdfPCell generateTitle(String title, int rowspan, int colspan, Font font) {
        PdfPCell cell = new PdfPCell(new Phrase(title, font));
        cell.setRowspan(rowspan);
        cell.setColspan(colspan);
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        cell.setMinimumHeight(20f);
        return cell;
    }

    public static PdfPCell generateTitleNoBorder(String title, int rowspan, int colspan, Font font) {
        PdfPCell cell = new PdfPCell(new Phrase(title, font));
        cell.setRowspan(rowspan);
        cell.setColspan(colspan);
        cell.setBorder(Rectangle.NO_BORDER);
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        return cell;
    }
}

总结

本文记录了用iText进行PDF导出时做一个固定表头的功能,这个功能就是通过在页眉中插入一个表头。若有人有其他方案,欢迎分享。

### 使用 iTextPDF 实现复杂报表导出的功能 #### 创建 PDF 表格并填充动态数据 为了实现复杂的报表导出功能,可以通过创建 PDF 表格来处理固定和动态的数据。首先需要构建一个基础的 PDF 文档结构,并利用 `PdfPTable` 来设计表格布局[^1]。 以下是基于 iTextPDF 的代码示例: ```java import com.itextpdf.text.Document; import com.itextpdf.text.PageSize; import com.itextpdf.text.pdf.PdfPCell; import com.itextpdf.text.pdf.PdfPTable; import com.itextpdf.text.pdf.PdfWriter; import java.io.FileOutputStream; public class ComplexReportExample { public static void main(String[] args) { Document document = new Document(PageSize.A4); try (FileOutputStream fos = new FileOutputStream("complex_report.pdf")) { PdfWriter.getInstance(document, fos); document.open(); PdfPTable table = new PdfPTable(3); // 定义三列的表格 PdfPCell cell = new PdfPCell(); // 单元格对象 cell.setPhrase(new Phrase("Header Spanning Three Columns")); // 设置表头内容 cell.setColspan(3); // 跨越三列 cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER); // 居中显示 table.addCell(cell); addRow(table, "Column 1", "Column 2", "Column 3"); // 添加表头行 addDataRows(table); // 动态添加数据行 document.add(table); } catch (Exception e) { System.err.println(e.getMessage()); } document.close(); } private static void addRow(PdfPTable table, String... cells) { for (String cell : cells) { table.addCell(cell); } } private static void addDataRows(PdfPTable table) { for (int i = 0; i < 10; i++) { // 假设我们有十行数据 addRow(table, "Row " + (i + 1), "Value A", "Value B"); } } } ``` 上述代码展示了如何使用 iTextPDF 构建带有表头和多行数据的复杂报表[^3]。 --- #### 处理动态数据与样式调整 当面对长度不固定的表格类数据时,可以采用循环机制动态生成每一行的内容。此外,还可以通过设置单元格属性(如字体大小、颜色、边框等),使报表更加美观。 例如,在上面的例子中,我们可以进一步优化单元格样式如下所示: ```java cell.setBorderColor(BaseColor.LIGHT_GRAY); // 边框颜色 cell.setBackgroundColor(BaseColor.GRAY); // 背景颜色 cell.setPadding(8f); // 内部间距 ``` --- #### 将 PDF 输出到浏览器响应流 如果希望将生成的 PDF 文件直接返回给客户端下载,则可以在 Servlet 或 Spring Controller 中完成此操作[^2]。下面是一个简单的控制器方法示例: ```java @Controller @RequestMapping("/export") public class ExportController { @GetMapping(value = "/report", produces = "application/pdf") public void export(HttpServletResponse response) throws Exception { response.setContentType("application/pdf"); response.setHeader("Content-Disposition", "attachment; filename=report.pdf"); Document document = new Document(); PdfWriter writer = PdfWriter.getInstance(document, response.getOutputStream()); document.open(); PdfPTable table = new PdfPTable(3); table.setWidthPercentage(100); PdfPCell header = new PdfPCell(new Phrase("Sample Report")); header.setColspan(3); header.setHorizontalAlignment(Element.ALIGN_CENTER); table.addCell(header); addRow(table, "ID", "Name", "Description"); addDataRows(table); document.add(table); document.close(); writer.flush(); } private void addRow(PdfPTable table, String... cells) { for (String cell : cells) { table.addCell(cell); } } private void addDataRows(PdfPTable table) { for (int i = 0; i < 5; i++) { addRow(table, Integer.toString(i + 1), "Item " + (i + 1), "This is item description."); } } } ``` 该示例演示了如何结合 HTTP 请求参数以及后端业务逻辑来自动生成个性化报告[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值