Spring Boot Generate PDF File from HTML Template

Tags: Flying Saucer PDF pdf generate pdf ClassLoaderTemplateResolver TemplateEngine ITextRenderer Thymeleaf

In this Spring Boot tutorial we will show you the step by step guide how to implement a Spring Boot console application to generate .pdf files from HTML template files. In order to create the .pdf file we will use Thymeleaf template library to process the HTML template file then from the processed HTML file we use the Flying Saucer PDF library to generate the .pdf file.

Table of contents

  1. Create New Spring Boot Project
  2. Add Flying Saucer PDF library to the project
  3. Configure Thymeleaf
  4. Implement PDF Generate Service
  5. Add HTML template file
  6. Implement Entity classes
  7. Implement Testing Code to Generate .pdf File
  8. Complete Source Code and Run The Application
  9. Download Source Code

Create New Spring Boot Project

Open IntelliJ IDEA, select the menu File > New > Project.

On the New Project dialog, select Spring Initializr and click Next button.

Spring Boot Generate PDF File from HTML Template

On the Spring initializr Project Settings dialog input the new project information as below and click Next button.

  • Group: dev.simplesolution
  • Artifact: spring-boot-generate-pdf
  • Version: 1.0.0
  • Name: spring-boot-generate-pdf
  • Description: Spring Boot Generate PDF File
  • Package: dev.simplesolution.pdf

Spring Boot Generate PDF File from HTML Template

On the Dependencies dialog, select Thymeleaf as the screenshot below and click Next button.

Spring Boot Generate PDF File from HTML Template

Select the location for your project and click Finish button.

Spring Boot Generate PDF File from HTML Template

You can also create new Spring Boot project using Spring Initializr online tool at start.spring.io as below screenshot.

Spring Boot Generate PDF File from HTML Template

Add Flying Saucer PDF library to the Spring Boot project

To use the Flying Saucer PDF library into the Maven project, add the following dependency to the pom.xml file.

<dependency>
    <groupId>org.xhtmlrenderer</groupId>
    <artifactId>flying-saucer-pdf</artifactId>
    <version>9.1.22</version>
</dependency>

If you are using Gradle, add the following dependency to the build.gradle file.

implementation group: 'org.xhtmlrenderer', name: 'flying-saucer-pdf', version: '9.1.22'

Implement Thymeleaf Configuration bean

In this step we add a new configuration to configure the Thymeleaf template engine.

Add a new Java packaged named dev.simplesolution.pdf.config, in the created package implement a new Java class named ThymeleafConfiguration as below.

src/main/java/dev/simplesolution/pdf/config/ThymeleafConfiguration.java

package dev.simplesolution.pdf.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;

@Configuration
public class ThymeleafConfiguration {

    @Bean
    public ClassLoaderTemplateResolver emailTemplateResolver() {
        ClassLoaderTemplateResolver pdfTemplateResolver = new ClassLoaderTemplateResolver();
        pdfTemplateResolver.setPrefix("pdf-templates/");
        pdfTemplateResolver.setSuffix(".html");
        pdfTemplateResolver.setTemplateMode("HTML5");
        pdfTemplateResolver.setCharacterEncoding("UTF-8");
        pdfTemplateResolver.setOrder(1);
        return pdfTemplateResolver;
    }

}

Implement PDF Generate Service

In this step we implement a new service class to generate .pdf file with a given template file name, the data to populate HTML template and provided output .pdf file name.

Firstly add the following properties to configure the directory to write .pdf files. For example we will write .pdf file to D:\SimpleSolution\ directory.

src/main/resources/application.properties

pdf.directory=D:\\SimpleSolution\\

Add a new Java package named dev.simplesolution.pdf.service, in this new package create a new interface named PdfGenerateService as below.

src/main/java/dev/simplesolution/pdf/service/PdfGenerateService.java

package dev.simplesolution.pdf.service;

import java.util.Map;

public interface PdfGenerateService {
    void generatePdfFile(String templateName, Map<String, Object> data, String pdfFileName);
}

Add a new Java package named dev.simplesolution.pdf.service.impl, in the new package implement a new Java class named PdfGenerateServiceImpl, in this class we implement method generatePdfFile() to generate the .pdf file.

src/main/java/dev/simplesolution/pdf/service/impl/PdfGenerateServiceImpl.java

package dev.simplesolution.pdf.service.impl;

import com.lowagie.text.DocumentException;
import dev.simplesolution.pdf.service.PdfGenerateService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.xhtmlrenderer.pdf.ITextRenderer;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.Map;

@Service
public class PdfGenerateServiceImpl implements PdfGenerateService {
    private Logger logger = LoggerFactory.getLogger(PdfGenerateServiceImpl.class);

    @Autowired
    private TemplateEngine templateEngine;

    @Value("${pdf.directory}")
    private String pdfDirectory;

    @Override
    public void generatePdfFile(String templateName, Map<String, Object> data, String pdfFileName) {
        Context context = new Context();
        context.setVariables(data);

        String htmlContent = templateEngine.process(templateName, context);
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(pdfDirectory + pdfFileName);
            ITextRenderer renderer = new ITextRenderer();
            renderer.setDocumentFromString(htmlContent);
            renderer.layout();
            renderer.createPDF(fileOutputStream, false);
            renderer.finishPDF();
        } catch (FileNotFoundException e) {
            logger.error(e.getMessage(), e);
        } catch (DocumentException e) {
            logger.error(e.getMessage(), e);
        }
    }
}

Add HTML template file

At this step we add the HTML template file in Thymeleaf format as below.

src/main/resources/pdf-templates/quotation.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <style>
        h1{
            color: brown;
        }
        .quotation {
            width: 100%;
        }
        .quotation, .quotation th, .quotation td {
            border: 1px solid brown;
            border-collapse: collapse;
        }
        .quotation th {
            background-color: brown;
            color: white;
        }
    </style>
</head>
<body>
<h1>Quotation</h1>
<table>
    <tr>
        <th>Customer</th>
    </tr>
    <tr>
        <td th:text="'Company Name: ' + ${customer.companyName}"></td>
    </tr>
    <tr>
        <td th:text="'Contact Name: ' + ${customer.contactName}"></td>
    </tr>
    <tr>
        <td th:text="'Address: ' + ${customer.address}"></td>
    </tr>
    <tr>
        <td th:text="'Email: ' + ${customer.email}"></td>
    </tr>
    <tr>
        <td th:text="'Phone: ' + ${customer.phone}"></td>
    </tr>
</table>
<br />
<table class="quotation">
    <tr>
        <th>Item #</th>
        <th>Description</th>
        <th>Quantity</th>
        <th>Unit Price</th>
        <th>Total</th>
    </tr>
    <tr th:each="item, iterStat: ${quoteItems}">
        <td th:text="${iterStat.index + 1}"></td>
        <td th:text="${item.description}"></td>
        <td th:text="${item.quantity}"></td>
        <td th:text="${item.unitPrice}"></td>
        <td th:text="${item.total}"></td>
    </tr>
</table>
</body>
</html>

Implement Entity classes

In this step we implement the entity classes for the project, these classes will be used to instantiate objects as variables in order to process HTML template. For example we have Customer information and a list of quotation items need pass to the HTML template.

Add a new Java package named dev.simplesolution.pdf.entity, the implement the Customer class as below.

src/main/java/dev/simplesolution/pdf/entity/Customer.java

package dev.simplesolution.pdf.entity;

public class Customer {
    private String companyName;
    private String contactName;
    private String address;
    private String email;
    private String phone;

    public String getCompanyName() {
        return companyName;
    }

    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }

    public String getContactName() {
        return contactName;
    }

    public void setContactName(String contactName) {
        this.contactName = contactName;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
}

Add new class named QuoteItem as below.

src/main/java/dev/simplesolution/pdf/entity/QuoteItem.java

package dev.simplesolution.pdf.entity;

public class QuoteItem {
    private String description;
    private Integer quantity;
    private Double unitPrice;
    private Double total;

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Integer getQuantity() {
        return quantity;
    }

    public void setQuantity(Integer quantity) {
        this.quantity = quantity;
    }

    public Double getUnitPrice() {
        return unitPrice;
    }

    public void setUnitPrice(Double unitPrice) {
        this.unitPrice = unitPrice;
    }

    public Double getTotal() {
        return total;
    }

    public void setTotal(Double total) {
        this.total = total;
    }
}

Implement Testing Code to Generate .pdf File

At this step we implement a new class named PdfGeneratorRunner and implements CommandLineRunner interface in order to run the code when the Spring Boot application start.

In this class we call the generatePdfFile() method from PDF generate service to generate the .pdf file with provided customer information and a list of QuoteItem objects.

src/main/java/dev/simplesolution/pdf/PdfGeneratorRunner.java

package dev.simplesolution.pdf;

import dev.simplesolution.pdf.entity.Customer;
import dev.simplesolution.pdf.entity.QuoteItem;
import dev.simplesolution.pdf.service.PdfGenerateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class PdfGeneratorRunner implements CommandLineRunner {

    @Autowired
    private PdfGenerateService pdfGenerateService;

    @Override
    public void run(String... args) throws Exception {
        Map<String, Object> data = new HashMap<>();
        Customer customer = new Customer();
        customer.setCompanyName("Simple Solution");
        customer.setContactName("John Doe");
        customer.setAddress("123, Simple Street");
        customer.setEmail("john@simplesolution.dev");
        customer.setPhone("123 456 789");
        data.put("customer", customer);

        List<QuoteItem> quoteItems = new ArrayList<>();
        QuoteItem quoteItem1 = new QuoteItem();
        quoteItem1.setDescription("Test Quote Item 1");
        quoteItem1.setQuantity(1);
        quoteItem1.setUnitPrice(100.0);
        quoteItem1.setTotal(100.0);
        quoteItems.add(quoteItem1);

        QuoteItem quoteItem2 = new QuoteItem();
        quoteItem2.setDescription("Test Quote Item 2");
        quoteItem2.setQuantity(4);
        quoteItem2.setUnitPrice(500.0);
        quoteItem2.setTotal(2000.0);
        quoteItems.add(quoteItem2);

        QuoteItem quoteItem3 = new QuoteItem();
        quoteItem3.setDescription("Test Quote Item 3");
        quoteItem3.setQuantity(2);
        quoteItem3.setUnitPrice(200.0);
        quoteItem3.setTotal(400.0);
        quoteItems.add(quoteItem3);

        data.put("quoteItems", quoteItems);

        pdfGenerateService.generatePdfFile("quotation", data, "quotation.pdf");
    }
}

Complete Source Code and Run The Application

At this step we have finished the implementation of Spring Boot console application to generate .pdf file. Your project source code should be structured as below screenshot.

Spring Boot Generate PDF File from HTML Template

Run the application and open D:\SimpleSolution directory you can see the quotation.pdf file be generated with the content as below.

Spring Boot Generate PDF File from HTML Template

Download The Source Code

The source code in this article can be found at: github.com/simplesolutiondev/spring-boot-generate-pdf

or clone at:

git clone https://github.com/simplesolutiondev/spring-boot-generate-pdf.git

or download at:

Download Source Code

Happy Coding 😊

Spring Boot Web Download PDF File from HTML Template

Java Export PDF File from HTML Template

Java Convert HTML to PDF

Spring Boot Web Convert HTML String to PDF File

Java Convert HTML to Image