PDF 生成因大量记录而失败

PDF generation fails with large number of records

我正在使用 itext 7 pdf 从 jdbc 查询生成 PDF。它适用于 4000 条记录,但是一旦我们在 table 中插入 17000 条记录,我就开始 Java 内存不足 space。我一次获取所有数据,如下所示,如何修改它以使用分页查询并将所有分页结果拼接成一个 PDF。

这是我的驱动程序代码,它获取 table 名称和 HttpServlet,并将其传递给实现 ResultSetExtractor 的 class。

public void generatePDF(String tableName, HttpServletResponse response, String[] filter) throws DataAccessException, IOException {
        //Table validation logic
        String sql = "select * from table";
        mainJdbcTemplate.query(sql, paramMap,
                new StreamingPDFResultSetExtractor(response.getOutputStream(), tableName));
    }

自定义 class 实现结果集提取器。我把所有的结果集数据都弄进去,用itext生成PDF。

public class StreamingPDFResultSetExtractor implements ResultSetExtractor<Void> {

    private final OutputStream os;
    private String tableName;

    /**
     * @param os the OutputStream to stream the PDF to
     */
    public StreamingPDFResultSetExtractor(final OutputStream os, final String tableName) {
        this.os = os;
        this.tableName = tableName;
    }

    @Override
    public Void extractData(final ResultSet rs) throws SQLException {
        // Creating a PdfDocument
        PdfDocument pdfDoc = new PdfDocument(new PdfWriter(os));
        // Creating a Document and setting page size
        Document document = new Document(pdfDoc, new PageSize(2384, 3370));
        // Adding a new page
        pdfDoc.addNewPage();
        final var rsmd = rs.getMetaData();
        final var columnCount = rsmd.getColumnCount();
        try {
            log.info("Generating PDF");
            Paragraph tablename = new Paragraph(tableName);
            tablename.setFontSize(20);
            // Add table
            Table table = new Table(columnCount);
            // Set width of table
            table.setWidth(UnitValue.createPercentValue(100)).setFixedLayout();
            table.setHorizontalAlignment(HorizontalAlignment.CENTER);
            table.setTextAlignment(TextAlignment.CENTER);
            // Header Font and color
            DeviceRgb hColor = new DeviceRgb(3, 148, 252);

            for (var i = 1; i <= columnCount; i++) {
                Cell hcell = new Cell();
                hcell.add(new Paragraph(rsmd.getColumnName(i)));
                hcell.setFontSize(14);
                hcell.setBackgroundColor(hColor);
                table.addHeaderCell(hcell);
            }
            while (rs.next()) {
                for (var i = 1; i <= columnCount; i++) {
                    final var value = rs.getObject(i);
                    String v = value == null ? "" : value.toString();
                        Cell cell = new Cell();
                        cell.add(new Paragraph(v));
                        table.addCell(cell);
                    }

                }
            }
            document.add(tablename);
            document.add(table);
            document.close();
            log.info("PDF generation complete");

        } catch (Exception ex) {

            log.error("Error occurred: {0}", ex);
        }
        return null;

    }
}

您基本上可以使用 Table class 的另一个重载构造函数,它专门用于大型表。如果将布尔值设置为 true,它将 boolean 作为参数来基本上减少内存占用。请参阅此示例,了解如何在 iText 7 中完成此操作 https://kb.itextpdf.com/home/it7kb/examples/large-tables

    // The second argument determines 'large table' functionality is used
    // It defines whether parts of the table will be written before all data is added.
    Table table = new Table(UnitValue.createPercentArray(5), true);