我们经常会遇到要导出pdf的需求,方式有很多种 今天的教程是采用itextpdf的方式生成pdf
itextpdf是用于生成PDF文档的一个java类库。通过iText不仅可以生成PDF文档,而且可以将Html文件转化为PDF文件。
这里先展示一下效果图
首先在pom.xml中引入相关依赖
<dependencys>
<!-- itext7 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>7.2.1</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>pdftest</artifactId>
<version>7.1.16</version>
<scope>test</scope>
</dependency>
</dependencys>
PdfUtil 工具类
创建pdf、获取字体
如果需要添加水印,可以自行修改对应的图片路径(static/logo.png)
其中用到的字体文件在这里下载
package com.***.utils.pdf;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.*;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.extgstate.PdfExtGState;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.layout.properties.UnitValue;
import com.itextpdf.layout.properties.VerticalAlignment;
import java.io.FileNotFoundException;
import java.io.IOException;
public class PdfUtil {
static final String LOGO_TEXT = "";
/**
* 给pdf 添加水印
*
* @param doc Document 对象
* @throws Exception
*/
public static void generateWatermark(Document doc) throws Exception {
// PdfDocument pdfDoc = new PdfDocument(new PdfReader(fis), new PdfWriter(fos));
// Document doc = new Document(pdfDoc);
// PdfFont font = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
PdfDocument pdfDoc = doc.getPdfDocument();
// 将字体包拖到路径下
PdfFont pdfFont = getZhFont();
Paragraph paragraph = new Paragraph(LOGO_TEXT).setFont(pdfFont).setFontSize(14);
ImageData img = ImageDataFactory.create(PdfUtil.class.getClassLoader().getResource("static/logo.png"));
float w = img.getWidth();
float h = img.getHeight();
PdfExtGState gs1 = new PdfExtGState().setFillOpacity(0.1f);
for (int i = 1; i <= pdfDoc.getNumberOfPages(); i++) {
PdfPage pdfPage = pdfDoc.getPage(i);
Rectangle pageSize = pdfPage.getPageSizeWithRotation();
pdfPage.setIgnorePageRotationForContent(true);
PdfCanvas over = new PdfCanvas(pdfDoc.getPage(i));
over.saveState();
over.setExtGState(gs1);
float x = pageSize.getX();
float y = pageSize.getY();
float pageWidth = pageSize.getWidth();
float pageHeight = pageSize.getHeight();
while (y < pageHeight) {
if (y == 0) y = y + 10;
while (x < pageWidth) {
// if(x==0) x = x+48;
if (x == 0) x = x + 68;
over.addImageWithTransformationMatrix(img, w / 2, 0, 0, h / 2, x, y, false);
// doc.showTextAligned(paragraph, x+32, y+38, i, TextAlignment.LEFT, VerticalAlignment.TOP, 0.3f);
x = x + 180;
}
x = pageSize.getX();
y = y + 120;
}
over.restoreState();
}
// doc.close();
}
/**
* 获取中文字体
*
* @return
* @throws IOException
*/
public static PdfFont getZhFont() throws IOException {
return PdfFontFactory.createFont(PdfUtil.class.getClassLoader().getResource("static/msyh.ttf").toString(),
PdfEncodings.IDENTITY_H);
}
/**
* 获得一个 PDF table cell
*
* @param txt text
* @param v 最大宽度百分比
* @return
*/
public static Cell newPdfCell(String txt, float v) {
return new Cell().add(
new Paragraph(txt).setTextAlignment(TextAlignment.CENTER))
.setVerticalAlignment(VerticalAlignment.MIDDLE)
.setMaxWidth(UnitValue.createPercentValue(v)
);
}
/**
* 新建 pdfDoc
*
* @param pdfPath pdfPath
* @param fileName 文件名
* @return
* @throws FileNotFoundException
*/
public static Document newPdfDoc(String pdfPath, String fileName) throws FileNotFoundException {
String filePath = pdfPath + fileName;
// pdf加密
// PdfWriter writer = new PdfWriter(filePath, new WriterProperties().setStandardEncryption(null, "Hz123456".getBytes(), EncryptionConstants.ALLOW_SCREENREADERS,
// EncryptionConstants.ENCRYPTION_AES_128));
PdfWriter writer = new PdfWriter(filePath);
PdfDocument pdf = new PdfDocument(writer);
pdf.setDefaultPageSize(PageSize.A4);
return new Document(pdf);
}
}
TableBuilder 工具类
用于构建pdf中用到的表格
package com.***.pdf;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.layout.properties.UnitValue;
import com.itextpdf.layout.properties.VerticalAlignment;
import lombok.Data;
import java.util.List;
@Data
public class TableBuilder {
/**
* pdf表格对象
*/
Table table;
/**
* 表格列数
*/
Integer column;
/**
* 每列宽度百分比
*/
Float columnWidthPercent;
/**
* 创建表格
*
* @param column 列数
* @param pdfFont 字体
* @return
*/
public static TableBuilder builder(int column, PdfFont pdfFont) {
TableBuilder tableBuilder = new TableBuilder();
tableBuilder.setColumn(column);
tableBuilder.setColumnWidthPercent(100f / column);
float[] values = new float[column];
for (int i = 0; i < column; i++) {
values[i] = 3;
}
Table table = new Table(UnitValue.createPercentArray(values))
// 这里是设置表格占整个pdf的宽度百分比,这里设置的是100%
.setWidth(UnitValue.createPercentValue(100))
.setTextAlignment(TextAlignment.CENTER)
.setVerticalAlignment(VerticalAlignment.MIDDLE)
// 设置字体
.setFont(pdfFont)
// 设置字体大小
.setFontSize(10);
tableBuilder.setTable(table);
return tableBuilder;
}
// 这里添加数据时,需要注意,每一行的数据个数必须与表格列数一致,单元格无数据时,添加空字符串
/**
* 添加一行数据
* @param row 一行数据
* @return
*/
public TableBuilder addRow(List<String> row) {
for (String item : row) {
this.table.addCell(PdfUtil.newPdfCell(item, this.columnWidthPercent));
}
return this;
}
/**
* 添加多行数据
* @param rowList 多行数据
* @return
*/
public TableBuilder addRows(List<List<String>> rowList) {
for (List<String> row : rowList) {
this.addRow(row);
}
return this;
}
/**
* 获取表格对象
* @return
*/
public Table build() {
return this.table;
}
}
使用以上工具类构建一个测试的pdf,测试pdf效果在文章开头查看
package com.***;
import com.***.utils.pdf.PdfUtil;
import com.***.utils.pdf.TableBuilder;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Div;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.HorizontalAlignment;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.layout.properties.UnitValue;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public class PdfTest {
@Test
public void testPdf() throws IOException {
Document document = PdfUtil.newPdfDoc("/Desktop/", "test.pdf");
// 这里的字体对象一个pdf用一次,不能重复(多个pdf)使用,否则会报错
PdfFont pdfFont = PdfUtil.getZhFont();
Div head1Div = new Div().setWidth(UnitValue.createPercentValue(100))
.setHeight(UnitValue.createPercentValue(100))
.setHorizontalAlignment(HorizontalAlignment.CENTER);
// 标题,22号字体,居中对齐,加粗
Paragraph title = new Paragraph("测试pdf标题")
.setFont(pdfFont).setFontSize(22).setHorizontalAlignment(HorizontalAlignment.CENTER)
.setTextAlignment(TextAlignment.CENTER).setBold();
head1Div.add(title);
head1Div.add(
new Paragraph("一、第一部分:测试表格")
.setFont(pdfFont).setFontSize(16).setBold()
);
List<String> header = Arrays.asList("姓名", "年龄", "性别", "手机号", "邮箱", "地址", "职业", "备注");
List<List<String>> data = Arrays.asList(
Arrays.asList("张三", "25", "男", "13812345678", "zhangsan@qq.com", "北京市海淀区", "学生", "无"),
Arrays.asList("王五", "28", "男", "13812345680", "wangwu@qq.com", "广东省深圳市", "律师", "无")
);
// 表格,8列,字体为pdfFont
Table table = TableBuilder.builder(8, pdfFont)
.addRow(header).addRows(data).build();
head1Div.add(table);
document.add(head1Div);
document.close();
}
}