最近遇到一个用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样式,第一行必须标识行- -