Nobody can deny from the fact that data is everything for an application. If there is no data, no need of an application. Since data is everything for an application, we need to know each & every way where & how we can import/export data. Many a time, almost every client needs the data in the form of text reports.
When we talk about reports in a web application from the front-end, two popular reports come into mind: Excel Report, and the PDF report. Spring Boot has an integration with Excel & PDF and offers us an API to create such type of reports easily. In this article, we are going to learn about โHow to export data into PDF in a Spring Boot MVC Application?โ.
Moreover, we will also provide you all the steps to build a MVC pattern based web App starting from user interface till the data layer. Obviously, our final goal is to learn โHow to export data into PDF in a Spring Boot MVC Application?โ. As a development part, we will start with building an MVC based web App and end with creating an PDF report using the API provided by Spring Boot. Letโs discuss our topic โHow to export data into PDF in a Spring Boot MVC Application?โ and the related concepts.
What all Technology & Software we used?
โฆ STS (Spring Tool Suite) : Version-> 4.7.1.RELEASE
โ Dependent Starters : โSpring Webโ, โSpring Data JPAโ, โMySQL Driverโ, โThymeleafโ, โLombokโ and โSpring Boot DevToolsโ
โฅ User Interface : Thymeleaf, Bootstrap, Font-Awesome
โฆ MySQL Database : Version ->8.0.19 MySQL Community Server
โฆ JDK8 or later versions (Extremely tested on JDK8, JDK9 and JDK14)
iText Dependency
We require below two dependencies to be added at pom.xml.
<!-- https://mvnrepository.com/artifact/com.lowagie/itext --> <dependency> <groupId>com.lowagie</groupId> <artifactId>itext</artifactId> <version>2.1.7</version> </dependency>
What is PDF Export functionality in a Web Application?
In a web application, we generally have some pages where we show data directly or indirectly mapped to the database. We store these data into the database once the user fills some data in the UI and submits the same. Sometimes we have a requirement to get all data from the UI and save it into a PDF file. In short, we generally call this functionality as an PDF Export. Now-a-days, having this functionality in an application becomes more popular.
What will be the output of the PDF Export functionality?
When we click on the Export PDF icon given in the โList Of Invoicesโ page, we will get the PDF downloaded. Below is the output that we can expect after implementing this functionality in the form of PDF as a whole.
How doesย Spring Boot internally work with iText API?
No doubt, When we use the inbuilt functionality of Spring Boot to export PDF, the whole process becomes very easy to implement and coding steps also reduces. In fact, Spring Boot has integration with iText API to make the PDF generation process easy. We only need to create PDF specific components such as header, footer and title by using iTextย API. Rest of the process is handled by Spring Boot itself.
As a part of MVC pattern, Spring Boot classifies PDF generation as a View. There is an interface โorg.springframework.web.servlet.Viewโ in Spring Boot API. An abstract class โorg.springframework.web.servlet.view.AbstractViewโ implements โorg.springframework.web.servlet.Viewโ. Furthermore, โorg.springframework.web.servlet.view.document.AbstractPdfViewโ extends โAbstractViewโ.ย Here, โAbstractPdfViewโ is an abstract class that we will be using to generate our Pdf. It has below abstract method in its hierarchy that we need to implement in our pdf generation class.
protected abstract void buildPdfDocument( Map<String, Object> model, Document document, PdfWriter writer, HttpServletRequest request, HttpServletResponse response) throws Exception;
If we open this method of the API, the comment above the method clearly states โApplication-provided subclasses must implement this method to populate the Pdf document, given the model.โ.
What all functionalities can you expect from this Spring Boot MVC example?
Below is the summary of page-wise functionalities that you can expect from this Spring Boot MVC CRUD Example.
Home Page
1) When the user hits the application URL into the browser, he/she will see the home page that is the entry point of the application. From Here, users will be able to visit the โInvoice registration pageโ and the โlist of All invoicesโ Page by clicking on the given links.
Invoice Registration Page
2) If user clicks on the โAdd Invoiceโ link available on the home page, he/she will redirect to the invoice registration page.
3) In the Invoice registration page, the user can fill the form and save it after clicking on the โSave Invoiceโ button. After the successful addition of the record, a message โInvoice with id: โXXXโ is added successfully !โ will be displayed at the bottom. From this page user can also visit to list of Invoice Pages after clicking on the โList Of Invoicesโ link.
4) If user clicks on the โShow All Invoicesโ link available on the home page, he/she will enter to the list of invoice Pages and can see all pre-existing invoices.
List Of Invoices Page
5) In the List Of Invoices page, we will have a link in the form of Icon that we can use to export all the data of the page in an excel sheet.
6) Apart from that, in the List Of Invoices page, user can perform โeditโ or โdeleteโ operation on the invoices. Additionally, user can also enter into the Invoice registration page after clicking on the โAdd Invoiceโ link.
7) If user clicks on the โEditโ link available at List Of Invoices page, a new form will open. User can modify the value and update it into the DB after clicking on the โUpdateโ button. After a successful update, a message โInvoice with id: โXXXโ is updated successfully !โ will be displayed at the bottom.
8) If user clicks on the โDeleteโ link available at List Of Invoices page, the record will be deleted. After successful removal of the record, a message โInvoice with id: โXXXโ is deleted successfully !โ will be displayed at the bottom.
9) From the list of Invoices page, user can go back to the home page after clicking on the โGo to Homeโ link.
Steps: How to export data into PDF in a Spring Boot MVC Application?
In order to implement the pdf export functionality, we need to have some data into a page on UI side. To achieve all this, we have divided the whole implementation into two parts as shown below.
1) Create an MVC web application using Spring Boot that supports CRUD operation and save some data from UI.
2) Implement pdf export functionality in this MVC web application.
However, if you already have a web application and want to implement pdf export functionality, you can directly go to the section โWhat are the steps to implement pdf export functionality in a Spring Boot MVC Application?โ.
What are the steps to develop a Spring Boot MVC CRUD Application?
If we develop any software following the specific steps, we minimize the chances of getting bugs. Furthermore, in case we face any issue after the implementation, we also reduce the time to fix it. Here are the common steps to develop a โSpring Boot MVC CRUD Exampleโ.
Step#1: Create a starter Project using an IDE
Create a Spring Boot starter project using any IDE like STS, Netbeans, Intellij Idea etc. While creating Starter Project select โSpring Webโ, โSpring Data JPAโ, โMySQL Driverโ, โ Thymeleafโ, โLombokโ and โSpring Boot DevToolsโ as starter project dependencies. Here โLombokโ and โSpring Boot Dev Toolsโ are optional to add.
Step#2: Update application.properties or application.yml
The next step to update either application.properties or application.yml whichever is applicable. Here we need to provide datasource details like DB driver class name, DB url, DB username and DB password. Additionally, we can provide other configuration properties such as dialect, ddl-auto, show-sql etc. However, as we are talking about a basic MVC application, our purpose to update this file is just to connect through the database.
Step#3: Create Entity (model) class
Now, itโs the first step to start coding. Itโs a recommendation that we should start with Entity class.
Step#4: Create Repository Interface for DB access
In order to access the database programmatically, we need to create one Repository Interface that will extend any Repository Interface provided by Spring Data JPA such as JpaRepository, CrudRepository, PagingAndSortingRepository etc. as per our requirement. However, for a basic CRUD operation, we donโt need to write any custom method in this interface. Spring Data JPA will provide all the methods by default that we require in a standard CRUD operation.
Step#5: Create Service Interface & Service Impl classes
Now we are in the Service Layer of the application. Here, we need to create one Service Interface and its Implementation class. Annotate this class with @Service to inform Spring Container that this class will act as a service. In order to connect to Data Layer, we need to provide dependency of the Repository interface (created in Step#4) in our service implementation class via auto-wiring.
Step#6: Create Controller class
Having followed the above steps, once we complete flow of data access, at the last, we need to create a Controller class to handle requests coming from the browser. Annotate this class with @Controller to inform Spring Container that this is a controller. The controller class will have handler methods to serve the requests for performing various operations involved in CRUD with the help of other layers. Please note that the Controller class will connect to the service layer via auto-wiring of Service Interface.
Step#7: Create pages as part of view
In this step, we need to develop user interface part from where a user interacts with the application to perform various operations included in the CRUD. Moreover, any request made by the user from UI page will be handed over to the Controller. Subsequently, based on the request nature, the controller will connect to service layer to serve the request accordingly. However, we can develop Step#6 and Step#7 interchangeably as both are dependent on each other.
Spring Boot MVC CRUD Application Example
Use-case Details
Letโs assume that we have to develop an Invoice Processing Application. As the application name suggests, we must have an Invoice entity in this application. In this example, we will develop CRUD operations for Invoice as an entity accordingly.
Letโs develop Spring Boot MVC CRUD Example step by step as below:
Step#1: Create a Spring Boot Starter Project using STS
Here, we are using STS (Spring tool Suite) as an IDE to develop the example. While creating Starter Project select โSpring Webโ, โSpring Data JPAโ, โMySQL Driverโ, โThymeleafโ, โLombokโ and โSpring Boot DevToolsโ as starter project dependencies. Here โLombokโ and โSpring Boot Dev Toolsโ are optional to add. Even If you donโt know how to create Spring Boot Starter Project, Kindly visitย Internal Link.ย Also, if you want to know more about Lombok, then visit internal article on โHow To Work With Lombok Annotations?โ.
Step#2: Update application.properties
Letโs update application.properties that we already have after creating the starter project in step#1. For example, we need to include below entries.
application.properties
server.port=8888 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/invoice-mvc spring.datasource.username=root spring.datasource.password=**** spring.jpa.show-sql=true spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect spring.jpa.hibernate.ddl-auto=update
Step#3: Create Entity (model) class
Since our use-case for this example is Invoice Processing, we will create an entity class as Invoice.java as below.
Invoice.java
package com.dev.springboot.model; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Entity @Data @NoArgsConstructor @AllArgsConstructor public class Invoice { @Id @GeneratedValue private Long id; private String name; private String location; private Double amount; }
Step#4: Create Repository Interface for DB access
Next step is to create one Repository Interface. Please note that we should create a separate repository interface for each Entity in the application. This is also applicable for classes taking part in other layers accordingly. Since we have only one Entity, we will create one Repository Interface for now. As a naming convention, we will create a repository interface as InviceRepository.java as below.
InvoiceRepository.java
package com.dev.springboot.repo; import org.springframework.data.jpa.repository.JpaRepository; import com.dev.springboot.model.Invoice; public interface InvoiceRepository extends JpaRepository<Invoice, Long> { }
Step#4A: Create a custom Exception class
However, this is an additional step to handle exceptions if any user search for an Invoice by Invoice Id and the same doesnโt exist at all. Letโs assume that a user search from the browser using direct URL, then there is a possibility that the invoice may not exist. In order to handle this scenario, we need to provide the user a readable message. It is possible with the help of creating a custom exception class. For example, below code demonstrates the concept of creating a custom exception.
InvoiceNotFoundException.java
package com.dev.springboot.exception; public class InvoiceNotFoundException extends RuntimeException { private static final long serialVersionUID = 1L; public InvoiceNotFoundException() { super(); } public InvoiceNotFoundException(String customMessage) { super(customMessage); } }
Step#5: Create Service Interface & Service Impl classes
As part of service layer, we need to create an interface and its implementation. Donโt forget to include @Service at the top of the service implementation class. Additionally, inject the dependency of the Repository interface via @Autowired. For example, below code demonstrates the concept behind the service layer. As a convention, the service interface should start with the letter โIโ to be recognized as an interface. Subsequently, the service implementation class should have a suffix โImplโ in its name as shown below.
IInvoiceService.java
package com.dev.springboot.service; import java.util.List; import com.dev.springboot.model.Invoice; public interface IInvoiceService { public Invoice saveInvice(Invoice invoice); public List<Invoice> getAllInvoices(); public Invoice getInvoiceById(Long id); public void deleteInvoiceById(Long id); public void updateInvoice(Invoice invoice); }
InvoiceServiceImpl.java
package com.dev.springboot.service.impl; import java.util.List; import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.dev.springboot.exception.InvoiceNotFoundException; import com.dev.springboot.model.Invoice; import com.dev.springboot.repo.InvoiceRepository; import com.dev.springboot.service.IInvoiceService; @Service public class InvoiceServiceImpl implements IInvoiceService{ @Autowired private InvoiceRepository repo; @Override public Invoice saveInvice(Invoice invoice) { return repo.save(invoice); } @Override public List<Invoice> getAllInvoices() { return repo.findAll(); } @Override public Invoice getInvoiceById(Long id) { Optional<Invoice> opt = repo.findById(id); if(opt.isPresent()) { return opt.get(); } else { throw new InvoiceNotFoundException("Invoice with Id : "+id+" Not Found"); } } @Override public void deleteInvoiceById(Long id) { repo.delete(getInvoiceById(id)); } @Override public void updateInvoice(Invoice invoice) { repo.save(invoice); } }
Step#6: Create Controller class
In order to handle various requests of a client, we need to create a controller as InvoiceController.java. Each handler method will return a UI page based on the criteria it implemented for. For example, below code snippet of InvoiceController will demonstrate the relation between UI page and the controller.
InvoiceController.java
package com.dev.springboot.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import com.dev.springboot.exception.InvoiceNotFoundException; import com.dev.springboot.model.Invoice; import com.dev.springboot.service.IInvoiceService; @Controller @RequestMapping("/invoice") public class InvoiceController { @Autowired private IInvoiceService service; @GetMapping("/") public String showHomePage() { return "homePage"; } @GetMapping("/register") public String showRegistration() { return "registerInvoicePage"; } @PostMapping("/save") public String saveInvoice( @ModelAttribute Invoice invoice, Model model ) { service.saveInvice(invoice); Long id = service.saveInvice(invoice).getId(); String message = "Record with id : '"+id+"' is saved successfully !"; model.addAttribute("message", message); return "registerInvoicePage"; } @GetMapping("/getAllInvoices") public String getAllInvoices( @RequestParam(value = "message", required = false) String message, Model model ) { List<Invoice> invoices= service.getAllInvoices(); model.addAttribute("list", invoices); model.addAttribute("message", message); return "allInvoicesPage"; } @GetMapping("/edit") public String getEditPage( Model model, RedirectAttributes attributes, @RequestParam Long id ) { String page = null; try { Invoice invoice = service.getInvoiceById(id); model.addAttribute("invoice", invoice); page="editInvoicePage"; } catch (InvoiceNotFoundException e) { e.printStackTrace(); attributes.addAttribute("message", e.getMessage()); page="redirect:getAllInvoices"; } return page; } @PostMapping("/update") public String updateInvoice( @ModelAttribute Invoice invoice, RedirectAttributes attributes ) { service.updateInvoice(invoice); Long id = invoice.getId(); attributes.addAttribute("message", "Invoice with id: '"+id+"' is updated successfully !"); return "redirect:getAllInvoices"; } @GetMapping("/delete") public String deleteInvoice( @RequestParam Long id, RedirectAttributes attributes ) { try { service.deleteInvoiceById(id); attributes.addAttribute("message", "Invoice with Id : '"+id+"' is removed successfully!"); } catch (InvoiceNotFoundException e) { e.printStackTrace(); attributes.addAttribute("message", e.getMessage()); } return "redirect:getAllInvoices"; } }
Step#7: Create pages for view
Last part of our example is to create UI pages that will help users to interact with the application. Here, we have four pages : homePage.html as an entry point of the application, registerInvoicePage.html to fill the form and register an Invoice, allInvoicesPages.html to see the list of registered invoices, and editInvoicePage.html to update the data of any invoice accordingly.
homePage.html
registerInvoicePage.html
allInvoicesPage.html
editInvoicePage.html
What are the steps to implement pdf export functionality in a Spring Boot MVC Application?
As we have already built a Spring Boot web based MVC application, now in this section we will particularly talk about the changes that we need to do to get the pdf export functionality implemented. Moreover, this section is very specific to our article โHow to export data into PDF in a Spring Boot MVC Application?โ. Letโs do it step by step as shown below.
Step#1: Add iText dependency to pom.xml
First of all add below iText dependencies to pom.xml.
<!-- https://mvnrepository.com/artifact/com.lowagie/itext --> <dependency> <groupId>com.lowagie</groupId> <artifactId>itext</artifactId> <version>2.1.7</version> </dependency>
Step#2: Create a class to implement pdf export functionality
In order to implement pdf export functionality, we will create a class, letโs say InvoiceDataPdfExport.java that will extend AbstractPdfView.java as below. As aforementioned, AbstractPdfView is provided by Spring framework under package โorg.springframework.web.servlet.view.documentโ.
package com.dev.springboot.view; import java.awt.Color; import java.util.Date; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.view.document.AbstractPdfView; import com.dev.springboot.model.Invoice; import com.lowagie.text.Document; import com.lowagie.text.Element; import com.lowagie.text.Font; import com.lowagie.text.HeaderFooter; import com.lowagie.text.Paragraph; import com.lowagie.text.Phrase; import com.lowagie.text.pdf.PdfPTable; import com.lowagie.text.pdf.PdfWriter; public class InvoiceDataPdfExport extends AbstractPdfView { @Override protected void buildPdfMetadata(Map<String, Object> model, Document document, HttpServletRequest request) { Font headerFont = new Font(Font.TIMES_ROMAN, 20, Font.BOLD, Color.magenta); HeaderFooter header = new HeaderFooter(new Phrase("All Invoices PDF View", headerFont), false); header.setAlignment(Element.ALIGN_CENTER); document.setHeader(header); Font dateFont = new Font(Font.HELVETICA, 12, Font.NORMAL, Color.BLUE); HeaderFooter footer = new HeaderFooter(new Phrase("PDF Export Executed On : "+new Date(), dateFont), true); footer.setAlignment(Element.ALIGN_CENTER); document.setFooter(footer); } @Override protected void buildPdfDocument( Map<String, Object> model, Document document, PdfWriter writer, HttpServletRequest request, HttpServletResponse response) throws Exception { //download PDF with a given filename response.addHeader("Content-Disposition", "attachment;filename=Invoices.pdf"); //read data from controller List<Invoice> list = (List<Invoice>) model.get("list"); //create element Font titleFont = new Font(Font.TIMES_ROMAN, 24, Font.BOLD, Color.blue); Paragraph title = new Paragraph("ALL INVOICES DATA", titleFont); title.setAlignment(Element.ALIGN_CENTER); title.setSpacingBefore(20.0f); title.setSpacingAfter(25.0f); //add to document document.add(title); Font tableHead = new Font(Font.TIMES_ROMAN, 12, Font.BOLD, Color.blue); PdfPTable table = new PdfPTable(4);// no.of columns table.addCell(new Phrase("ID",tableHead)); table.addCell(new Phrase("NAME",tableHead)); table.addCell(new Phrase("LOCATION",tableHead)); table.addCell(new Phrase("AMOUNT",tableHead)); for(Invoice invoice : list ) { table.addCell(invoice.getId().toString()); table.addCell(invoice.getName()); table.addCell(invoice.getLocation()); table.addCell(invoice.getAmount().toString()); } //add table data to document document.add(table); } }
Step#3: Create a method in Controller to accept pdf export requests
Add a method as shown below in the code snippet in your InvoiceController.java. When we click on the Pdf Export link given in the UI, request will come to this method.
/*** * Export data to pdf file */ @GetMapping("/pdf") public ModelAndView exportToPdf() { ModelAndView mav = new ModelAndView(); mav.setView(new InvoiceDataPdfExport()); //read data from DB List<Invoice> list= service.getAllInvoices(); //send to pdfImpl class mav.addObject("list", list); return mav; }
Step#4: Modify UI page to send pdf export requests
Add below code snippet in allInvoicesPage.html just before the start of โtableโ tag.
<div> <a th:href="@{/invoice/pdf}" class="btn btn-success">Export data into PDF <i class="fa fa-file-pdf-o" aria-hidden="true"></i></a> </div><br/>
The structure of the project should look like below:
How to test the Application?
In order to test the application, we need to open a browser and hit the URL http://localhost:8888/invoice/. On hitting the URL, home page will get displayed. Further, we need to click on โAdd Invoiceโ link to get into the โRegister Invoicesโ page. From there, we need to add some invoices to test the pdf export functionality. Next, in the โList of Invoicesโ page, we should be able to see the PDF icon labelled as โExport data into PDFโ. In order to get the exported pdf, we need to click on that icon. Once clicked, the pdf will get downloaded by the browser.
Conclusion
In this article we have covered all the theoretical and example part of โHow to export data into PDF in a Spring Boot MVC Application?โ, finally, you should be able to build a functionality of pdf export 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.