首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java POI 實戰:Excel 文件生成與圖片導出完整指南

     編輯:Java 相關知識

前言

Apache POI 是 Java 操作 Microsoft Office 文件的標準庫,廣泛應用於報表導出、數據導入等場景。本文詳細講解如何使用 POI 生成 Excel 文件,並重點解決圖片導出的定位與縮放難題。

一、Excel 文件結構與核心物件

POI 中 Excel 文件層級結構:

  • HSSFWorkbook (.xls) / XSSFWorkbook (.xlsx) - 工作簿
  • HSSFSheet / XSSFSheet - 工作表
  • HSSFRow / XSSFRow - 行
  • HSSFCell / XSSFCell - 儲存格

二、基礎 Excel 生成實作

1. 實體類定義

public class ErrorCondition {
    private String name;      // 姓名
    private String idCard;    // 身份證
    private String status;    // 錯誤狀態
    private String message;   // 錯誤信息
    
    // 建構子、getter/setter 省略
}

2. 導出服務實作

public class ExportErrorExcel {
    public static void main(String[] args) {
        // 1. 建立工作簿
        HSSFWorkbook wb = new HSSFWorkbook();
        
        // 2. 建立工作表
        HSSFSheet sheet = wb.createSheet("身份證錯誤信息");
        
        // 3. 建立表頭樣式
        HSSFCellStyle headerStyle = wb.createCellStyle();
        headerStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        
        // 4. 寫入表頭
        HSSFRow headerRow = sheet.createRow(0);
        String[] headers = {"姓名", "身份證", "錯誤狀態", "錯誤信息"};
        for (int i = 0; i < headers.length; i++) {
            HSSFCell cell = headerRow.createCell(i);
            cell.setCellValue(headers[i]);
            cell.setCellStyle(headerStyle);
        }
        
        // 5. 寫入數據
        List<ErrorCondition> list = getErrorData();
        for (int i = 0; i < list.size(); i++) {
            ErrorCondition data = list.get(i);
            HSSFRow row = sheet.createRow(i + 1);
            row.createCell(0).setCellValue(data.getName());
            row.createCell(1).setCellValue(data.getIdCard());
            row.createCell(2).setCellValue(data.getStatus());
            row.createCell(3).setCellValue(data.getMessage());
        }
        
        // 6. 自動調整列寬
        for (int i = 0; i < headers.length; i++) {
            sheet.autoSizeColumn(i);
        }
        
        // 7. 寫入文件
        try (FileOutputStream fos = new FileOutputStream("D:/errorCondition.xls")) {
            wb.write(fos);
            System.out.println("Excel 文件生成成功");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private static List<ErrorCondition> getErrorData() {
        // 測試數據...
    }
}

三、圖片導出核心技術

1. 關鍵類別

  • HSSFPatriarch:繪圖管理器,每個 Sheet 只能有一個
  • HSSFClientAnchor:圖片錨點,控制位置與大小
  • HSSFPicture:圖片物件

2. 錨點參數詳解

HSSFClientAnchor anchor = new HSSFClientAnchor(
    dx1, dy1, dx2, dy2,   // 起始/終止儲存格內的相對座標 (0-1023, 0-255)
    col1, row1,           // 起始儲存格 (列, 行)
    col2, row2            // 終止儲存格 (列, 行)
);

參數說明:

  • dx1, dy1:圖片左上角在起始儲存格內的偏移量
  • dx2, dy2:圖片右下角在終止儲存格內的偏移量
  • col1, row1:左上角所在儲存格(0 基索引)
  • col2, row2:右下角所在儲存格
  • anchor.setAnchorType(3):移動且不調整大小(預設 0:移動並調整大小)

3. 單張圖片導出完整範例

public class ExcelImageExport {
    public static void main(String[] args) {
        try (FileOutputStream fos = new FileOutputStream("D:/test_image.xls")) {
            HSSFWorkbook wb = new HSSFWorkbook();
            HSSFSheet sheet = wb.createSheet("圖片測試");
            
            // 讀取圖片轉為位元組陣列
            BufferedImage img = ImageIO.read(new File("F:/photo.jpg"));
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(img, "jpg", baos);
            byte[] imgBytes = baos.toByteArray();
            
            // 獲取繪圖管理器
            HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
            
            // 設定錨點:跨儲存格 B2 到 F9
            HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 1023, 255, 1, 1, 5, 8);
            anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_DONT_RESIZE);
            
            // 導出圖片
            int pictureIdx = wb.addPicture(imgBytes, HSSFWorkbook.PICTURE_TYPE_JPEG);
            patriarch.createPicture(anchor, pictureIdx);
            
            wb.write(fos);
            System.out.println("圖片導出成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4. 多張圖片導出策略

// 建立多個錨點,控制不同位置
HSSFClientAnchor anchor1 = new HSSFClientAnchor(0, 0, 1023, 255, 1, 1, 5, 8);   // 第 1-8 行
HSSFClientAnchor anchor2 = new HSSFClientAnchor(0, 0, 1023, 255, 1, 9, 5, 16); // 第 9-16 行

patriarch.createPicture(anchor1, pictureIdx);
patriarch.createPicture(anchor2, pictureIdx);

四、進階技巧與避坑指南

1. 圖片自適應儲存格大小

// 獲取圖片原始尺寸
BufferedImage img = ImageIO.read(new File(path));
int imgWidth = img.getWidth();
int imgHeight = img.getHeight();

// 計算縮放比例,適應儲存格
double scale = Math.min((double)cellWidth / imgWidth, (double)cellHeight / imgHeight);
// 設置錨點 dx2, dy2 實現縮放
anchor.setDx2((int)(1023 * scale));
anchor.setDy2((int)(255 * scale));

2. 大數據量導出優化 (SXSSF)

// 使用 SXSSF (流式處理),僅保留最近 100 行在記憶體
SXSSFWorkbook wb = new SXSSFWorkbook(100);
SXSSFSheet sheet = wb.createSheet("大數據導出");
// 後續操作與 HSSF 相同
// 寫入後需手動釋放臨時文件
wb.dispose();

3. 常見問題解決

問題原因解決方案
圖片顯示為紅叉 圖片格式不支援或路徑錯誤 確認使用 JPEG/PNG,檢查文件路徑
圖片位置偏移 錨點參數理解錯誤 仔細核對 col1/row1/col2/row2 對應關係
導出文件打不開 Workbook 未正確 close 使用 try-with-resources 確保資源釋放
OOM 記憶體溢出 大量數據載入記憶體 使用 SXSSF 流式寫入

五、總結

掌握 POI 的核心在於理解 Workbook → Sheet → Row → Cell 的層級關係,以及 Patriarch + Anchor + Picture 的圖片導出三要素。實際專案中建議封裝通用的導出工具類,支援模板導出、樣式複用、大數據流式處理等企業級需求。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved