Java servlet PDF 教程展示了如何从 Java servlet 返回 PDF 数据。我们使用 iText 库来处理 PDF。Web 应用程序部署在 Tomcat 服务器上。
PDF格式
可移植文档格式 (PDF)是一种文件格式,用于以独立于应用软件、硬件和操作系统的方式呈现文档。PDF 由 Adobe 发明,现在是由国际标准化组织 (ISO) 维护的开放标准。
Java 小服务程序
Servlet是一个 Java 类,它响应特定类型的网络请求——最常见的是 HTTP 请求。Java servlet 用于创建 Web 应用程序。它们在 Tomcat 或 Jetty 等 servlet 容器中运行。现代 Java Web 开发使用构建在 servlet 之上的框架。
文字
iText是一个开源库,用于在 Java 中创建和操作 PDF 文件。
Java servlet PDF 应用程序
以下 Web 应用程序使用 Java servlet 将 PDF 文件发送到客户端。它从对象列表生成 PDF。
$ tree
.
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── zetcode
│ │ ├── bean
│ │ │ └── City.java
│ │ ├── service
│ │ │ └── CityService.java
│ │ ├── util
│ │ │ └── GeneratePdf.java
│ │ └── web
│ │ └── MyServlet.java
│ └── webapp
│ ├── index.html
│ ├── META-INF
│ │ └── context.xml
│ └── WEB-INF
└── test
└── java
这是项目结构。
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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zetcode</groupId>
<artifactId>JavaServletPDF</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>JavaServletPDF</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>4.2.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
这是 Maven POM 文件。我们有两个工件:javax.servlet-api
用于 servlet 和itext
用于 Java 中的 PDF 生成。maven-war-plugin
负责收集 Web 应用程序的所有工件依赖项、类和资源,并将它们打包到 Web 应用程序存档 (WAR) 中 。
context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/JavaServletPdf"/>
在 Tomcatcontext.xml
文件中,我们定义了上下文路径。它是 Web 应用程序的名称。
com/zetcode/City.java
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 + '}';
}
}
这是City
豆子。它具有三个属性:id
、name
和 population
。
com/zetcode/MyServlet.java
package com.zetcode.web;
import com.zetcode.bean.City;
import com.zetcode.service.CityService;
import com.zetcode.util.GeneratePdf;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(name = "MyServlet", urlPatterns = {"/MyServlet"})
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, 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);
}
}
这是MyServlet
小服务程序。它从服务类中检索数据,从数据中生成 PDF 文件,并将 PDF 文件返回给客户端。
response.setContentType("application/pdf;charset=UTF-8");
我们将响应对象的内容类型设置为application/pdf
。
response.addHeader("Content-Disposition", "inline; filename=" + "cities.pdf");
响应标Content-Disposition
头表示内容应显示inline
在浏览器中,即作为网页或网页的一部分,或作为attachment
下载并保存在本地的 . 可选filename
指令指定传输文件的名称。
ServletOutputStream out = response.getOutputStream();
我们ServletOutputStream
从响应对象中获取。
List<City> cities = CityService.getCities();
从 中CityService
,我们得到城市列表。
List<City> cities = CityService.getCities();
从 中CityService
,我们得到城市列表。
ByteArrayOutputStream baos = GeneratePdf.getPdfFile(cities);
baos.writeTo(out);
我们从数据中生成一个 PDF 文件,并将返回 ByteArrayOutputStream
的内容写入ServletOutputStream
.
com/zetcode/CityService.java
package com.zetcode.service;
import com.zetcode.bean.City;
import java.util.ArrayList;
import java.util.List;
public class CityService {
public static List<City> getCities() {
List<City> cities = new ArrayList<>();
cities.add(new City(1L, "Bratislava", 432000));
cities.add(new City(2L, "Budapest", 1759000));
cities.add(new City(3L, "Prague", 1280000));
cities.add(new City(4L, "Warsaw", 1748000));
cities.add(new City(5L, "Los Angeles", 3971000));
cities.add(new City(6L, "New York", 8550000));
cities.add(new City(7L, "Edinburgh", 464000));
cities.add(new City(8L, "Berlin", 3671000));
return cities;
}
}
该CityService's
getCities()
方法返回一个城市对象列表。
com/zetcode/GeneratePdf.java
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) {
Document document = new Document();
ByteArrayOutputStream bout = new ByteArrayOutputStream();
try {
PdfPTable table = new PdfPTable(3);
table.setWidthPercentage(60);
table.setWidths(new int[]{1, 3, 3});
Font headFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD);
PdfPCell hcell;
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) {
PdfPCell cell;
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
根据提供的数据创建 PDF 文件。
ByteArrayOutputStream bout = new ByteArrayOutputStream();
数据将写入ByteArrayOutputStream
. ByteArrayOutputStream
实现将数据写入字节数组的输出流。
PdfPTable table = new PdfPTable(3);
我们将把我们的数据放在一个表格中;为此,我们有PdfPTable
课。该表包含三列:Id、Name 和 Population。
Font headFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD);
我们使用粗体 Helvetica 字体作为表头。
PdfPCell hcell;
hcell = new PdfPCell(new Phrase("Id", headFont));
hcell.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(hcell);
数据放置在表格单元格中,由 表示PdfPCell
。该setHorizontalAlignment()
方法水平对齐文本。
PdfWriter.getInstance(document, bout);
使用PdfWriter
,将文档写入ByteArrayOutputStream
.
document.open();
document.add(table);
表格被插入到 PDF 文档中。
document.close();
为了将数据写入ByteArrayOutputStream
,必须关闭文档。
return bout;
最后,数据返回为ByteArrayOutputStream
.
输出:
使用PDFBox
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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zetcode</groupId>
<artifactId>JavaServletPDF</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>JavaServletPDF</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>4.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.25</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>fontbox</artifactId>
<version>2.0.25</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>jempbox</artifactId>
<version>1.8.16</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>xmpbox</artifactId>
<version>2.0.25</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>preflight</artifactId>
<version>2.0.25</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox-tools</artifactId>
<version>2.0.25</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
PDFBoxServlet .java
package com.zetcode.web;
import com.zetcode.bean.City;
import com.zetcode.service.CityService;
import com.zetcode.util.GeneratePdf;
import java.awt.Color;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
@WebServlet(name = "PDFBoxServlet", urlPatterns = {"/PDFBoxServlet"})
public class PDFBoxServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("application/pdf;charset=UTF-8");
response.addHeader("Content-Disposition", "inline; filename=" + "cities.pdf");
ServletOutputStream out = response.getOutputStream();
PDDocument pdfDoc = new PDDocument();
PDPage firstPage = new PDPage();
// add page to the PDF document
pdfDoc.addPage(firstPage);
// For writing to a page content stream
try ( PDPageContentStream cs = new PDPageContentStream(pdfDoc, firstPage)) {
cs.beginText();
// setting font family and font size
//cs.setFont(PDType1Font.COURIER, 15);
cs.setFont(PDType0Font.load(pdfDoc, new File("C:\\Windows\\Fonts\\simfang.TTF")), 10);
// color for the text
cs.setNonStrokingColor(Color.RED);
cs.setLeading(14.5f);
// starting position
cs.newLineAtOffset(20, 750);
cs.showText("由PDFBox创建的第一行中文;");
cs.newLine();
cs.showText("由PDFBox创建的第二行中文!");
cs.endText();
}
// save PDF document
pdfDoc.save(out);
pdfDoc.close();
}
}
输出:
在本教程中,我们从 Java servlet 发送了 PDF 数据。