1. 程式人生 > >POI匯入,相容xlsx 和 xls

POI匯入,相容xlsx 和 xls

氣死了,之前遇到一個感覺比較好用的poi匯入,誰知道現在用起來,各種bug,乾脆使用最新的api模仿實現了一個,使用模版方法模式回撥,只需要實現介面,處理每一行資料,就ok了。此實現只支援單頁sheetIndex
多頁實現請參考:http://git.oschina.net/zhuqiang/utils

使用到的jar包pom

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version
>
3.12</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.12</version> </dependency>

核心PoiAbstract抽象類

import java.io.FileInputStream;
import java.io.InputStream;
import
java.util.ArrayList; import java.util.List; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.DateUtil; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; /** * 讀取xlsx 和 xls,只支援單頁sheetIndex * @author
zq * */
public abstract class PoiAbstract { Workbook wb = null; public PoiAbstract(String path) { try { InputStream inp = new FileInputStream(path); wb = WorkbookFactory.create(inp); //使用工廠建立,相容xlsx 和 xls } catch (Exception e) { new RuntimeException(e.getMessage()); } } /** * 遍歷Excel所有資料,包含header * * @param sheetIndex */ public void process(int sheetIndex) { int columnNum = 0; // 獲取列 Sheet sheet = wb.getSheetAt(sheetIndex); if (sheet.getRow(0) != null) { columnNum = sheet.getRow(0).getLastCellNum() - sheet.getRow(0).getFirstCellNum(); } if (columnNum > 0) { for (Row row : sheet) { List<String> rowlist = new ArrayList<String>(columnNum); int n = 0; for (int i = 0; i < columnNum; i++) { Cell cell = row.getCell(i, Row.CREATE_NULL_AS_BLANK); switch (cell.getCellType()) { case Cell.CELL_TYPE_BLANK: rowlist.add(n, ""); break; case Cell.CELL_TYPE_BOOLEAN: rowlist.add(Boolean.toString(cell.getBooleanCellValue())); break; // 數值 case Cell.CELL_TYPE_NUMERIC: if (DateUtil.isCellDateFormatted(cell)) { rowlist.add(String.valueOf(cell.getDateCellValue())); } else { cell.setCellType(Cell.CELL_TYPE_STRING); String temp = cell.getStringCellValue(); // 判斷是否包含小數點,如果不含小數點,則以字串讀取,如果含小數點,則轉換為Double型別的字串 if (temp.indexOf(".") > -1) { rowlist.add(String.valueOf(new Double(temp)).trim()); } else { rowlist.add(temp.trim()); } } break; case Cell.CELL_TYPE_STRING: rowlist.add(cell.getStringCellValue().trim()); break; case Cell.CELL_TYPE_ERROR: rowlist.add(""); break; case Cell.CELL_TYPE_FORMULA: cell.setCellType(Cell.CELL_TYPE_STRING); rowlist.add(cell.getStringCellValue()); if (rowlist.get(n) != null) { rowlist.set(n, rowlist.get(n).replaceAll("#N/A", "").trim()); } break; default: rowlist.add(""); break; } n++; } try { this.optRows(sheetIndex, row.getRowNum(), rowlist); // 行結束,呼叫行,每行的資料 } catch (Exception e) { e.printStackTrace(); } } } } public abstract void optRows(int sheetIndex, int curRow, List<String> rowlist) throws Exception; }

PoiRead 簡易處理方式

import java.util.ArrayList;
import java.util.List;
/**
 * 一種感覺比較好的處理方式。資訊量比較全。
 * @author zq
 *
 */
public class PoiRead extends PoiAbstract {
    // 資料處理解析資料的介面
    private PoiOptRowsInterface poiOptRowsInterface;
    // 處理資料總數 (如果有總數包含總數)
    private int optRows_sum = 0;
    // 處理資料成功數量
    private int optRows_success = 0;
    // 處理資料失敗數量
    private int optRows_failure = 0;
    // excel表格每列標題
    private List<String> rowtitle;
    // 失敗資料
    private List<List<String>> failrows;
    // 失敗原因
    private List<String> failmsgs;

    // 要處理資料所在的sheet索引,sheet索引從0開始
    private int sheetIndex;

    /**
     * @param path
     *            匯入檔案的物理路徑
     * @param sheetIndex
     *            要讀取資料所在sheet序號,從0開始
     * @param poiOptRowsInterface
     *            處理讀取每一行資料的介面
     */
    PoiRead(String path, int sheetIndex, PoiOptRowsInterface poiOptRowsInterface) {
        super(path);
        this.sheetIndex = sheetIndex;
        this.poiOptRowsInterface = poiOptRowsInterface;
        this.rowtitle = new ArrayList<String>();
        this.failrows = new ArrayList<List<String>>();
        this.failmsgs = new ArrayList<String>();
    }

    @Override
    public void optRows(int sheetIndex, int curRow, List<String> rowlist) throws Exception {
        // 將rowlist的長度補齊和標題一致
        int k = rowtitle.size() - rowlist.size();
        for (int i = 0; i < k; i++) {
            rowlist.add(null);
        }
        if (sheetIndex == this.sheetIndex) {
            optRows_sum++;

            if (curRow == 0) {// 記錄標題
                rowtitle.addAll(rowlist);
            } else {
                // 介面返回的結果是匯入資料的結果,有成功,有失敗
                String result = poiOptRowsInterface.optRows(sheetIndex, curRow, rowlist);
                if (result != null && !result.equals(PoiOptRowsInterface.SUCCESS)) {
                    optRows_failure++;// 失敗統計數加1
                    // 失敗資料列表
                    failrows.add(new ArrayList<String>(rowlist));
                    failmsgs.add(result);
                } else {
                    optRows_success++;
                }
            }

        }
    }

    public int getOptRows_sum() {
        return optRows_sum;
    }

    public void setOptRows_sum(int optRows_sum) {
        this.optRows_sum = optRows_sum;
    }

    public int getOptRows_success() {
        return optRows_success;
    }

    public void setOptRows_success(int optRows_success) {
        this.optRows_success = optRows_success;
    }

    public int getOptRows_failure() {
        return optRows_failure;
    }

    public void setOptRows_failure(int optRows_failure) {
        this.optRows_failure = optRows_failure;
    }

    public List<String> getRowtitle() {
        return rowtitle;
    }

    public void setRowtitle(List<String> rowtitle) {
        this.rowtitle = rowtitle;
    }

    public List<List<String>> getFailrows() {
        return failrows;
    }

    public void setFailrows(List<List<String>> failrows) {
        this.failrows = failrows;
    }

    public List<String> getFailmsgs() {
        return failmsgs;
    }

    public void setFailmsgs(List<String> failmsgs) {
        this.failmsgs = failmsgs;
    }


    //測試讀取
    public static void main(String[] args) {
        PoiRead poiRead = new PoiRead("C:/Users/99299/Desktop/讀取測試.xlsx", 0, new Impl());
        poiRead.process(0);
        System.out.println("處理資料總數:" + poiRead.getOptRows_sum());
        System.out.println("處理資料成功數量:" + poiRead.getOptRows_success());
        System.out.println("處理資料失敗數量:" + poiRead.getOptRows_failure());
        System.out.println("excel表格每列標題:" + poiRead.getRowtitle());
        System.out.println("失敗資料:" + poiRead.getFailrows());
        System.out.println("失敗原因:" + poiRead.getFailmsgs());
    }

}

PoiRead的回撥介面PoiOptRowsInterface

import java.util.List;

/**
 * 與 簡易實現 PoiRead.java類配合使用的回撥介面
 * @author zq
 *
 */
public interface PoiOptRowsInterface {
    public static final String SUCCESS = "success";

    /**
     * 處理excel檔案每行資料方法
     * 
     * @param sheetIndex
     *            為sheet的序號
     * @param curRow
     *            為行號
     * @param rowlist
     *            行資料
     * @return success:返回 SUCCESS 或則 null 表示成功,否則為失敗原因
     * @throws Exception
     */
    public String optRows(int sheetIndex, int curRow, List<String> rowlist) throws Exception;
}

使用示例

編寫一個回撥介面的實現類

編寫該類的一些思路:這裡回撥給你的是,當前頁數,當前處理的行,當前行的所有列資料
在構建該實現類的時候,可以加入各種與資料庫的服務,和各種驗證方法,比如:可以定義一些變數,把所要保留下來的資料存起來;在返回的字串中,按照一定的格式記錄錯誤的行和列,在前臺jsp頁面中就能做到把錯誤的列都飄紅顯示。等等。 這裡就簡單的列印下

import java.util.List;

public class Impl implements PoiOptRowsInterface {

    public String optRows(int sheetIndex, int curRow, List<String> rowlist) throws Exception {
        System.out.println( curRow + "行------------");
        for (String st : rowlist) {
            System.out.print(st + "\t");
        }
        System.out.println("");
        return "xxxxxxxxxx";
    }

}