Java 导出PDF 1、内容可以插入自定义表格 2、内容插入图片

发布于:2025-07-05 ⋅ 阅读:(20) ⋅ 点赞:(0)

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);
        });
    }
}

使用说明

要运行此程序,您需要以下依赖项:

  1. iText 7 Core库 (用于PDF生成)
  2. 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>

程序功能

  1. 表格自定义

    • 添加/删除表格行
    • 编辑表格内容
    • 支持多列数据
  2. 图片插入

    • 添加多张图片
    • 自动调整图片大小
    • 保持图片宽高比
  3. PDF操作

    • 预览生成的PDF
    • 导出PDF文件
    • 自动打开生成的PDF
  4. 用户界面

    • 表格数据编辑区
    • PDF内容预览区
    • 操作按钮面板

使用步骤

  1. 在表格中编辑或添加图书数据
  2. 点击"添加图片"按钮插入图书封面
  3. 使用"预览PDF"查看效果
  4. 满意后点击"导出PDF"保存文件

程序会自动为表格添加样式,并根据评分值显示不同颜色,使生成的PDF更具可读性。

注意:实际使用中,您可能需要添加中文字体支持以正确显示中文内容。