Java PDF导出工具:自定义表格与图片插入
下面我将实现一个Java PDF导出工具,支持插入自定义表格和图片的功能。这个解决方案使用iText 7库,提供了一个直观的用户界面,可以预览生成的PDF内容。
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.property.TextAlignment;
import com.itextpdf.layout.property.UnitValue;
public class PDFExporter extends JFrame {
private JTable table;
private DefaultTableModel tableModel;
private JTextArea previewArea;
private List<String> imagePaths = new ArrayList<>();
private PdfFont font;
private PdfFont titleFont;
public PDFExporter() {
super("PDF导出工具 - 支持自定义表格与图片插入");
setSize(900, 700);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
initFonts();
initUI();
}
private void initFonts() {
try {
// 创建字体(实际应用中应使用支持中文的字体文件)
font = PdfFontFactory.createFont();
titleFont = PdfFontFactory.createFont(PdfFontFactory.HELVETICA_BOLD);
} catch (Exception e) {
e.printStackTrace();
font = PdfFontFactory.createFont(PdfFontFactory.COURIER);
titleFont = PdfFontFactory.createFont(PdfFontFactory.COURIER_BOLD);
}
}
private void initUI() {
// 创建主面板
JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
mainPanel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
// 创建顶部面板
JPanel topPanel = new JPanel(new BorderLayout(10, 10));
// 表格模型
String[] columns = {"书名", "作者", "价格 (¥)", "出版年份", "评分"};
tableModel = new DefaultTableModel(columns, 0);
table = new JTable(tableModel);
table.setRowHeight(30);
table.setFont(new Font("微软雅黑", Font.PLAIN, 14));
// 添加示例数据
addSampleData();
JScrollPane tableScroll = new JScrollPane(table);
tableScroll.setBorder(BorderFactory.createTitledBorder("自定义表格数据"));
topPanel.add(tableScroll, BorderLayout.CENTER);
// 表格操作按钮
JPanel tableButtonPanel = new JPanel(new GridLayout(5, 1, 5, 5));
JButton addRowBtn = new JButton("添加行");
JButton deleteRowBtn = new JButton("删除行");
JButton addImageBtn = new JButton("添加图片");
JButton previewBtn = new JButton("预览PDF");
JButton exportBtn = new JButton("导出PDF");
addRowBtn.addActionListener(e -> tableModel.addRow(new Object[]{"", "", "", "", ""}));
deleteRowBtn.addActionListener(e -> {
int row = table.getSelectedRow();
if (row != -1) {
tableModel.removeRow(row);
}
});
addImageBtn.addActionListener(e -> addImage());
previewBtn.addActionListener(e -> previewPDF());
exportBtn.addActionListener(e -> exportPDF());
tableButtonPanel.add(addRowBtn);
tableButtonPanel.add(deleteRowBtn);
tableButtonPanel.add(addImageBtn);
tableButtonPanel.add(previewBtn);
tableButtonPanel.add(exportBtn);
topPanel.add(tableButtonPanel, BorderLayout.EAST);
// 预览区域
previewArea = new JTextArea();
previewArea.setFont(new Font("等线", Font.PLAIN, 14));
previewArea.setEditable(false);
previewArea.setBackground(new Color(240, 240, 240));
previewArea.setBorder(BorderFactory.createTitledBorder("PDF预览内容"));
JScrollPane previewScroll = new JScrollPane(previewArea);
previewScroll.setPreferredSize(new Dimension(0, 200));
// 添加组件到主面板
mainPanel.add(topPanel, BorderLayout.CENTER);
mainPanel.add(previewScroll, BorderLayout.SOUTH);
add(mainPanel);
// 状态栏
JLabel statusBar = new JLabel("就绪 | 添加表格数据并插入图片,然后导出PDF");
statusBar.setBorder(BorderFactory.createEtchedBorder());
add(statusBar, BorderLayout.SOUTH);
updatePreview();
}
private void addSampleData() {
Object[][] data = {
{"Java核心技术", "Cay S. Horstmann", "128.50", "2022", "4.8"},
{"Effective Java", "Joshua Bloch", "99.80", "2018", "4.9"},
{"深入理解Java虚拟机", "周志明", "119.00", "2019", "4.7"},
{"Spring实战", "Craig Walls", "89.90", "2020", "4.6"},
{"Python编程:从入门到实践", "Eric Matthes", "75.00", "2021", "4.7"}
};
for (Object[] row : data) {
tableModel.addRow(row);
}
}
private void addImage() {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setDialogTitle("选择要插入的图片");
fileChooser.setMultiSelectionEnabled(true);
int result = fileChooser.showOpenDialog(this);
if (result == JFileChooser.APPROVE_OPTION) {
for (File file : fileChooser.getSelectedFiles()) {
imagePaths.add(file.getAbsolutePath());
}
updatePreview();
JOptionPane.showMessageDialog(this, "已添加 " + fileChooser.getSelectedFiles().length + " 张图片", "添加图片", JOptionPane.INFORMATION_MESSAGE);
}
}
private void updatePreview() {
StringBuilder sb = new StringBuilder();
sb.append("PDF 内容预览:\n");
sb.append("----------------------------------------\n");
sb.append("标题: 图书清单报告\n\n");
sb.append("表格数据 (").append(tableModel.getRowCount()).append(" 行):\n");
for (int col = 0; col < tableModel.getColumnCount(); col++) {
sb.append(String.format("%-20s", tableModel.getColumnName(col)));
}
sb.append("\n");
for (int row = 0; row < tableModel.getRowCount(); row++) {
for (int col = 0; col < tableModel.getColumnCount(); col++) {
Object value = tableModel.getValueAt(row, col);
sb.append(String.format("%-20s", value != null ? value.toString() : ""));
}
sb.append("\n");
}
sb.append("\n图片列表 (").append(imagePaths.size()).append(" 张):\n");
for (String path : imagePaths) {
sb.append("• ").append(new File(path).getName()).append("\n");
}
previewArea.setText(sb.toString());
}
private void previewPDF() {
try {
File tempFile = File.createTempFile("pdf_preview", ".pdf");
createPDF(tempFile.getAbsolutePath());
if (Desktop.isDesktopSupported()) {
Desktop.getDesktop().open(tempFile);
} else {
JOptionPane.showMessageDialog(this,
"PDF预览已生成: " + tempFile.getAbsolutePath(),
"预览生成成功",
JOptionPane.INFORMATION_MESSAGE);
}
} catch (Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(this,
"生成预览时出错: " + ex.getMessage(),
"错误",
JOptionPane.ERROR_MESSAGE);
}
}
private void exportPDF() {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setDialogTitle("保存PDF文件");
fileChooser.setSelectedFile(new File("图书清单报告.pdf"));
int result = fileChooser.showSaveDialog(this);
if (result == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
String filePath = file.getAbsolutePath();
if (!filePath.toLowerCase().endsWith(".pdf")) {
filePath += ".pdf";
}
try {
createPDF(filePath);
JOptionPane.showMessageDialog(this,
"PDF导出成功: " + filePath,
"导出成功",
JOptionPane.INFORMATION_MESSAGE);
if (Desktop.isDesktopSupported()) {
Desktop.getDesktop().open(new File(filePath));
}
} catch (Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(this,
"导出PDF时出错: " + ex.getMessage(),
"错误",
JOptionPane.ERROR_MESSAGE);
}
}
}
private void createPDF(String filePath) throws Exception {
try (PdfWriter writer = new PdfWriter(filePath);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf)) {
// 设置文档属性
document.setMargins(50, 50, 50, 50);
// 添加标题
Paragraph title = new Paragraph("图书清单报告")
.setFont(titleFont)
.setFontSize(24)
.setTextAlignment(TextAlignment.CENTER)
.setFontColor(ColorConstants.DARK_GRAY)
.setMarginBottom(20);
document.add(title);
// 添加副标题
Paragraph subtitle = new Paragraph("自定义表格与图片展示")
.setFont(font)
.setFontSize(16)
.setTextAlignment(TextAlignment.CENTER)
.setFontColor(ColorConstants.GRAY)
.setMarginBottom(30);
document.add(subtitle);
// 添加表格
addTableToDocument(document);
// 添加图片
addImagesToDocument(document);
// 添加页脚
Paragraph footer = new Paragraph("生成时间: " + new java.util.Date())
.setFont(font)
.setFontSize(10)
.setTextAlignment(TextAlignment.CENTER)
.setFontColor(ColorConstants.LIGHT_GRAY)
.setMarginTop(30);
document.add(footer);
}
}
private void addTableToDocument(Document document) {
// 创建表格
float[] columnWidths = {3, 2, 1, 1, 1};
Table pdfTable = new Table(UnitValue.createPercentArray(columnWidths));
pdfTable.setWidth(UnitValue.createPercentValue(100));
pdfTable.setMarginBottom(30);
// 添加表头
for (int col = 0; col < tableModel.getColumnCount(); col++) {
Cell headerCell = new Cell()
.add(new Paragraph(tableModel.getColumnName(col))
.setFont(titleFont)
.setFontSize(12)
.setBackgroundColor(new com.itextpdf.kernel.color.Color(230, 230, 230))
.setTextAlignment(TextAlignment.CENTER);
pdfTable.addHeaderCell(headerCell);
}
// 添加表格数据
for (int row = 0; row < tableModel.getRowCount(); row++) {
for (int col = 0; col < tableModel.getColumnCount(); col++) {
Object value = tableModel.getValueAt(row, col);
String text = value != null ? value.toString() : "";
Cell dataCell = new Cell()
.add(new Paragraph(text))
.setFont(font)
.setFontSize(11);
// 设置特殊列的样式
if (col == 2) { // 价格列
dataCell.setTextAlignment(TextAlignment.RIGHT);
} else if (col == 4) { // 评分列
try {
double rating = Double.parseDouble(text);
if (rating >= 4.5) {
dataCell.setFontColor(ColorConstants.GREEN);
} else if (rating >= 4.0) {
dataCell.setFontColor(ColorConstants.BLUE);
} else {
dataCell.setFontColor(ColorConstants.ORANGE);
}
} catch (NumberFormatException e) {
// 忽略格式错误
}
dataCell.setTextAlignment(TextAlignment.CENTER);
} else {
dataCell.setTextAlignment(TextAlignment.LEFT);
}
pdfTable.addCell(dataCell);
}
}
document.add(pdfTable);
}
private void addImagesToDocument(Document document) throws Exception {
if (imagePaths.isEmpty()) return;
// 添加图片标题
Paragraph imageTitle = new Paragraph("图书封面")
.setFont(titleFont)
.setFontSize(16)
.setMarginBottom(15);
document.add(imageTitle);
// 添加图片
for (String path : imagePaths) {
if (!Files.exists(Paths.get(path))) continue;
try {
ImageData imageData = ImageDataFactory.create(path);
Image pdfImage = new Image(imageData);
// 调整图片大小(最大宽度400px,保持宽高比)
float width = pdfImage.getImageWidth();
float height = pdfImage.getImageHeight();
float maxWidth = 400;
if (width > maxWidth) {
float ratio = maxWidth / width;
pdfImage.scale(ratio, ratio);
}
// 居中显示
pdfImage.setHorizontalAlignment(com.itextpdf.layout.property.HorizontalAlignment.CENTER);
pdfImage.setMarginBottom(20);
document.add(pdfImage);
} catch (Exception e) {
System.err.println("无法加载图片: " + path);
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
PDFExporter exporter = new PDFExporter();
exporter.setVisible(true);
});
}
}
使用说明
要运行此程序,您需要以下依赖项:
- iText 7 Core库 (用于PDF生成)
- Java Swing (用于GUI)
Maven依赖配置
<dependencies>
<!-- iText 7 Core -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>7.2.5</version>
<type>pom</type>
</dependency>
<!-- 其他必要的依赖项 -->
</dependencies>
程序功能
表格自定义:
- 添加/删除表格行
- 编辑表格内容
- 支持多列数据
图片插入:
- 添加多张图片
- 自动调整图片大小
- 保持图片宽高比
PDF操作:
- 预览生成的PDF
- 导出PDF文件
- 自动打开生成的PDF
用户界面:
- 表格数据编辑区
- PDF内容预览区
- 操作按钮面板
使用步骤
- 在表格中编辑或添加图书数据
- 点击"添加图片"按钮插入图书封面
- 使用"预览PDF"查看效果
- 满意后点击"导出PDF"保存文件
程序会自动为表格添加样式,并根据评分值显示不同颜色,使生成的PDF更具可读性。
注意:实际使用中,您可能需要添加中文字体支持以正确显示中文内容。