Generating PDFs with Dynamic Tables and Images Using Java iText
This tutorial demonstrates how to generate PDF files in Java with iText by filling form templates, inserting images and charts, creating dynamic tables, handling page breaks, and adding custom page headers, footers, and watermarks for backend applications.
The article explains how to generate PDF files in Java using iText, including filling templates, adding images, dynamic tables, and handling page breaks.
Dependencies: Add iText and iText-asian Maven dependencies.
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.9</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>Data models: Two domain classes DuizhangDomain and YqTable are defined with Lombok annotations.
package com.example.demo.domain;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
@Data
@Accessors(chain = true)
public class DuizhangDomain {
private String jg;
private Integer ydz;
private Integer wdz;
private BigDecimal dzl;
}
package com.example.demo.domain;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
public class YqTable implements Serializable {
private String jg;
private Integer yqs;
}PDF generation: The main class CreatePdfEchrtsAndTableMain2 shows how to read a PDF template, set fonts, fill form fields, insert images (logo, charts), and add dynamic tables using PdfStamper and PdfWriter . It also demonstrates the need for document.newPage() to avoid overlapping content.
public void createPdfFile(HttpServletResponse response) throws IOException, DocumentException, TemplateException {
response.setHeader("Content-Disposition", "attachment; filename=测试.pdf");
OutputStream outputStream = response.getOutputStream();
ClassPathResource classPathResource = new ClassPathResource("templates/test1.pdf");
InputStream inputStream = classPathResource.getInputStream();
PdfReader reader = new PdfReader(inputStream);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
PdfStamper ps = new PdfStamper(reader, bos);
// set font
BaseFont font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
ArrayList
fontList = new ArrayList<>();
fontList.add(font);
AcroFields s = ps.getAcroFields();
s.setSubstitutionFonts(fontList);
s.setFieldProperty("jrfk", "textfont", font, null);
s.setField("jrfk", "10");
// add logo image
PdfContentByte cb = ps.getOverContent(1);
Rectangle logo = s.getFieldPositions("logo").get(0).position;
Image logoImage = Image.getInstance("https://example.com/logo.png");
logoImage.scaleToFit(logo.getWidth() + 100, logo.getHeight());
logoImage.setAbsolutePosition(logo.getLeft(), logo.getBottom());
cb.addImage(logoImage);
// ... add other images and tables ...
ps.setFormFlattening(true);
ps.close();
// fill edited PDF
reader = new PdfReader(bos.toByteArray());
Rectangle pageSize = reader.getPageSize(1);
Document document = new Document(pageSize);
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
writer.setPageEvent(new PageEvent());
document.open();
PdfContentByte cbUnder = writer.getDirectContentUnder();
PdfImportedPage pageTemplate = writer.getImportedPage(reader, 1);
cbUnder.addTemplate(pageTemplate, 0, 0);
document.newPage();
createTable(writer, document);
createTableYq(writer, document);
document.close();
outputStream.close();
}Additional helper methods createSetCell , createTable , and createTableYq build tables with headers and rows, using BaseFont , PdfPTable , and adding them to the document.
public PdfPCell createSetCell(String value, Font font) {
PdfPCell cell = new PdfPCell();
cell.setPhrase(new Phrase(value, font));
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
return cell;
}
public void createTable(PdfWriter writer, Document document) throws DocumentException, IOException {
PdfPTable table = new PdfPTable(new float[]{30, 80, 50, 50, 50});
table.setTotalWidth(520);
table.setLockedWidth(true);
table.setHorizontalAlignment(Element.ALIGN_CENTER);
// set fonts, header, rows, etc.
// ...
document.add(table);
}Alternative approach: CreatePdfEchrtsAndTableMain3 shows how to insert a blank table as a spacer instead of starting a new page when the template does not fill the first page.
public void createBlankTable(PdfWriter writer, Document document, BaseFont font, int height) throws DocumentException {
PdfPTable table = new PdfPTable(new float[]{30});
table.setTotalWidth(520);
table.setLockedWidth(true);
table.setHorizontalAlignment(Element.ALIGN_CENTER);
Font textFont = new Font(font, 10, Font.NORMAL);
PdfPCell cell = new PdfPCell(new Paragraph(" ", textFont));
cell.setBorder(Rectangle.NO_BORDER);
cell.setFixedHeight(height);
cell.setColspan(1);
table.addCell(cell);
document.add(table);
}PageEvent class: Provides page header/footer and watermark functionality, creating a template for total pages, adding page numbers, and drawing a semi‑transparent watermark.
public class PageEvent extends PdfPageEventHelper {
public int presentFontSize = 10;
public Rectangle pageSize = PageSize.A4;
public PdfTemplate total;
public BaseFont bf = null;
public Font fontDetail = null;
// ... constructors ...
@Override
public void onOpenDocument(PdfWriter writer, Document document) {
total = writer.getDirectContent().createTemplate(50, 50);
}
@Override
public void onEndPage(PdfWriter writer, Document document) {
addPage(writer, document);
addWatermark(writer);
}
public void addPage(PdfWriter writer, Document document) {
try {
if (bf == null) {
bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);
}
if (fontDetail == null) {
fontDetail = new Font(bf, presentFontSize, Font.NORMAL);
}
} catch (Exception e) { e.printStackTrace(); }
int pageS = writer.getPageNumber();
String foot1 = "第 " + pageS + " 页 /共";
Phrase footer = new Phrase(foot1, fontDetail);
float len = bf.getWidthPoint(foot1, presentFontSize);
PdfContentByte cb = writer.getDirectContent();
ColumnText.showTextAligned(cb, Element.ALIGN_CENTER, footer,
(document.rightMargin() + document.right() + document.leftMargin() - document.left() - len) / 2.0F,
document.bottom() - 20, 0);
cb.addTemplate(total, (document.rightMargin() + document.right() + document.leftMargin() - document.left()) / 2.0F,
document.bottom() - 20);
}
public void addWatermark(PdfWriter writer) {
BaseFont font = null;
try { font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); }
catch (Exception e) { e.printStackTrace(); }
PdfGState gs = new PdfGState();
gs.setFillOpacity(0.4f);
PdfContentByte content = writer.getDirectContentUnder();
content.beginText();
content.setColorFill(BaseColor.DARK_GRAY);
content.setGState(gs);
content.setFontAndSize(font, 35);
for (int j = 0; j < 3; j++) {
content.showTextAligned(Element.ALIGN_CENTER, "锦鲤飞上天测试水印", 300, 200 * (j + 1), 30);
}
content.endText();
}
@Override
public void onCloseDocument(PdfWriter writer, Document document) {
total.beginText();
total.setFontAndSize(bf, presentFontSize);
String foot2 = " " + writer.getPageNumber() + " 页";
total.showText(foot2);
total.endText();
total.closePath();
}
}Conclusion: The article provides a complete, runnable example for generating PDFs with dynamic content, suitable for backend services that need to produce reports, invoices, or any document with tables and charts.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.