⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 江南一点雨 「江南一点雨」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

不知道小伙伴们在项目中有没有遇到过导出 PDF 的需求,我在之前的 tienchin 项目中有一个合同导出的功能,需要将文档导出为 PDF。

将文档导出为 PDF 有很多方案,不同方案的优缺点也各不相同,今天就和大家演示一个。

一 解决方案

以下是列举的一些常见的 PDF 导出方案。

1.1 iText

iText 是一个强大的 PDF 处理库,可以用来创建和操作 PDF 文件。在 Spring Boot 项目中,你可以通过添加 iText 的依赖来使用它。iText 支持直接创建 PDF,也可以将 HTML 内容转换为 PDF。

iText 的特点如下:

优点:

  • 功能强大,支持创建和编辑 PDF 文件。
  • 提供丰富的 API,支持添加图像、水印、表格、书签和超链接等。
  • 支持数字签名和加密 PDF 文件。
  • 性能优秀,能够高效地处理大型 PDF 文件和复杂操作。

缺点:

  • 学习曲线较陡峭,需要一定的时间和精力去熟悉。
  • 商业版需要购买许可证,可能会增加成本。
  • 对于简单的 PDF 处理任务可能过于复杂。

1.2 OpenPDF

OpenPDF 是基于 iText5.x 版本开发的,它提供了将 HTML 转换为 PDF 的功能。

OpenPDF 的特点如下:

优点:

  • 简单易用,适合快速开发。
  • 提供了创建和操作 PDF 文件的一组 API。

缺点:

功能相对较少,可能无法满足复杂需求。

1.3 Apache PDFBox

Apache PDFBox 是一个开源的 Java PDF 库,可以用来创建和编辑 PDF 文档。它提供了丰富的 API 来操作 PDF 内容。

Apache PDFBox 的特点如下:

优点:

  • 功能齐全,支持创建、编辑、提取内容等操作。
  • 支持 OCR 识别和打印等功能。
  • 性能稳定,适合全面处理 PDF 文件的场景。
  • 开源免费,采用 Apache 许可证。

缺点:

  • 相对于 iText,处理大型文件时性能可能略逊一筹。
  • API 设计较为复杂,可能会影响开发效率。

1.4 Flyingsaucer

Flyingsaucer 是一个基于 iText 和 XHTMLRenderer 的 Java 库,可以将 XHTML/CSS 内容转换为 PDF。

Flyingsaucer 特点如下:

优点:

  • 可以将 HTML/CSS 内容直接转换为 PDF。
  • 支持使用 CSS 样式来控制 PDF 的外观。

缺点:

  • 不支持富文本,对于使用富文本编辑器的内容处理不佳。
  • 对 HTML 的规范性要求较高,容错性较差。

上面是给大家列举的几个常见的方案,实际方案除了这些还有很多,比如 WeasyPrint、OpenHTMLtoPDF 等,在实际项目中选择哪种方案取决于你的具体需求,比如是否需要处理复杂的布局、是否需要支持 CSS 样式、是否需要处理中文等非 ASCII 字符等。每种方案都有其优缺点,需要根据项目实际情况进行选择。

这里和小伙伴们演示一下 iText 的使用,这个工具的能力最为强大。

二 iText

2.1 什么是 iText

iText 是一个功能强大的开源 Java 库,用于创建和操作 PDF 文件。

iText 提供了丰富的 API,可以生成交互式 PDF 文档、添加书签、页码、水印,以及拆分和合并 PDF 文档等。

iText 支持将 PDF 保存为图像文件,如 PNG 或 JPEG,并且可以在 PDF 文档上绘制各种几何形状,如圆形、线条等。

iText的主要特点:

  1. 交互性:可以创建交互式 PDF 文档,如表单填写。
  2. 添加元素:可以添加书签、页码、水印等。
  3. 分割与合并:可以将现有 PDF 分割或合并其他页面。
  4. 表单处理:可以处理 PDF 表单。
  5. 保存为图像:可以将 PDF 保存为图像格式。
  6. 绘制功能:提供 Canvas 类,支持绘制各种形状。

注意,iText 本身不支持中文,需要引入中文字体文件,并使用 BaseFont.createFont 方法创建字体对象,然后使用该字体对象创建文本。

在使用 iText 时,还需要注意开源协议的问题。iText 目前遵循 AGPL 开源协议,如果是商业用途,需要公开源代码或者购买商业许可。

此外,iText 还提供了一些高级功能,如 PDF 加密、数字签名、优化 PDF 文件大小等。

2.2 案例

首先我们新建一个 Spring Boot 项目,引入 Thymeleaf 依赖,引入这个依赖的原因在于我们一会利用 Thymeleaf 做页面模版,然后利用 iText 做 PDF 生成。

项目创建成功之后,再引入 iText 的依赖,最终依赖如下:

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation group: 'com.itextpdf', name: 'itextpdf', version: '5.5.13.4'
implementation group: 'com.itextpdf', name: 'html2pdf', version: '5.0.5'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

注意,这里和 iText 相关的依赖一共有两个。

接下来我们创建一个 HTML 页面作为生成的 PDF 模版,这个模版我们就放到 Thymeleaf 默认的 templates 目录下:

<!DOCTYPE html>
<h1 th:text="${title}"></h1>
<table border="1">
<tr>
<td>图书名称</td>
<td th:text="${name}"></td>
</tr>
<tr>
<td>图书价格</td>
<td th:text="${price}"></td>
</tr>
<tr>
<td>图书作者</td>
<td th:text="${author}"></td>
</tr>
</table>

这个页面模版使用 Thymeleaf 来构建。

另外,由于这些工具大部分都不直接支持中文,需要我们提前准备中文字体,松哥这里准备了一个宋体字库,放在 resources/fonts 目录下:

接下来我们就准备一个生成 PDF 的工具类,如下:

package org.javaboy.openpdfdemo.utils;

import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.font.FontProvider;

import java.io.IOException;
import java.io.OutputStream;

/**
* @github:https://github.com/lenve
* @gitee:https://gitee.com/lenve
*/
public class HtmlToPdfUtils {

public static void convertToPdf(String html, OutputStream outputStream) throws IOException {

PdfWriter pdfWriter = new PdfWriter(outputStream);
PdfDocument pdfDocument = new PdfDocument(pdfWriter);
// 设置为A4大小
pdfDocument.setDefaultPageSize(PageSize.A4);

// 添加中文字体支持
ConverterProperties properties = new ConverterProperties();
FontProvider fontProvider = new FontProvider();

// 添加自定义字体,例如宋体
PdfFont stSong = PdfFontFactory.createFont(HtmlToPdfUtils.class.getResource("/fonts/STSong.ttf").getPath(), PdfEncodings.WINANSI);
fontProvider.addFont(stSong.getFontProgram(), PdfEncodings.IDENTITY_H);

properties.setFontProvider(fontProvider);
if (html != null) {
// 生成pdf文档
HtmlConverter.convertToPdf(html, pdfDocument, properties);
pdfWriter.close();
pdfDocument.close();
} else {
throw new RuntimeException("HTML 内容不能为空");
}
}
}

这块代码没啥好说的,基本上见名知义。

最后,在 Controller 接口中调用该工具类,如下:

package org.javaboy.openpdfdemo.controller;

import com.itextpdf.text.DocumentException;
import jakarta.servlet.http.HttpServletResponse;
import org.javaboy.openpdfdemo.utils.HtmlToPdfUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import java.io.IOException;

/**
* @github:https://github.com/lenve
* @gitee:https://gitee.com/lenve
*/
@RestController
public class HelloController {

@Autowired
TemplateEngine templateEngine;

@GetMapping("/getBookInfo")
public void getBookInfo(HttpServletResponse response) throws IOException, DocumentException {
Context ctx = new Context();
ctx.setVariable("title","<深入浅出 Spring Security>图书详情");
ctx.setVariable("name","<深入浅出 Spring Security>");
ctx.setVariable("price","99.00");
ctx.setVariable("author","江南一点雨");
String bookInfo = templateEngine.process("book_info", ctx);
response.setContentType("application/pdf;charset=utf-8");
HtmlToPdfUtils.convertToPdf(bookInfo, response.getOutputStream());
}
}

先利用 TemplateEngine,将页面模版的内容转为渲染后的 HTML 字符串,然后调用工具方法去生成 PDF,生成的 PDF 直接就赋值给请求响应的输出流。

最后,我们在浏览器中访问 http://localhost:8080/getBookInfo 就可以查看生成的 PDF 内容啦~

好啦,一个简单的案例,带小伙伴们感受下 Java 生成 PDF。

文章目录
  1. 1. 一 解决方案
    1. 1.1. 1.1 iText
    2. 1.2. 1.2 OpenPDF
    3. 1.3. 1.3 Apache PDFBox
    4. 1.4. 1.4 Flyingsaucer
  2. 2. 二 iText
    1. 2.1. 2.1 什么是 iText
    2. 2.2. 2.2 案例