在Java后端做PDF这件事,绕不开的是iText。最近总有人拿“iText接口api”来问,仔细一看,多数是卡在这几个点上:7.x和5.x的API完全对不上、中文字体显示成方块、生僻字直接消失、以及不知道怎么把生成逻辑包装成一个可以稳定对外调用的接口api。这篇就把这些事从头到尾捋一遍。内容对新手友好,也适合已经写过几版PDF的老手查缺补漏;哪怕你用的是C#、Python,只要了解PDF库设计,看完思路也能平移。
1. 先把iText新老接口的坑摸清楚
1.1 为什么一提“iText接口api”大家就头疼
老项目里大量使用的是iText 5.x/2.x时代的写法:
java复制Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream("foo.pdf"));
document.open();
document.add(new Paragraph("Hello"));
document.close();
这段代码在论坛里还能搜到,但它属于iText 5时代的“老接口”。iText 7从架构上做了大幅重构,接口api设计从职责分散的静态工具类改成了更接近文档对象模型的方式,类之间的协作关系也变了。如果你把5.x的代码直接粘到7.x工程里,编译期就会报一堆错。所以“iText接口api”这个热搜词背后,其实藏着三类需求:一类是搞不清iText自己的API怎么调,一类是想把生成PDF的能力封装成一个接口api给其他服务调用,还有一类是被“Flying Saucer生僻字乱码”这类问题逼着来找方案的。这三类我今天都会覆盖到。
1.2 从对象模型理解iText 7的接口设计
iText 7的核心对象建议先记五个:PdfWriter、PdfReader、PdfDocument、Document、PdfFont。PdfWriter负责把字节流写到文件、内存或网络;PdfReader负责读一份已经存在的PDF;PdfDocument是PDF文档的底层抽象,相当于一张还没排版的白纸;Document是高层门面,你平时调用的add Paragraph、add Table,操作的都是它;PdfFont负责解决“字从哪来”的问题。
这个设计的逻辑是:把所有读、写、排版、字体问题拆开,每个对象只干一件事。接口api看着分散,组合起来反而灵活。比如要给已有PDF加一页内容,不需要重新生成整份文档,用PdfReader加PdfDocument就能实现;要合并多个PDF,用一个PdfMerger对象搞定;要做表单填充,有PdfAcroForm和PdfFormField。这类小工具对象在5.x里大多是静态方法,7.x则更强调持有状态的对象,所以你在调用时要先new对象、再调方法,而不是直接调一个静态工具类。
提示:查iText 7的API时,优先看官方文档javadoc,注意版本号。网上很多教程是5.x的,你在7.x工程里直接抄会非常痛苦。
1.3 版本选择建议:5.x还是7.x
面向长期维护的项目,我建议直接上7.x。理由很实在:
| 对比项 | iText 5.x | iText 7.x |
|---|---|---|
| API风格 | 静态工厂+PdfWriter | 对象协作,链式写法 |
| 中文字体 | 依赖font-asian,配置较绕 | 也需要字体注册,但流程清晰 |
| 官方维护 | 低版本功能更新早已冻结 | 持续迭代,有商业双授权 |
| 教程存量 | 老教程多,容易误导 | 官方文档齐全,中文资料偏少 |
| 新能力 | 不支持HTML转PDF | 有独立的pdfHTML模块 |
有些老系统还停在5.x,改动成本太高,那就维持现状别硬迁。如果是从零开始,直接学7.x,不要在旧教程上耽误时间。后面我所有的代码示例都基于iText 7.x。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 从一行代码到一份完整PDF
2.1 Maven依赖怎么配
iText 7拆成了多个模块,官方叫add-on。基础功能最少需要kernel、io、layout三个包。在pom里加上:
xml复制<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>kernel</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>
版本号我用的是7.2.5,你可以换成当前最新的稳定版。注意这三个包的版本必须一致,混用会导致方法签名对不上,报NoSuchMethodError。
如果要做HTML转PDF,再额外引入:
