# Java servlet PDF 教程

> 原文： [http://zetcode.com/articles/javaservletpdf/](http://zetcode.com/articles/javaservletpdf/)

Java servlet PDF 教程展示了如何从 Java servlet 返回 PDF 数据。 我们使用 iText 库处理 PDF。 该 Web 应用已部署在 Tomcat 服务器上。

## PDF 格式

便携式文档格式（PDF）是用于以独立于应用软件，硬件和操作系统的方式呈现文档的文件格式。 PDF 由 Adobe 发明，现在是国际标准化组织（ISO）维护的开放标准。

## Java Servlet

Servlet 是 Java 类，可响应特定类型的网络请求-最常见的是 HTTP 请求。 Java servlet 用于创建 Web 应用。 它们在 servlet 容器（例如 Tomcat 或 Jetty）中运行。 现代 Java Web 开发使用在 servlet 之上构建的框架。

## iText

iText 是一个开放源代码库，用于在 Java 中创建和处理 PDF 文件。

## Java Servlet PDF 应用

以下 Web 应用使用 Java Servlet 将 PDF 文件发送到客户端。 它从对象列表生成 PDF。

```java
$ 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`

```java
<?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 文件。 我们有两个工件：用于 Java 的 servlet 的`javax.servlet-api`和用于 PDF 生成的`itext`。 `maven-war-plugin`负责收集 Web 应用的所有工件依赖项，类和资源，并将它们打包到 Web 应用存档（WAR）中。

`context.xml`

```java
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/JavaServletPdf"/>

```

在 Tomcat `context.xml`文件中，我们定义了上下文路径。 它是 Web 应用的名称。

`City.java`

```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` bean。 它具有三个属性：`id`，`name`和`population`。

`MyServlet.java`

```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` servlet。 它从服务类检索数据，从数据生成 PDF 文件，然后将 PDF 文件返回给客户端。

```java
response.setContentType("application/pdf;charset=UTF-8");

```

我们将响应对象的内容类型设置为`application/pdf`。

```java
response.addHeader("Content-Disposition", "inline; filename=" + "cities.pdf");

```

`Content-Disposition`响应标头指示内容应在浏览器中显示为`inline`，即作为 Web 页面或 Web 页面的一部分，或作为`attachment`在本地下载和保存。 。 可选的`filename`伪指令指定传输文件的名称。

```java
ServletOutputStream out = response.getOutputStream();

```

我们从响应对象获得`ServletOutputStream`。

```java
List<City> cities = CityService.getCities();

```

从`CityService`中，我们可以获得城市列表。

```java
List<City> cities = CityService.getCities();

```

从`CityService`中，我们可以获得城市列表。

```java
ByteArrayOutputStream baos = GeneratePdf.getPdfFile(cities);
baos.writeTo(out);

```

我们根据数据生成 PDF 文件，并将返回的`ByteArrayOutputStream`写入`ServletOutputStream`。

`CityService.java`

```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`的`getCities()`方法返回城市对象的列表。

`GeneratePdf.java`

```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 文件。

```java
ByteArrayOutputStream bout = new ByteArrayOutputStream();

```

数据将被写入`ByteArrayOutputStream`。 `ByteArrayOutputStream`实现了一个输出流，其中数据被写入字节数组。

```java
PdfPTable table = new PdfPTable(3);

```

我们将数据放在表格中； 为此，我们有`PdfPTable`类。 该表具有三列：ID，名称和人口。

```java
Font headFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD);

```

我们使用粗体 Helvetica 字体作为表标题。

```java
PdfPCell hcell;
hcell = new PdfPCell(new Phrase("Id", headFont));
hcell.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(hcell);

```

数据放置在表单元格内，由`PdfPCell`表示。 `setHorizontalAlignment()`方法使文本水平对齐。

```java
PdfWriter.getInstance(document, bout);

```

使用`PdfWriter`，将文档写入`ByteArrayOutputStream`。

```java
document.open();
document.add(table);

```

该表将插入到 PDF 文档中。

```java
document.close();

```

为了将数据写入`ByteArrayOutputStream`，必须关闭文档。

```java
return bout; 

```

最后，数据返回为`ByteArrayOutputStream`。

在本教程中，我们从 Java servlet 发送了 PDF 数据。

您可能也对以下相关教程感兴趣： [Java `RequestDispatcher`](/java/requestdispatcher/) ， [Java Servlet 图表教程](/articles/javaservletchart/)，[从 Java Servlet 提供纯文本](/articles/javaservlettext/)， [Java Servlet 检查框教程](/articles/javaservletcheckbox/)， [Java servlet 图像教程](/articles/javaservletimage/)， [Java Servlet HTTP 标头](/articles/javaservlethttpheaders/)或 [Java 教程](/lang/java/)