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);
我正在使用 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);