杰瑞科技汇

iText生成PDF时如何解决中文乱码问题?

准备工作:添加 iText 依赖

你需要在你的 Java 项目中添加 iText 的依赖,iText 有两个主要版本:

iText生成PDF时如何解决中文乱码问题?-图1
(图片来源网络,侵删)
  • iText 5: 经典版本,API 相对简单,但许可证为 AGPL,如果用于商业闭源项目,需要购买商业许可证。
  • iText 7: 最新版本,架构更现代化,性能更好,但 API 与 5.x 不兼容,许可证同样是 AGPL。

推荐使用 iText 7,因为它代表了未来的发展方向,下面以 Maven 为例,展示如何添加依赖。

Maven 依赖 (iText 7)

pom.xml 文件中添加以下依赖:

<dependencies>
    <!-- iText 7 Core -->
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itext7-core</artifactId>
        <version>7.2.5</version> <!-- 请使用最新版本 -->
        <type>pom</type>
    </dependency>
    <!-- iText 7 PDF 核心库 -->
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>kernel</artifactId>
        <version>7.2.5</version>
    </dependency>
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>pdf</artifactId>
        <version>7.2.5</version>
    </dependency>
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>io</artifactId>
        <version>7.2.5</version>
    </dependency>
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>layout</artifactId>
        <version>7.2.5</version>
    </dependency>
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>fonts</artifactId>
        <version>7.2.5</version>
    </dependency>
    <!-- 如果需要处理 HTML 到 PDF,需要添加 -->
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>html2pdf</artifactId>
        <version>4.0.3</version> <!-- 注意版本兼容性 -->
    </dependency>
</dependencies>

基础示例:创建一个简单的 PDF

让我们从一个最简单的例子开始:创建一个包含 "Hello, World!" 的 PDF 文件。

HelloWorld.java

iText生成PDF时如何解决中文乱码问题?-图2
(图片来源网络,侵删)
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import java.io.File;
import java.io.IOException;
public class HelloWorld {
    public static void main(String[] args) {
        // 1. 定义 PDF 输出路径
        String dest = "results/hello_world.pdf";
        // 2. 创建目录(如果不存在)
        File file = new File(dest);
        file.getParentFile().mkdirs();
        // 3. 使用 try-with-resources 确保 PdfDocument 和 Document 被正确关闭
        try (PdfWriter writer = new PdfWriter(dest);
             PdfDocument pdf = new PdfDocument(writer);
             Document document = new Document(pdf)) {
            // 4. 创建一个段落
            Paragraph p = new Paragraph("Hello, World! This is my first iText 7 PDF.");
            // 5. 将段落添加到文档中
            document.add(p);
            System.out.println("PDF created successfully at: " + dest);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

代码解释:

  1. PdfWriter: 负责将 PDF 内容写入到一个文件或输出流,它定义了 PDF 的目标位置。
  2. PdfDocument: 代表 PDF 文档本身,它是所有 PDF 操作的基础对象。
  3. Document: 这是 iText 7 Layout 模块的核心,它提供了一个高级别的 API,让你可以像处理 Word 文档一样,轻松添加段落、表格、列表等元素,而无需关心它们在页面上的精确坐标。
  4. Paragraph: 代表一个文本段落。
  5. document.add(p): 将段落添加到文档中。Document 对象会自动处理分页、字体、边距等。

运行此代码后,你将在 results 目录下得到一个 hello_world.pdf 文件。


常用功能详解

1 添加元数据 (Metadata)

你可以为 PDF 设置标题、作者、主题等元数据。

// 在创建 PdfDocument 后,添加元数据
PdfDocument pdf = new PdfDocument(writer);
pdf.getDocumentInfo().setTitle("My First PDF");
pdf.getDocumentInfo().setAuthor("Your Name");
pdf.getDocumentInfo().setSubject("iText 7 Tutorial");
pdf.getDocumentInfo().setKeywords("Java, PDF, iText");

2 设置页面大小和边距

// 1. 创建一个指定大小的 PdfPage
PdfPage page = pdf.addNewPage(new PageSize(PageSize.A4).rotate()); // A4,并旋转为横向
// 2. 创建 Document 时设置边距
Document document = new Document(pdf, new PageSize(PageSize.A4), 20, 20, 20, 20); // 左, 右, 上, 下边距

3 添加图片

import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.layout.element.Image;
// ...
try (Document document = new Document(pdf)) {
    // 图片路径
    String imagePath = "resources/itext-logo.png";
    Image image = new Image(ImageDataFactory.create(imagePath));
    // 设置图片宽度(高度会自动按比例调整)
    image.setWidth(200); 
    document.add(image);
}

4 创建表格

import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.UnitValue;
// ...
try (Document document = new Document(pdf)) {
    // 创建一个 3 列的表格,列宽分别为 1, 2, 1 的比例
    Table table = new Table(new float[]{1, 2, 1});
    // 添加表头单元格
    table.addHeaderCell("ID");
    table.addHeaderCell("Product Name");
    table.addHeaderCell("Price");
    // 添加数据单元格
    table.addCell("001");
    table.addCell("iText 7 Core");
    table.addCell("$99.99");
    table.addCell("002");
    table.addCell("iText 7 PDF");
    table.addCeel("$149.99");
    document.add(table);
}

5 列表

import com.itextpdf.layout.element.List;
import com.itextpdf.layout.element.ListItem;
// ...
try (Document document = new Document(pdf)) {
    // 创建一个有序列表
    List orderedList = new List().setSymbolNumbered(List.NUMBERED_LOWER_ROMAN);
    orderedList.add(new ListItem("First item"));
    orderedList.add(new ListItem("Second item"));
    orderedList.add(new ListItem("Third item"));
    document.add(orderedList);
    // 创建一个无序列表
    List unorderedList = new List().setSymbol(List.UNORDERED);
    unorderedList.add(new ListItem("Apple"));
    unorderedList.add(new ListItem("Banana"));
    unorderedList.add(new ListItem("Cherry"));
    document.add(unorderedList);
}

6 处理中文字符 (非常重要!)

iText 默认不支持中文,因为它需要特定的 TrueType 或 OpenType 字体文件,你必须手动加载字体。

iText生成PDF时如何解决中文乱码问题?-图3
(图片来源网络,侵删)

步骤:

  1. 下载一个中文字体文件,simhei.ttf (黑体)。
  2. 将字体文件放在项目的 resources 目录下。
  3. 使用 PdfFontFactory 加载字体。
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
// ...
String fontPath = "resources/simhei.ttf";
PdfFont font = null;
try {
    // 加载中文字体
    font = PdfFontFactory.createFont(fontPath, PdfEncodings.IDENTITY_H, true);
} catch (IOException e) {
    e.printStackTrace();
}
// 在创建 Document 时设置字体
try (Document document = new Document(pdf)) {
    // 确保所有文本都使用这个字体
    document.setFont(font);
    Paragraph p = new Paragraph("你好,世界!这是 iText 7 生成的 PDF 文档。");
    document.add(p);
}

高级功能

1 页眉、页脚和页码

iText 7 提供了 EventHandler 接口来实现页眉、页脚等高级页面事件处理。

示例:添加页码

import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.property.TextAlignment;
import com.itextpdf.layout.property.VerticalAlignment;
// ...
// 1. 创建一个自定义的页脚处理器
class MyPageEventHandler implements IEventHandler {
    @Override
    public void handleEvent(Event event) {
        PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
        PdfDocument pdf = docEvent.getDocument();
        PdfPage page = docEvent.getPage();
        PdfCanvas canvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdf);
        new Canvas(canvas, pdf, page.getPageSize())
            .showTextAligned("Page " + pdf.getPageNumber(page), 
                            page.getPageSize().getRight() - 50, 
                            page.getPageSize().getBottom() + 30, 
                            PdfPageNumberingLayout.TextAlignment.RIGHT)
            .close();
    }
}
// 2. 在创建 PdfDocument 后注册事件处理器
try (PdfWriter writer = new PdfWriter(dest);
     PdfDocument pdf = new PdfDocument(writer)) {
    pdf.addEventHandler(PdfDocumentEvent.END_PAGE, new MyPageEventHandler());
    try (Document document = new Document(pdf)) {
        // 添加大量内容以触发分页
        for (int i = 0; i < 100; i++) {
            document.add(new Paragraph("This is line " + (i + 1) + " of the document."));
        }
    }
}

2 HTML 转 PDF

iText 7 提供了 html2pdf 模块,可以非常方便地将 HTML 和 CSS 渲染成 PDF。

Maven 依赖: 请参考上文添加 html2pdf 依赖。

import com.itextpdf.html2pdf.HtmlConverter;
public class HtmlToPdf {
    public static void main(String[] args) {
        String html = "<h1>Hello from HTML</h1><p>This paragraph is styled with <b>HTML</b>.</p>";
        String dest = "results/html_to.pdf";
        File file = new File(dest);
        file.getParentFile().mkdirs();
        HtmlConverter.convertToPdf(html, new FileOutputStream(dest));
        System.out.println("PDF created from HTML at: " + dest);
    }
}

最佳实践与注意事项

  1. 许可证问题: 这是最重要的一点! iText 7 核心库使用 AGPLv3 许可证,如果你的项目是一个商业闭源项目,并且你使用了 iText 的核心功能,你必须购买商业许可证,否则会面临法律风险,如果你的项目是开源的(遵循 AGPLv3),则可以免费使用。
  2. 资源管理: 始终使用 try-with-resources 语句来管理 PdfWriter, PdfDocument, 和 Document 等实现了 AutoCloseable 接口的对象,这可以确保文件流被正确关闭,避免资源泄露。
  3. 性能: 对于生成大量 PDF 的后台任务,避免在循环中重复创建 PdfDocumentDocument,一次性创建,然后在循环中添加内容,最后再关闭。
  4. 字体: 处理多语言(特别是中文)时,务必确保你使用的字体文件包含了所有需要的字符,并且正确加载,否则会出现方框 。
  5. 官方文档: iText 的官方文档和 API 非常完善,遇到问题时,iText 7 Documentation 是最好的参考资料。

希望这份详细的指南能帮助你快速上手使用 iText 7 在 Java 中生成 PDF 文件!

分享:
扫描分享到社交APP
上一篇
下一篇