Generating and Merging PDFs with iTextPdf in a Java SpringBoot Application
This article demonstrates how to use the iTextPdf library in a Java SpringBoot project to create PDF templates, dynamically fill fixed and tabular invoice data, generate separate PDFs, and merge them into a single document, providing complete code examples and configuration details.
Background
The original project used FanRuan reports, but a new requirement demanded a lightweight PDF solution without deploying an additional reporting server. The author decided to replace the old Jasper solution with iTextPdf, which can generate PDFs directly from Java.
Solution Overview
The invoice PDF consists of two parts: fixed information (buyer, seller) and dynamic product rows. The plan is to create two PDFs—one for each part—and then concatenate them into a single document.
Specific Implementation
1. Add iTextPdf dependencies
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13.2</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>2. Design a PDF template
Use Adobe Acrobat (or any PDF form designer) to create a fillable form. Place text fields for the fixed sections and give each field a unique name; these names will be used as keys when filling the form with iTextPdf.
3. Write the Java program
The program is a simple main method for demonstration; in production it can be exposed as a SpringBoot service.
3.1 Read the template
PdfReader reader = new PdfReader("C:\\Users\\User\\Desktop\\开票预览模板.pdf");
// In production you may read from a byte[] stream instead of a file path3.2 Fill the fixed‑information template
ByteArrayOutputStream bos1 = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(reader, bos1);
AcroFields form = stamper.getAcroFields();
form.setGenerateAppearances(true);
form.setField("purName", "购买方对应公司");
// Fill other fields similarly
stamper.close();3.3 Generate the dynamic product table
Document doc = new Document(reader.getPageSize(1));
PdfWriter writer = PdfWriter.getInstance(doc, bos2);
doc.open();
PdfPTable table = new PdfPTable(2);
table.addCell("Name");
table.addCell("Age");
table.addCell("Alice");
table.addCell("25");
// Add rows from a List
>
doc.add(table);
doc.close();3.4 Merge the two PDFs
public static byte[] merge(List
files) throws DocumentException, IOException {
Document document = new Document();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
PdfCopy copy = new PdfCopy(document, bos);
document.open();
for (byte[] f : files) {
PdfReader r = new PdfReader(f);
int n = r.getNumberOfPages();
for (int i = 1; i <= n; i++) {
copy.addPage(copy.getImportedPage(r, i));
}
r.close();
}
document.close();
return bos.toByteArray();
}After generating the two byte streams ( bos1 and bos2 ), they are added to a list and passed to the merge method. The resulting byte array can be written to a file or uploaded to S3.
Post‑implementation Summary
The tutorial shows the complete workflow: add iTextPdf to the Maven project, create a fillable PDF template, programmatically populate fixed fields, build a dynamic table for product lines, and finally concatenate the PDFs. This approach eliminates the need for a separate reporting server and keeps the solution lightweight.
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.