Java Servlet serve PDF
last modified August 24, 2023
Java servlet PDF tutorial shows how to return PDF data from a Java servlet. We use iText library to work with PDF.
The Portable Document Format (PDF) is a file format used to present documents in a manner independent of application software, hardware, and operating systems. Invented by Adobe, PDF is now an open standard maintained by the International Organization for Standardization (ISO).
Java Servlet
Servlet is a Java class which responds to a particular type of network request - most commonly an HTTP request. Java servlets are used to create web applications. They run in servlet containers such as Tomcat or Jetty. Modern-day Java web development uses frameworks that are built on top of servlets.
iText
iText is an open source library for creating and manipulating PDF files in Java.
Java servlet PDF application
The following web application uses a Java servlet to send a PDF file to the client. It generates PDF from a list of objects.
pom.xml src ├── main │ ├── java │ │ └── com │ │ └── zetcode │ │ ├── bean │ │ │ └── City.java │ │ ├── service │ │ │ └── CityService.java │ │ ├── util │ │ │ └── GeneratePdf.java │ │ └── web │ │ └── MyServlet.java │ └── resources └── test └── java
This is the project structure.
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>JavaServletPdf</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>6.0.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.13.3</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.2.3</version> </plugin> <plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>11.0.11</version> <configuration> <webApp> <contextPath>/app</contextPath> </webApp> </configuration> </plugin> </plugins> </build> </project>
This is the Maven POM file. We have two artifacts: jakarta.servlet-api
for servlets and itextpdf
for PDF generation in Java. The
maven-war-plugin
is responsible for collecting all artifact
dependencies, classes and resources of the web application and packaging them
into a web application archive (WAR). The jetty-maven-plugin
is
a helper plugin for easy tesing and integration of Jetty witn Maven.
<configuration> <webApp> <contextPath>/app</contextPath> </webApp> </configuration>
In the Jetty Maven plugin, we set the context path to /app
.
package com.zetcode.bean; public class City { private Long id; private String name; private int population; public City() { } public City(Long id, String name, int population) { this.id = id; this.name = name; this.population = population; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPopulation() { return population; } public void setPopulation(int population) { this.population = population; } @Override public String toString() { return "City{" + "id=" + id + ", name=" + name + ", population=" + population + '}'; } }
This is the City
bean. It has three attributes: id
,
name
, and population
.
package com.zetcode.web; import com.zetcode.bean.City; import com.zetcode.service.CityService; import com.zetcode.util.GeneratePdf; import jakarta.servlet.ServletOutputStream; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.List; @WebServlet(name = "MyServlet", urlPatterns = {"/pdf"}) public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { response.setContentType("application/pdf;charset=UTF-8"); response.addHeader("Content-Disposition", "inline; filename=" + "cities.pdf"); ServletOutputStream out = response.getOutputStream(); List<City> cities = CityService.getCities(); ByteArrayOutputStream baos = GeneratePdf.getPdfFile(cities); baos.writeTo(out); } }
This is the MyServlet
servlet. It retrieves data from a service
class, generates PDF file from the data, and returns the PDF file to the client.
response.setContentType("application/pdf;charset=UTF-8");
We set the content type of the response object to application/pdf
.
response.addHeader("Content-Disposition", "inline; filename=" + "cities.pdf");
The Content-Disposition
response header indicates that the content is
expected to be displayed inline
in the browser, that is, as a Web page
or as part of a Web page, or as an attachment
, that is downloaded and
saved locally. The optional filename
directive specifies the name of
the file transmitted.
ServletOutputStream out = response.getOutputStream();
We get the ServletOutputStream
from the response object.
List<City> cities = CityService.getCities();
From the CityService
, we get the list of cities.
ByteArrayOutputStream baos = GeneratePdf.getPdfFile(cities); baos.writeTo(out);
We generate a PDF file from the data and write the returned
ByteArrayOutputStream
to the ServletOutputStream
.
package com.zetcode.service; import com.zetcode.bean.City; import java.util.List; public class CityService { public static List<City> getCities() { var cities = List.of( new City(1L, "Bratislava", 432000), new City(2L, "Budapest", 1759000), new City(3L, "Prague", 1280000), new City(4L, "Warsaw", 1748000), new City(5L, "Los Angeles", 3971000), new City(6L, "New York", 8550000), new City(7L, "Edinburgh", 464000), new City(8L, "Berlin", 3671000)); return cities; } }
The CityService's
getCities
method returns a list of
city objects.
package com.zetcode.util; import com.itextpdf.text.Document; import com.itextpdf.text.DocumentException; import com.itextpdf.text.Element; import com.itextpdf.text.Font; import com.itextpdf.text.FontFactory; import com.itextpdf.text.Phrase; import com.itextpdf.text.pdf.PdfPCell; import com.itextpdf.text.pdf.PdfPTable; import com.itextpdf.text.pdf.PdfWriter; import com.zetcode.bean.City; import java.io.ByteArrayOutputStream; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; public class GeneratePdf { public static ByteArrayOutputStream getPdfFile(List<City> cities) { var document = new Document(); var bout = new ByteArrayOutputStream(); try { var table = new PdfPTable(3); table.setWidthPercentage(60); table.setWidths(new int[]{1, 3, 3}); Font headFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD); var hcell = new PdfPCell(new Phrase("Id", headFont)); hcell.setHorizontalAlignment(Element.ALIGN_CENTER); table.addCell(hcell); hcell = new PdfPCell(new Phrase("Name", headFont)); hcell.setHorizontalAlignment(Element.ALIGN_CENTER); table.addCell(hcell); hcell = new PdfPCell(new Phrase("Population", headFont)); hcell.setHorizontalAlignment(Element.ALIGN_CENTER); table.addCell(hcell); for (City city : cities) { var cell = new PdfPCell(new Phrase(city.getId().toString())); cell.setVerticalAlignment(Element.ALIGN_MIDDLE); cell.setHorizontalAlignment(Element.ALIGN_CENTER); table.addCell(cell); cell = new PdfPCell(new Phrase(city.getName())); cell.setPaddingLeft(5); cell.setVerticalAlignment(Element.ALIGN_MIDDLE); cell.setHorizontalAlignment(Element.ALIGN_LEFT); table.addCell(cell); cell = new PdfPCell(new Phrase(String.valueOf(city.getPopulation()))); cell.setVerticalAlignment(Element.ALIGN_MIDDLE); cell.setHorizontalAlignment(Element.ALIGN_RIGHT); cell.setPaddingRight(5); table.addCell(cell); } PdfWriter.getInstance(document, bout); document.open(); document.add(table); document.close(); } catch (DocumentException ex) { Logger.getLogger(GeneratePdf.class.getName()).log(Level.SEVERE, null, ex); } return bout; } }
GeneratePdf
creates PDF file from the provided data.
var bout = new ByteArrayOutputStream();
The data will be written to ByteArrayOutputStream
.
ByteArrayOutputStream
implements an output stream in which the data
is written into a byte array.
var table = new PdfPTable(3);
We will put our data in a table; for this, we have the PdfPTable
class. The table has three columns: Id, Name, and Population.
Font headFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD);
We use bold Helvetica font for the table header.
var hcell = new PdfPCell(new Phrase("Id", headFont)); hcell.setHorizontalAlignment(Element.ALIGN_CENTER); table.addCell(hcell);
The data is placed inside table cells, represented by PdfPCell
.
The setHorizontalAlignment
method horizontally alignes the text.
PdfWriter.getInstance(document, bout);
With PdfWriter
, the document is written to
the ByteArrayOutputStream
.
document.open(); document.add(table);
The table is inserted into the PDF document.
document.close();
In order for the data to be written to the ByteArrayOutputStream
,
the document must be closed.
return bout;
In the end, the data is returned as ByteArrayOutputStream
.
$ mvn jetty:run
Start the Jetty server and navigate to localhost:8080/app/pdf
.
In this article we have sent PDF data from a Java servlet.
List all Java Servlet tutorials.