package org.demo;
import com.lowagie.text.*;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List;
/**
* 使用OpenPDF将列表数据导出为PDF文件的工具类
*/
public class ListToPdfExporter {
private static BaseFont getBaseFont() {
try {
// 加载本地自定义字体(以思源黑体为例)
BaseFont baseFont = BaseFont.createFont(
"xx/NotoSansSC-Black.ttf", // 字体文件路径(相对于resources目录)
BaseFont.IDENTITY_H, // 支持中文的编码方式
BaseFont.EMBEDDED // 将字体嵌入PDF,确保在其他设备上正常显示
);
return baseFont;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 将列表数据导出为PDF文件
*
* @param dataList 要导出的数据列表
* @param filePath 导出的PDF文件路径
* @param title PDF文档标题
* @param <T> 数据类型
* @throws DocumentException PDF文档处理异常
* @throws FileNotFoundException 文件未找到异常
* @throws IllegalAccessException 反射访问异常
*/
public static <T> void export(List<T> dataList, String filePath, String title)
throws DocumentException, IOException, IllegalAccessException {
// 检查输入参数
if (dataList == null || dataList.isEmpty()) {
throw new IllegalArgumentException("数据列表不能为空");
}
if (filePath == null || filePath.trim().isEmpty()) {
throw new IllegalArgumentException("文件路径不能为空");
}
// 创建文档对象,设置页面大小为A4,左右上下边距为50
Document document = new Document(PageSize.A4, 50, 50, 50, 50);
// 创建PdfWriter对象,将文档写入指定文件
PdfWriter.getInstance(document, new FileOutputStream(filePath));
// 打开文档
document.open();
// 添加标题
Font titleFont = new Font(getBaseFont(), 18, Font.BOLD);
Paragraph titleParagraph = new Paragraph(title, titleFont);
titleParagraph.setAlignment(Element.ALIGN_CENTER);
titleParagraph.setSpacingAfter(20); // 标题后间距
document.add(titleParagraph);
// 获取数据类的所有字段(作为表格列)
Class<?> dataClass = dataList.get(0).getClass();
Field[] fields = dataClass.getDeclaredFields();
int columnCount = fields.length;
// 创建表格,列数为字段数量
PdfPTable table = new PdfPTable(columnCount);
table.setWidthPercentage(100); // 表格宽度占页面100%
table.setSpacingBefore(10f); // 表格前间距
table.setSpacingAfter(10f); // 表格后间距
// 设置表格列宽比例(平均分配)
float[] columnWidths = new float[columnCount];
for (int i = 0; i < columnCount; i++) {
columnWidths[i] = 1.0f;
}
table.setWidths(columnWidths);
// 添加表头(使用字段名)
Font headerFont = new Font(getBaseFont(), 12, Font.BOLD);
for (Field field : fields) {
PdfPCell cell = new PdfPCell(new Phrase(field.getName(), headerFont));
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
//cell.setBackgroundColor(BaseColor.LIGHT_GRAY);
table.addCell(cell);
}
// 添加数据行
// Font dataFont = new Font(Font.HELVETICA, 10, Font.NORMAL);
// 使用自定义字体创建Font对象,替代原来的Font.HELVETICA
Font dataFont = new Font(getBaseFont(), 10, Font.NORMAL);
for (T data : dataList) {
for (Field field : fields) {
field.setAccessible(true); // 设置可访问私有字段
Object value = field.get(data);
String cellValue = value != null ? value.toString() : "";
PdfPCell cell = new PdfPCell(new Phrase(cellValue, dataFont));
cell.setHorizontalAlignment(Element.ALIGN_LEFT);
table.addCell(cell);
}
}
// 将表格添加到文档
document.add(table);
// 添加页脚信息
Paragraph footer = new Paragraph("导出时间: " + new java.util.Date(), new Font(Font.HELVETICA, 8));
footer.setAlignment(Element.ALIGN_RIGHT);
footer.setSpacingBefore(20);
document.add(footer);
// 关闭文档
document.close();
System.out.println("PDF文件已成功导出至: " + filePath);
}
// 测试用的实体类
public static class User {
private String name;
private int age;
private String email;
private String address;
public User(String name, int age, String email, String address) {
this.name = name;
this.age = age;
this.email = email;
this.address = address;
}
// getter和setter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
// 测试方法
public static void main(String[] args) {
try {
// 创建测试数据列表
List<User> userList = List.of(
new User("张三", 25, "zhangsan@example.com", "北京市朝阳区"),
new User("李四", 30, "lisi@example.com", "上海市浦东新区"),
new User("王五", 35, "wangwu@example.com", "广州市天河区"),
new User("赵六", 28, "zhaoliu@example.com", "深圳市南山区")
);
// 导出为PDF
export(userList, "用户列表.pdf", "系统用户信息列表");
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 字体库 https://github.com/adobe-fonts/source-han-sans/releases/tag/2.005R
不使用字体库,会导致生成的PDF不显示中文,因为默认的字体库不支持中文编码
OpenPDF依赖
<dependency>
<groupId>com.github.librepdf</groupId>
<artifactId>openpdf</artifactId>
<version>1.3.30</version>
</dependency>