最近遇到一個用excel文件批量上傳某對象數據的問題,由於之前的程序是對每個上傳的excel進行分別解析進行,然後對bean進行設置,我覺得這樣實在太過麻煩。於是就稍微改寫了一下。讓所有的設置都使用一個方法,然後返回設置好的beans,最後調用對應的service保存就可以了。
(1)首先我用了java的annotation,關於annotation的基本學習資料這個就挺好的:http://www.blogjava.net/landon/archive/2010/07/14/326071.html
/**
*
* @author chen_dawei02
* 這個annotation用來註解bean屬性的中文名字
* 方便批量上傳檢測
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ChineseFieldAnnotation {
String name();
}
(2)然後用這個註釋給需要進行上傳解析的字段的set方法加註解,例如:
@ChineseFieldAnnotation(name="失效控制")
public void setExpireFlag(String expireFlag) {
this.expireFlag = expireFlag;
}
(3)寫了一個泛型方法用來接收傳遞來的excel,然後用apache的poi(疑犯追蹤→_→)來解析。這裏有點疑惑,比如一個5行5列的excel進行上傳,sheet.getLastRowNum()得到的是4(數組最大小標),而row.getLastCellNum()得到的是5(長度),所以下面一個循環用的<=一個用的是<。感覺非常奇怪啊。。幾個excel都是這樣子。。。。
/**
*
* @param file 數據流
* @param cl 調用該函數的bean的類,與T相同
* @return 返回裝在T對象的list
* @author chen_dawei02
*/
private <T> List<T> batchAdd(File file,Class<T> cl) throws Exception{
FileInputStream inputStream=new FileInputStream(file);
// 打開Excel文件
HSSFWorkbook workbook = new HSSFWorkbook(inputStream);//讀取信息
// 取得Excel中的第一個Sheet
HSSFSheet sheet = workbook.getSheetAt(0);
Method[] methods=cl.getMethods(); //該bean類的所有方法
HSSFRow firstRow=sheet.getRow(0); //取得第一行標識行
List<T> dataList = new ArrayList<T>();//存放數據結果的鏈表
//返回存有列對應的method方法的序列
int[] result=getMethodSequence(firstRow, methods);
for(int i=1;i <= sheet.getLastRowNum();i++){
T info = cl.newInstance();
HSSFRow row = sheet.getRow(i);
for(int j=0;j<row.getLastCellNum();j++){
HSSFCell cell = row.getCell(j);
if(cell != null)
cell.setCellType(Cell.CELL_TYPE_STRING);
//調用該列所用到的set方法
methods[result[j]].invoke(info,new Object[]{cell.getStringCellValue()});
}
dataList.add(info);
}
logger.info("批量數據保存成功,記錄條數爲:" + dataList.size());
return dataList;
}
/**
*
* @param tagRow 標識行
* @param method 類中方法
* @return 列所對應的方法
*/
private int[] getMethodSequence(HSSFRow tagRow,Method[] methods){
int[] result=new int[tagRow.getLastCellNum()];
for(int i=0;i<tagRow.getLastCellNum();i++)
for(int j=0;j<methods.length;j++){
//如果沒有被ChineseFieldAnnotation註解過就跳過
if(!methods[j].isAnnotationPresent(ChineseFieldAnnotation.class))
continue;
//方法涉及字段的中文名
String setFieldCNName=methods[j].getAnnotation(ChineseFieldAnnotation.class).name();
String tag=tagRow.getCell(i).toString();
//如果excel標籤和方法名的中文標籤相同,則記錄當前列方法序號
if(tag.equals(setFieldCNName)){
result[i]=j;
break;
}
}
return result;
}
(4)調用batchAdd,返回的是一組已經set好數據的TblMerchList,然後通過調用save就能保存到數據庫中 List<TblMerchList> list = batchAdd(file, TblMerchList.class);
for(TblMerchList n:list)
MerchListService.getInstance().save(n);
(5)以下是上傳的excel樣式,第一行必須標識行- -