POI匯入,相容xlsx 和 xls
阿新 • • 發佈:2019-01-23
氣死了,之前遇到一個感覺比較好用的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";
}
}