重要声明:本文章仅仅代表了作者个人对此观点的理解和表述。读者请查阅时持自己的意见进行讨论。
前言
有时候,业务系统要求提供一个PDF文件导出的功能,这时候我们就需要将数据库的对应数据查询出来,然后生成PDF并提供下载,这其中比较陌生的部分相信就是如何使用这些数据生成一个PDF文件了,本文讲述了使用 Itext
在Java后端生成PDF的方法,不妨来看看一吧。
一、加入依赖
Itext 的官方地址是:https://itextpdf.com。
首要第一步则是加入Itext的依赖,然后才可以使用相关的操作类。Itext 的依赖不是都在一个包里,它分了许许多多模块,但基本的生成PDF的依赖包只需要引入2个即可。
首先是核心包:
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
然后需要引入对中文支持的包,毕竟大部分文档中都会有中文内容的。
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
只需要引入这两个包,就可以完成基本的生成PDF操作了。
二、开始使用
Itext 的用法十分简单,大致可以分为下面几步:
- 构建文档
- 打开文档编辑功能
- 插入文档内容
- 关闭文档编辑功能
1、构建文档
Itext 构建文档是通过 Document
类进行构建,不过要注意,大多数项目里面应该存在许多个 Document
类了,这里一定要使用 com.itextpdf.text
包下面的 Document
类。这个类包含一个无参构造函数,意味着可以十分方便的 new 一个空文档出来:
Document document = new Document();
默认创建的是 A4 纸大小、内边距 36 的PDF文档。如果你希望创建不同大小以及不同边距的文档,你可以使用带参构造函数:
Document documentA8 = new Document(PageSize.A8);
Document documentA8_2 = new Document(PageSize.A8, 10, 10, 10,10);
这里构建了 2 个文档,第一个文档设定了大小为 A8 纸张大小, 第二个文档设定了边距为 10,这些边距值分别对应左, 右, 上, 下。构建好了文档,就可以开始进行文档编辑了。
2、 打开文档编辑功能
在编辑之前,需要先认识一个类 PdfWriter
,这个类帮助我们打开文档的编辑功能,同时能指定将pdf文件输出到对应的输出流里面,意味着我们如果使用文件输出流,它就可以将pdf文件输出到文件中。
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream("D:/test.pdf"));
document.open();
使用 PdfWriter.getInstance
方法可以将文件到指定输出流,传入文件输出流可实现输出到文件。然后调用 document.open
方法打开编辑功能,只有调用了此方法之后,才可以对 document 进行编辑。
3、 插入内容及中文
现在,可以放心的向文档中插入内容了,不如先插入一个段落在文档中试一试, 使用 com.itextpdf.text.Paragraph
类可以实现对段落的构建,先来看个效果:
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream("D:/test.pdf"));
document.open();
// 新建一个段落,内容 Hello Pdf.
Paragraph p1 = new Paragraph("Hello Pdf.");
document.add(p1);
document.close();
最后不要忘了执行关闭。打开D盘,发现文件test.pdf,效果如图:
似乎非常完美,但当我把 “Hello” 改成 “你好”后,再一次生成文档:
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream("D:/test.pdf"));
document.open();
Paragraph p1 = new Paragraph("你好 Pdf.");
document.add(p1);
document.close();
再次运行,得到效果:
发现中文并没有被显示出来,这时候就需要用到刚才添加的第二个依赖了。要让中文显示正常,需要借助中文字体来实现这个需求,itext-asian
包内置了一个中文字体提供使用。建立使用 itext-asian
内置中文支持:
BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
Font mfont = new Font(bfChinese, 15, Font.NORMAL, BaseColor.BLACK);
首先使用内置字体建立基本字体类型,然后建立段落可以使用的字体对象,最后,mfont
对象就可以传递给 Paragraph
,从而实现中文支持。代码如下:
BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
Font mfont = new Font(bfChinese, 15, Font.NORMAL, BaseColor.BLACK);
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream("D:/test.pdf"));
document.open();
Paragraph p1 = new Paragraph("你好 Pdf.", mfont);
document.add(p1);
document.close();
运行效果图如下:
.
有时候这个字体并不能满足需求,你可以自己使用自己的字体文件来实现个性化字体:
// 使用window内置的等线字体
BaseFont.createFont("C:/Windows/Fonts/Deng.ttf", BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED);
// 使用自己的字体文件
BaseFont.createFont("D:/思源黑体正常字体.ttf", BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED);
三、Itext 提供的各种文档组件
上面简单的介绍了段落使用方法,其实Itext除了段落组件,还提供了许多其他的组件封装,比较常用的组件见下表:
类 | 介绍 |
---|---|
com.itextpdf.text.Anchor | 功能类似锚点、超链接 |
com.itextpdf.text.Chapter | 章节 |
com.itextpdf.text.Chunk | 能添加到文档里的最小文本块 |
com.itextpdf.text.Header | 这个信息不会显示到pdf,常常是编辑者自己定义的一些文档先关信息 |
com.itextpdf.text.Image | 图片 |
com.itextpdf.text.Jpeg | Jpeg的图片,其实它继承自Image |
com.itextpdf.text.List | 列表,这里面放 ListItem |
com.itextpdf.text.ListItem | 列表条目 |
com.itextpdf.text.Meta | 这个和Header类似,但这是固定的一些文档信息,字段名只允许:subject,title,keywords,author,creationdate,producer |
com.itextpdf.text.Paragraph | 文本段落 |
com.itextpdf.text.Phrase | 文本,这就好像html里面的span,它可以设定自己的样式。 |
四、导出PDF
当你把你的各个数据全部写入到了 document
里面后,就可以将这个 document
导出给请求端了,如果我们把这个文档像这样进行构建写操作:
PdfWriter.getInstance(document, new FileOutputStream("D:/test.pdf"));
那么我们的pdf文件就会被保存到服务器里面,而我们的目标是导出给请求端,所以,只需要把 第二个参数从文件输出流变成响应输出流即可:
// ... 更多代码
PdfWriter.getInstance(document, response.getOutputStream());
// ... 跟多代码