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

Apache POI 深度解析:Excel 單元格樣式複製、數據讀取與公式處理實戰

     編輯:Java 綜合教學

前言:為什麼選擇 Apache POI?

在 Java 處理 Excel 的領域中,Apache POI 與 JXL 是兩大主流庫。作為 POI 的長期使用者,我更傾向於 POI,主要因為它對現代 Excel 格式(.xlsx,即 Office 2007+ 版本)支援更完善,且社群活躍、文檔豐富。本文將通過實際代碼示例,詳細講解如何使用 POI 進行單元格樣式深度複製、不同類型數據的讀取策略,以及公式的讀寫操作。

核心技術點一:單元格樣式的完整深度複製

Excel 單元格包含豐富的樣式信息:字體、邊框、填充顏色、對齊方式、數據格式等。在跨 Workbook 複製數據時,必須將樣式完整克隆。以下是一個生產級的樣式複製工具方法,處理了空指針、顏色對象轉換等邊界情況:

public XSSFCellStyle cloneAllCellStyle(XSSFCell sourceCell, XSSFWorkbook targetWb) {
    // 1. 在目標工作簿中創建新樣式
    XSSFCellStyle tempStyle = targetWb.createCellStyle();
    
    // 2. 處理數據格式(如日期、貨幣、百分比等)
    DataFormat format = targetWb.createDataFormat();
    try {
        tempStyle.setDataFormat(format.getFormat(sourceCell.getCellStyle().getDataFormatString()));
    } catch (NullPointerException e) {
        tempStyle.setDataFormat((short) 0); // 預設為 General 格式
    }

    // 3. 深度複製字體屬性
    XSSFFont font = targetWb.createFont();
    XSSFCellStyle sourceStyle = sourceCell.getCellStyle();
    XSSFFont sourceFont = sourceStyle.getFont();
    
    font.setColor(sourceFont.getXSSFColor());
    font.setBold(sourceFont.getBold());
    font.setBoldweight(sourceFont.getBoldweight());
    try {
        font.setCharSet(sourceFont.getCharSet());
    } catch (POIXMLException e) {
        font.setCharSet(0);
    }
    font.setFamily(sourceFont.getFamily());
    font.setFontHeight(sourceFont.getFontHeight());
    font.setFontHeightInPoints(sourceFont.getFontHeightInPoints());
    font.setFontName(sourceFont.getFontName());
    font.setItalic(sourceFont.getItalic());
    font.setStrikeout(sourceFont.getStrikeout());
    font.setTypeOffset(sourceFont.getTypeOffset());
    font.setUnderline(sourceFont.getUnderline());
    tempStyle.setFont(font);

    // 4. 複製對齊與垂直對齊
    tempStyle.setAlignment(sourceStyle.getAlignment());
    tempStyle.setVerticalAlignment(sourceStyle.getVerticalAlignment());

    // 5. 複製邊框樣式與顏色
    tempStyle.setBorderBottom(sourceStyle.getBorderBottom());
    tempStyle.setBorderLeft(sourceStyle.getBorderLeft());
    tempStyle.setBorderRight(sourceStyle.getBorderRight());
    tempStyle.setBorderTop(sourceStyle.getBorderTop());
    
    tempStyle.setBottomBorderColor(sourceStyle.getBottomBorderXSSFColor());
    tempStyle.setLeftBorderColor(sourceStyle.getLeftBorderXSSFColor());
    tempStyle.setRightBorderColor(sourceStyle.getRightBorderXSSFColor());
    tempStyle.setTopBorderColor(sourceStyle.getTopBorderXSSFColor());

    // 6. 複製填充圖案與前景/背景色
    tempStyle.setFillPattern(sourceStyle.getFillPattern());
    tempStyle.setFillBackgroundColor(sourceStyle.getFillBackgroundColorColor());
    try {
        tempStyle.setFillForegroundColor(sourceStyle.getFillForegroundColorColor());
    } catch (NullPointerException e) {
        tempStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
    }

    // 7. 其他屬性:旋轉、隱藏、換行、縮進、鎖定
    tempStyle.setRotation(sourceStyle.getRotation());
    tempStyle.setHidden(sourceStyle.getHidden());
    tempStyle.setWrapText(sourceStyle.getWrapText());
    tempStyle.setIndention(sourceStyle.getIndention());
    tempStyle.setLocked(sourceStyle.getLocked());

    return tempStyle;
}

使用提示:調用時傳入來源單元格與目標 Workbook 即可獲得獨立的樣式對象,避免修改影響原樣式。

核心技術點二:單元格數據類型判斷與值提取

POI 中單元格類型由 cell.getCellType() 返回(POI 4.0+ 建議使用 cell.getCellTypeEnum())。不同類型需調用對應的 getter 方法,否則會拋出異常。以下是標準的類型分發邏輯:

List<Object> tempValue = new ArrayList<>();
Map<String, Object> map = new HashMap<>();

switch (cell.getCellType()) {
    case Cell.CELL_TYPE_BLANK:
        tempValue.add("");
        break;
    case Cell.CELL_TYPE_BOOLEAN:
        tempValue.add(cell.getBooleanCellValue());
        break;
    case Cell.CELL_TYPE_ERROR:
        tempValue.add(cell.getErrorCellString());
        break;
    case Cell.CELL_TYPE_FORMULA:
        // 關鍵:讀取公式字符串而非計算結果
        tempValue.add(cell.getCellFormula());
        map.put("formulaFlag", true); // 標記該單元格包含公式
        break;
    case Cell.CELL_TYPE_NUMERIC:
        // 進階:可結合 DateUtil.isCellDateFormatted 判斷日期類型
        tempValue.add(cell.getNumericCellValue());
        break;
    case Cell.CELL_TYPE_STRING:
        tempValue.add(cell.getStringCellValue());
        break;
    default:
        break;
}

最佳實踐:對於數值類型,建議額外檢查 DateUtil.isCellDateFormatted(cell) 以正確處理日期單元格;公式單元格若需計算結果,可使用 FormulaEvaluator。

核心技術點三:動態創建 Sheet、Row、Cell 結構

導出 Excel 時需按業務邏輯動態構建結構,以下代碼展示核心 API 用法:

// 創建工作簿(.xlsx 格式)
XSSFWorkbook targetWb = new XSSFWorkbook();

// 創建/刪除 Sheet
XSSFSheet targetSheet = targetWb.createSheet("行匯總");
// targetWb.removeSheetAt(index); // index 從 0 開始

// 創建行(i 為行索引)
XSSFRow row = targetSheet.createRow(i + num1 - startRow + 1);

// 創建單元格(j 為列索引)
XSSFCell cell = row.createCell(j);

// 設置值與樣式
cell.setCellValue("示例數據");
cell.setCellStyle(cloneAllCellStyle(sourceCell, targetWb));

核心技術點四:公式的讀取與寫入機制

POI 的公式處理遵循「讀取公式字符串 → 寫入公式字符串 → Excel 打開時自動計算」的模式:

  • 讀取: cell.getCellFormula() 返回不含等號的公式體,如 SUM(A1:B1)。
  • 寫入: cell.setCellFormula("SUM(A1:B1)"),同樣不需等號。
  • 注意:公式中的單元格引用為相對/絕對地址,寫入後位置固定,若模板行列變動需動態調整公式引用。

總結與建議

掌握 POI 核心在於理解三大對象模型:Workbook → Sheet → Row → Cell 的層級關係,以及 CellStyle、Font、DataFormat 的組合規則。實際項目中建議封裝通用工具類(如上述樣式複製、類型安全取值),並善用 FormulaEvaluator 處理公式計算、DataFormatter 統一格式化輸出,提升代碼健壯性與可維護性。

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