I am trying to generate pdf using html, using thymeleaf and flying saucer library. However the CSS is not being applied when pdf is generating.
Here is my pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>dev.simplesolution</groupId>
<artifactId>spring-boot-pdf</artifactId>
<version>1.0.0</version>
<name>spring-boot-pdf</name>
<description>Spring Boot Generate PDF File</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf</artifactId>
<version>9.1.22</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Service class
@Service
public class PdfGeneratorServiceImpl {
private Logger logger = LoggerFactory.getLogger(PdfGeneratorServiceImpl.class);
@Autowired
private TemplateEngine templateEngine;
public ByteArrayInputStream generatePdfFile(String templateName, Map<String, Object> data) {
Context context = new Context();
context.setVariables(data);
String htmlContent = templateEngine.process(templateName, context);
System.out.println(htmlContent);
ByteArrayInputStream byteArrayInputStream = null;
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(htmlContent);
renderer.layout();
renderer.createPDF(byteArrayOutputStream, false);
renderer.finishPDF();
byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
} catch (DocumentException e) {
logger.error(e.getMessage(), e);
}
return byteArrayInputStream;
}
}
HTML template
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: white;
margin-left: 150px;
}
.section {
background-color: white;
padding: 20px;
margin-bottom: 20px;
}
.details-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.detail {
padding: 10px 0;
}
.label {
font-weight: bold;
display: block;
}
.value {
margin-top: 5px;
}
h2 {
font-size: 18px;
color: #333;
padding-bottom: 10px;
margin-top: 0;
}
@media screen and (max-width: 600px) {
.details-grid {
grid-template-columns: 1fr;
gap: 10px;
}
}
.table {
border-collapse: collapse;
width: 100%;
}
th,
td {
padding: 15px 4px 0px 50px;
border-bottom: 1px solid gray;
}
tr,
td:first-child {
border-right: 1px solid gray;
}
.ratingComponent {
margin: 20px;
text-align: center;
}
.ratingComponent__heading {
display: block;
color: #666;
margin-bottom: 5px;
}
.ratingComponent__rating {
display: flex;
flex-direction: row-reverse;
align-items: center;
align-content: center;
justify-content: space-between;
}
.ratingComponent__dot {
border: solid 2px #eb822f;
width: 16px;
height: 16px;
border-radius: 50%;
margin: 0 5px 0 0;
}
.ratingComponent__dot:first-of-type {
margin: 0;
}
.ratingComponent__dot--filled {
background-color: #eb822f;
}
.ratingComponent__dot--halfFilled {
background-color: #eb822f;
width: 7px;
border-radius: 10px 0 0 10px;
margin-right: 15px;
}
.ratingComponent__dot--halfFilled:after {
content: "";
display: block;
position: relative;
left: 7px;
top: -2px;
width: 8px;
height: 16px;
border-radius: 0 10px 10px 0;
border: solid 2px #eb822f;
}
.ratingComponent__dot--unRated {
background-color: transparent;
border-color: #e0e0e0;
cursor: pointer;
transition: all 200ms ease-in-out;
}
.ratingComponent__dot--unRated:hover,
.ratingComponent__dot--unRated:hover~.ratingComponent__dot,
.ratingComponent__dot--unRated:focus,
.ratingComponent__dot--unRated:focus~.ratingComponent__dot {
border-color: #eb822f;
background-color: #eb822f;
}
</style>
</head>
<body>
<div style="text-align: center;">
<div class="image">
<img src="assets/images/brands_logo/logo_150.png" alt="img" width="150" />
</div>
</div>
<div class="section">
<h2>Customer details</h2>
<div class="details-grid">
<div class="detail">
<span class="label">First name</span>
<span class="value" th:text="${customerDetails.firstName}"></span>
</div>
<div class="detail">
<span class="label">Last name</span>
<span class="value" th:text="${customerDetails.lastName}"></span>
</div>
<div class="detail">
<span class="label">Phone</span>
<span class="value" th:text="${customerDetails.cellphone}"></span>
</div>
<div class="detail">
<span class="label">Email</span>
<span class="value" th:text="${customerDetails.emailaddress}"></span>
</div>
<div class="detail">
<span class="label">Regione</span>
<span class="value" th:text="${customerDetails.region}"></span>
</div>
<div class="detail">
<span class="label">Market</span>
<span class="value" th:text="${customerDetails.market}"></span>
</div>
<div class="detail">
<span class="label">Importer</span>
<span class="value" th:text="${customerDetails.importer}"></span>
</div>
<div class="detail">
<span class="label">Agent</span>
<span class="value" th:text="${customerDetails.agent}"></span>
</div>
<div class="detail">
<span class="label">Dealer</span>
<span class="value" th:text="${customerDetails.dealer}"></span>
</div>
</div>
</div>
<div class="section">
<h2>Vehicle details</h2>
<div class="details-grid">
<div class="detail">
<span class="label">Brand</span>
<span class="value" th:text="${customerDetails.brand}"></span>
</div>
<div class="detail">
<span class="label">VIN</span>
<span class="value" th:text="${customerDetails.vin}"></span>
</div>
<div class="detail">
<span class="label">Model</span>
<span class="value"></span>
</div>
</div>
</div>
<div class="section">
<h2>Survey details</h2>
<div class="details-grid">
<div class="detail">
<span class="label">Response channel</span>
<span class="value" th:text="${customerDetails.responseChannel}"></span>
</div>
<div class="detail">
<span class="label">Response date</span>
<span class="value" th:text="${customerDetails.responseDate}"></span>
</div>
<div class="detail">
<span class="label">Event date</span>
<span class="value" th:text="${customerDetails.eventDate}"></span>
</div>
</div>
</div>
<div class="section">
<h4 style="block-size: auto;">Domande / Risposte</h4>
</div>
<div>
<table class="table">
<tr th:each="qa, qaStat: ${qaList}">
<td th:text="${qa.question}"></td>
<td><br />
<br />
<div class="ratingComponent">
<!-- <small class="ratingComponent__heading"></small> -->
<div class="ratingComponent__rating" th:utext="${qa.answer}">
<!-- <div th:utext="${qa.answer}"></div>-->
</div>
</div>
</td>
</tr>
</table>
</div>
</body>
</html>
Thymeleaf is generating correct HTML and it is rendering as expected in the browser, however, the generated pdf is completely ignoring the CSS.
Thymeleaf generated HTML: https://pastebin.com/QJKyPzqw