You are here
Home > Spring Boot >

How to Generate Dynamic PDF Report using Spring Boot?

How to Generate Dynamic PDF Report using Spring BootAlmost every client expects the report of data as it is in the database. The most popular & user-friendly reports are PDF & Excel. Here, in this article, we will learn how to generate dynamic PDF report. We will fetch all values from the database, no hard-coding will be done. Further to escape from hard-coding we will take some of the values from properties file. In this way we don’t need to modify the java file in case we have some change requests in future. Let’s get into the topic “How to Generate Dynamic PDF Report using Spring Boot”.

Here we will use Spring Boot to generate our dynamic PDF. However, you can easily utilize the code from this example to generate PDF in any other framework of Java. Moreover, you can generate in a Simple Servlet application also using this spring boot pdf generation example.

What all functionalities will you get in generated PDF?

1) All contents in the PDF which are appearing as static, are actually dynamic. Moreover It is designed in such a way that you don’t need to make changes in your source code. You just have to provide entries of dynamic values in application.properties file accordingly.
2) You can easily replace the Logo on the upper right corner.
3) The header line of the PDF “Employee-Report” is dynamic & can be changed.
4) Also, Number of columns in the PDF table can be updated as per your need.

5) You can easily replace the Name of Table columns as per your need.
6) Values in the PDF table are dynamic & taken from the database.
7) Moreover, any prefix can be added to update all values of a particular column. It is like ‘$’ symbol as a prefix in the ‘Emp Sal’ column.
8) We can also update PDF footer easily.
9) The next important thing, We can have the PDF file name suffixed or prefixed with the current date.

What will you learn after implementing this application?

1) Where to use Annotations such as @Value, @Query, @Autowired, @Component, @Entity, @Id etc. ?
2) How to work with application.properties file?
3) In addition, How to inject values from properties file as an Array & List?
4) How to write code without hard-coding the values using Spring Boot?
5) Also, How to use List.Of() method introduced in JDK9?
6) How to include any prefix dynamically in all values of a particular column?
7) Equally important, How to write modular & reusable code?
8) How to implement dynamic code with minimal changes, keeping future change requests in mind?
9) Last but not the least you will learn “How to Generate Dynamic PDF Report using Spring Boot?”.

Software Used in this project?

♦ STS (Spring Tool Suite) : Version-> 4.7.1.RELEASE
⇒ Dependent Starters : Spring Data JPA, MySQL Driver, Spring Configuration Processor
♦ MySQL Database : Version ->8.0.19 MySQL Community Server
♦ JDK8 or later versions (Extremely tested on JDK8, JDK9 and JDK14)

External Dependencies

We will add following ‘iText’ dependency in pom.xml as it is an external jar to get the features of PDF.

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

You can find this dependency from itext mvn repository.

Pre-requisites

You should already have a database in order to fetch values from there. If you are not familiar with ‘how to save data into database’, you can visit to ‘Saving Data into database in a batch using Spring boot- Data JPA‘. You can also use your own database to test the functionalities accordingly.

Coding Steps

Step #1 : Create Project in STS

If you are new in Spring Boot, kindly visit Internal Link to create a sample project in spring boot.

Step #2 : Writing classes & updating application.properties

Package/Location Class/Interface name Create/Update
com.dev.springboot SpringBoot2PdfGenerationApplication.javaupdate
com.dev.springboot.modelEmployee.java create
com.dev.springboot.repositoryEmployeeRepository.java (interface)create
com.dev.springboot.util.pdfPDFGenerator.javacreate
src/main/resourcesapplication.propertiesupdate

Your project structure should look like below screenshot.

Generating dynamic PDF Report using Spring Boot

Below are the codes for each file.

application.properties
--------------------------------------------------------------------------------------------------
#------------Database properties---------------------
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mytestdb
spring.datasource.username=root
spring.datasource.password=devs

spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update


#------------PDF Genration properties---------------------
pdfDir=D:/PdfReportRepo/
reportFileName=Employee-Report
reportFileNameDateFormat=dd_MMMM_yyyy
localDateFormat="dd MMMM yyyy HH:mm:ss"
logoImgPath=D:/img_JTO_logo.jpg
logoImgScale=50,50
currencySymbol=$
table_noOfColumns=4
table.columnNames=Emp Id,Emp Name,Emp Dept,Emp Sal
PDFGenerator.java
package com.dev.springboot.util.pdf;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.dev.springboot.model.Employee;
import com.dev.springboot.repository.EmployeeRepository;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;

@Component("pdfGenerator")
public class PDFGenerator {
	
	@Value("${pdfDir}")
	private String pdfDir;
	
	@Value("${reportFileName}")
	private String reportFileName;
	
	@Value("${reportFileNameDateFormat}")
	private String reportFileNameDateFormat;
	
	@Value("${localDateFormat}")
	private String localDateFormat;
	
	@Value("${logoImgPath}")
	private String logoImgPath;
	
	@Value("${logoImgScale}")
	private Float[] logoImgScale;
	
	@Value("${currencySymbol:}")
	private String currencySymbol;
	
	@Value("${table_noOfColumns}")
	private int noOfColumns;
	
	@Value("${table.columnNames}")
	private List<String> columnNames;
	
	@Autowired
	EmployeeRepository eRepo;

	private static Font COURIER = new Font(Font.FontFamily.COURIER, 20, Font.BOLD);
	private static Font COURIER_SMALL = new Font(Font.FontFamily.COURIER, 16, Font.BOLD);
	private static Font COURIER_SMALL_FOOTER = new Font(Font.FontFamily.COURIER, 12, Font.BOLD);

	public void generatePdfReport() {

		Document document = new Document();

		try {
			PdfWriter.getInstance(document, new FileOutputStream(getPdfNameWithDate()));
			document.open();
			addLogo(document);
			addDocTitle(document);
			createTable(document,noOfColumns);
			addFooter(document);
			document.close();
			System.out.println("------------------Your PDF Report is ready!-------------------------");

		} catch (FileNotFoundException | DocumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	private void addLogo(Document document) {
		try {	
			Image img = Image.getInstance(logoImgPath);
			img.scalePercent(logoImgScale[0], logoImgScale[1]);
			img.setAlignment(Element.ALIGN_RIGHT);
			document.add(img);
		} catch (DocumentException | IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void addDocTitle(Document document) throws DocumentException {
		String localDateString = LocalDateTime.now().format(DateTimeFormatter.ofPattern(localDateFormat));
		Paragraph p1 = new Paragraph();
		leaveEmptyLine(p1, 1);
		p1.add(new Paragraph(reportFileName, COURIER));
		p1.setAlignment(Element.ALIGN_CENTER);
		leaveEmptyLine(p1, 1);
		p1.add(new Paragraph("Report generated on " + localDateString, COURIER_SMALL));

		document.add(p1);

	}

	private void createTable(Document document, int noOfColumns) throws DocumentException {
		Paragraph paragraph = new Paragraph();
		leaveEmptyLine(paragraph, 3);
		document.add(paragraph);

		PdfPTable table = new PdfPTable(noOfColumns);
		
		for(int i=0; i<noOfColumns; i++) {
			PdfPCell cell = new PdfPCell(new Phrase(columnNames.get(i)));
			cell.setHorizontalAlignment(Element.ALIGN_CENTER);
			cell.setBackgroundColor(BaseColor.CYAN);
			table.addCell(cell);
		}

		table.setHeaderRows(1);
		getDbData(table);
		document.add(table);
	}
	
	private void getDbData(PdfPTable table) {
		
		List<Employee> list = eRepo.getAllEmployeeData();
		for (Employee employee : list) {
			
			table.setWidthPercentage(100);
			table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);
			table.getDefaultCell().setVerticalAlignment(Element.ALIGN_MIDDLE);
			
			table.addCell(employee.getEmpId().toString());
			table.addCell(employee.getEmpName());
			table.addCell(employee.getEmpDept());
			table.addCell(currencySymbol + employee.getEmpSal().toString());
			
			System.out.println(employee.getEmpName());
		}
		
	}
	
	private void addFooter(Document document) throws DocumentException {
		Paragraph p2 = new Paragraph();
		leaveEmptyLine(p2, 3);
		p2.setAlignment(Element.ALIGN_MIDDLE);
		p2.add(new Paragraph(
				"------------------------End Of " +reportFileName+"------------------------", 
				COURIER_SMALL_FOOTER));
		
		document.add(p2);
	}

	private static void leaveEmptyLine(Paragraph paragraph, int number) {
		for (int i = 0; i < number; i++) {
			paragraph.add(new Paragraph(" "));
		}
	}
	
	private String getPdfNameWithDate() {
		String localDateString = LocalDateTime.now().format(DateTimeFormatter.ofPattern(reportFileNameDateFormat));
		return pdfDir+reportFileName+"-"+localDateString+".pdf";
	}
}
SpringBoot2PdfGenerationApplication.java
package com.dev.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;

import com.dev.springboot.util.pdf.PDFGenerator;

@SpringBootApplication
@ComponentScan(basePackages = {"com.dev.springboot"})
public class SpringBoot2PdfGenerationApplication {
	
	public static void main(String[] args) {
		
		ApplicationContext ac = SpringApplication.run(SpringBoot2PdfGenerationApplication.class, args);
		
		PDFGenerator pDFGenerator = ac.getBean("pdfGenerator",PDFGenerator.class);
		
		pDFGenerator.generatePdfReport();
	}
	
}
Employee.java
package com.dev.springboot.model;

import javax.persistence.Entity;
import javax.persistence.Id;


@Entity
public class Employee {

	@Id
	private Integer empId;
	private String empName;
	private Double empSal;
	private String empDept;

	public Employee() {

	}

	public Employee(Integer empId, String empName, Double empSal, String empDept) {
		super();
		this.empId = empId;
		this.empName = empName;
		this.empSal = empSal;
		this.empDept = empDept;
	}

	public Integer getEmpId() {
		return empId;
	}
	public void setEmpId(Integer empId) {
		this.empId = empId;
	}
	public String getEmpName() {
		return empName;
	}
	public void setEmpName(String empName) {
		this.empName = empName;
	}
	public Double getEmpSal() {
		return empSal;
	}
	public void setEmpSal(Double empSal) {
		this.empSal = empSal;
	}
	public String getEmpDept() {
		return empDept;
	}
	public void setEmpDept(String empDept) {
		this.empDept = empDept;
	}

}
EmployeeRepository.java
package com.dev.springboot.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import com.dev.springboot.model.Employee;

public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
			
		@Query("FROM Employee e")
		List<Employee> getAllEmployeeData();
		
}

How to run the application?

In order to run the application, right click on Project and select Run As >> Spring Boot App. Subsequently, observe the output in the console. You will see a message “—Your PDF Report is ready!——”

Testing Results

In order to test the results, go to the location where you have saved your generated PDF. Now verify the values you are expecting to appear in the PDF. Your PDF will look like below screenshot.

PDF Report

How to implement our own PDF Report from this Example with minimal changes?

We need to change values of properties included in the application.properties.

1) Update the values of the first 4 properties as per your database.

2) Then, Update the pdf file storage path in the value of property ‘pdfDir’.

3) To change the Logo on the upper right corner change the values of 2 properties : ‘logoImgPath’ & ‘logoImgScale’. ‘logoImgPath’ is for     image storage path in your system and ‘logoImgScale’ is for image scaling in percentage.

4) In order to change the Header of the PDF change the values of ‘reportFileName’.

5) To change the format of Date in the first line change the value of ‘localDateFormat’.

6) Next, To change the Number of Columns in the PDF table change the value of ‘table_noOfColumns’.

7) In order to change the Column Names of PDF table, change the values of ‘table.columnNames’. In the end, make sure that number of column names values are equal to the value of ‘table_noOfColumns’ property. Otherwise, you will get an error.

8) To change the currency from ‘$’ to any other symbol change the value of ‘currencySymbol’. However If you don’t want to include any symbol leave it blank. Any other prefix can also be included with all values of a particular column.

Below are the changes in java files :
9) In order to display dynamic database values you need to create a new Entity class, new Repository class in place of Employee.java & EmployeeRepository.java respectively.

10) Subsequently, you need to update getDbData() method of PDFGenerator.java as per your database.

Can we apply this implementation in a real project ?

Of course, you can apply this implementation in a real project if no constraints on using itextpdf library. You just have to do modifications described above according to your requirement.

What are the changes do we need to do if we want to use this functionality in our real project ?

In order to use this functionality in your real project, you have to go through the minimal modifications suggested in the above section. That is ‘How to implement our own PDF Report from this Example with minimal changes?’ of this article.

Conclusion

In this article we have covered all the theoretical and example part of ‘How to Generate Dynamic PDF Report using Spring Boot’, finally, you should be able to implement a pdf generation using Spring Boot. Similarly, we expect from you to further extend this example, as per your requirement. Also try to implement it in your project accordingly. Moreover, Feel free to provide your comments in the comments section below.

♦ Additionally, If you face any issue on running this project, don’t hesitate to put your comments below.

close

3 thoughts on “How to Generate Dynamic PDF Report using Spring Boot?

  1. You’ve made some good points there. I checked on the net for more info about the issue and found most people will go along with your views on this web site.

Leave a Reply

Top