Sitemap

Generating PDF Receipts in Java with iText

3 min readJul 9, 2024

In modern applications, generating PDF documents is a common requirement, especially for creating receipts, reports, or any other formatted documents. This article walks you through the process of creating a PDF receipt generator in Java using the iText library.

Press enter or click to view image in full size

Overview

We’ll implement a class, ReceiptGenerator, which generates a PDF receipt for fund transfer transactions. The PDF will include a logo, transaction details, and a timestamp. We will use iText for PDF generation and Lombok for logging.

Setting Up the Environment

First, add the iText library dependency to your pom.xml file:

<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.10</version>
</dependency>

The Receipt Generator Class

Let’s break down the ReceiptGenerator class.

@Slf4j
@Component
public class ReceiptGenerator {

@Value("${fund.transfer.receipt.download.folder}")
private String receiptDownloadPath;

@Value("${bank.receipt.companylogo.path}")
String companyLogoPath;

We use Lombok’s @Slf4j for logging and Spring's @Component to mark this class as a Spring bean. The @Value annotations inject values from the application's properties file.

Generating the Receipt

public String generateReceipt(FundTransferTransaction fundTransferTransaction, TransferStateHolder transferStateHolder) {
String downloadPath = "";
String filePath = "";

try {
downloadPath = receiptDownloadPath;
log.info("receiptDownloadPath:" + receiptDownloadPath);

final String timestamp = new SimpleDateFormat("yyyyMMddhhmm").format(new Date());
filePath = downloadPath + "Fund_Transfer" + "_" + fundTransferTransaction.getAux_no() + "_" + timestamp + ".pdf";
log.info("filePath --> " + filePath);

We start by setting the download path and file path for the PDF. The timestamp ensures each file name is unique. sample receipt name will be: Fund_Transfer_0000000001710503147678_202407020346.pdf

Setting Up the Document

        int numberOfDetails = 10;
float rowHeight = 20f;
float logoHeight = 100f;
float headerHeight = 40f;
float totalHeight = logoHeight + headerHeight + (numberOfDetails * rowHeight) + 50f;

Rectangle pageSize = new Rectangle(PageSize.A4.getWidth(), totalHeight);
Document document = new Document(pageSize);

PdfWriter.getInstance(document, new FileOutputStream(filePath));
document.open();

We calculate the custom page size based on the number of details to be included and initialize the iText Document.

Adding the Logo and Header

        Font catFont = FontFactory.getFont(FontFactory.TIMES_BOLD, 20, BaseColor.BLACK);
Font font = FontFactory.getFont(FontFactory.COURIER, 13, BaseColor.BLACK);
Font hFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD, 10, BaseColor.BLACK);

String logoPath = companyLogoPath + "Companylogo.png";
log.info("companyLogoPath:" + companyLogoPath);
Image logo = Image.getInstance(logoPath);
logo.scaleToFit(150, 100);

PdfPTable headerTable = new PdfPTable(2);
headerTable.setWidthPercentage(100);
headerTable.setWidths(new int[]{1, 4});

PdfPCell logoCell = new PdfPCell(logo);
logoCell.setBorder(Rectangle.NO_BORDER);
logoCell.setHorizontalAlignment(Element.ALIGN_LEFT);
headerTable.addCell(logoCell);

Paragraph dateParagraph = new Paragraph(String.valueOf(new Date()), hFont);
dateParagraph.setAlignment(Element.ALIGN_RIGHT);
Paragraph titleParagraph = new Paragraph("Payment Receipt", catFont);
titleParagraph.setAlignment(Element.ALIGN_RIGHT);

PdfPCell dateTitleCell = new PdfPCell();
dateTitleCell.addElement(dateParagraph);
dateTitleCell.addElement(titleParagraph);
dateTitleCell.setBorder(Rectangle.NO_BORDER);
dateTitleCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
headerTable.addCell(dateTitleCell);

document.add(headerTable);

We create and add a header table that includes the company logo and the receipt title with the current date.

Adding Transaction Details

        PdfPTable detailsTable = new PdfPTable(2);
detailsTable.setWidthPercentage(100);
detailsTable.setSpacingBefore(20f);

addDetailRow(detailsTable, "Aux No:", fundTransferTransaction.getAux_no(), font);
// Setting transaction types
String tranType = getTransactionType(fundTransferTransaction.getTnx_type());
addDetailRow(detailsTable, "Transaction Type:", tranType, font);
addDetailRow(detailsTable, "From Account:", fundTransferTransaction.getFr_acc_id(), font);
addDetailRow(detailsTable, "", fundTransferTransaction.getFr_acc_lbl(), font);
addDetailRow(detailsTable, "To Account:", fundTransferTransaction.getToAccountId(), font);
addDetailRow(detailsTable, "", fundTransferTransaction.getTo_acc_lbl(), font);
String data_14 = fundTransferTransaction.getAccountCurr() + "_" + fundTransferTransaction.getOriginal_amt();
addDetailRow(detailsTable, "Transaction Amount:", data_14, font);
addDetailRow(detailsTable, "Narration:", fundTransferTransaction.getNarrat() != null ? fundTransferTransaction.getNarrat() : "N/A", font);
addDetailRow(detailsTable, "Transaction Date:", String.valueOf(fundTransferTransaction.getAdded_date()), font);
addDetailRow(detailsTable, "Fund Transfer Status:", transferStateHolder.getTransferStates().getMessage(), font);

document.add(detailsTable);
document.close();

The transaction details are added to the PDF using a details table. The addDetailRow method ensures the details are formatted correctly.

Helper Methods

private static void addDetailRow(PdfPTable table, String label, String value, Font font) {
PdfPCell labelCell = new PdfPCell(new Phrase(label, font));
labelCell.setBorder(Rectangle.NO_BORDER);
labelCell.setHorizontalAlignment(Element.ALIGN_LEFT);

PdfPCell valueCell = new PdfPCell(new Phrase(value, font));
valueCell.setBorder(Rectangle.NO_BORDER);
valueCell.setHorizontalAlignment(Element.ALIGN_RIGHT);

table.addCell(labelCell);
table.addCell(valueCell);
}

private String getTransactionType(String tnxType) {
switch (tnxType) {
case "1":return "Own Account Fund transfer";
case "2":return "Third party Fund transfer";
case "3":return "Inter bank Fund transfer";
case "4":return "Mobile Fund transfer";
case "5":return "Overseas Fund transfer";
default:return "Fund transfer";
}
}

The addDetailRow method helps in adding rows to the details table, while the getTransactionType method maps transaction type codes to human-readable strings.

Handling Exceptions

We handle exceptions for various issues that might occur during PDF generation:

} catch (DocumentException | FileNotFoundException e) {
log.error("Error in PDF generation: ", e);
throw new RuntimeException(e);
} catch (IOException e) {
log.error("IOException: ", e);
throw new RuntimeException(e);
}

The full Code of my example work can be accessed here.

Press enter or click to view image in full size
Sample Receipt template with test data and sample logo

Conclusion

The ReceiptGenerator class demonstrates a practical approach to generating PDF receipts using iText in a Spring Boot application. Following this example, you can customize the receipt content and formatting to fit your specific requirements. Happy coding!

--

--

Isurie K. Liyanage
Isurie K. Liyanage

Written by Isurie K. Liyanage

Technical Writer | BSc. (Hons.) IT — UoM | Software Engineer