dbeaver导入excel文件_使用POI封装工具类处理Excel表格文件导入篇
使用POI封装工具类处理Excel表格文件--导入篇
有关于系统中导入Excel表格文件,其实大家普遍见过或者使用过。但是相较于网上提供的EasyPOI或者Hutool工具类里面封装好的Excel处理方法(马总推荐使用的工具类),其实在很多情况下不太符合我们的导出或者导入场景,总是需要手动处理下,很是繁琐,毕竟不是所有的表格数据我们都需要,或不是所有的数据都需要我们导出。所以这里手动处理下POI类(其实人家封装的已经很完整了,~~然而还是不太好用~~),让这个处理的方法更贴合实际使用。
> 云中谁寄锦书来?雁字回时,月满西楼。
构思
我们使用Excel导入的目的是什么?
* 通常我们使用Excel导入的目的说白了就是为了获取表格里面的数据,然后整理后提炼出来被我们使用或者存入到数据库中。但是很多情况下,不是所有的列数据都是我们需要的,所以我们首先要明确我们需要什么。我这里处理使用常量来定义了导入的模板。(当然大家还可以使用枚举,或者选择和前端交互,肆意而为,毕竟办法总比困难多-狗头保命:: )
> 模板定义: 0|备注(属性名)|属性名
public static class TempLate{ @ConstantAnnotation("001") public static final String MODE_CONTENT="0|凭证号|voucherNo,1|会计年度|accountYear,2|会计月度|accountMonth,3|数据来源|dataSource,4|存储类型(0. 电子 1. 电子和纸质)|saveType,5|存储类型名称|voucherName,6|摘要|accountAbstract,7|关键字|keyWord,8|凭证类型|voucherTypeId,9|凭证类型名称|voucherTypeName,10|凭证状态0 待装册 1 已装册|voucherState,11|创建时间|creatTime,12|单位编码|orgCode,13|单位名称|orgName"; }
知道了我们要获取的数据有哪些后,我们怎么做匹配?
* 当我们知道了我们需要表格数据的哪一列,我们心中其实也就明白了这列数据对应我们数据模型的哪一个字段,这样在后面处理的时候只要匹配成功即可。
所以我们需要用到反射的一点点知识,使用好Field,然后简单的做几个判断,就可以完美匹配了。
T object = instance.newInstance(); Field[] fields= object.getClass().getDeclaredFields();
> 注:instance是一个Class 类型的入参,用来放我们需要储存数据的数据模型类.class 还有就是fields,是我们.class里面的所有属性。(获取私有属性要把accessible赋值true)
* 接下来我们拿到属性数组后,可以循环比较类型或者属性名来操作并赋值。
if (mapHeader.get(s).equals(f.getName())) { //获取私有变量 f.setAccessible(true); f.set(object, cell.getStringCellValue());
如何调用?我们该传什么进行处理?
* 首先传一个要处理的Excel文件,然后我们传个模板,再传一个我们想要返回结果集合的类型.class即可。例:
List list=POIUtils.excelToEmployee(file,EaVoucher.class,modeText);
> 模板处理
public static Map stringToMap(String text) throws Exception { Map mapHeader = new HashMap<>(); String[] decollator = text.split(","); if (decollator.length > 0) { for (String s : decollator) { String[] desc = s.split("\\|"); if (desc.length < 3 || "".equals(desc[0]) || "".equals(desc[2])) { throw new Exception("模板格式有误,请检查!"); } mapHeader.put(desc[0], desc[2]); } } return mapHeader; }
然后我们就可以使用这个工具类了。源码方法如下:
/** * @Description: excel文件解析成相应类型的List * @Param: [file, instance, modeText] * @return: java.util.List * @Author: ShiDunKai * @Date: 2020/5/29 */ public static List excelToEmployee(MultipartFile file, Class instance, String modeText) throws Exception { //获取导入模板 Map mapHeader = stringToMap(modeText); //接收list List tList = new ArrayList<>(); //创建一个workbook对象 HSSFWorkbook workbook = new HSSFWorkbook(file.getInputStream()); //获取workbook中标签页的数量 int numberOfSheets = workbook.getNumberOfSheets(); for (int sheetNumber = 0; sheetNumber < numberOfSheets; sheetNumber++) { HSSFSheet sheetAt = workbook.getSheetAt(sheetNumber); //获取行 int physicalNumberOfRows = sheetAt.getPhysicalNumberOfRows(); for (int rowNumber = 0; rowNumber < physicalNumberOfRows; rowNumber++) { if (0 == rowNumber) {//跳过标题行 因为我们这里不做任何处理,所以有没有continue,效果都是一样的,精简才是王道。 } else { //解析第一行,与模板进行匹配 HSSFRow row = sheetAt.getRow(rowNumber); //空行判断 if (null == row) { continue; } //一行一个对象 T object = instance.newInstance(); Field[] fields = object.getClass().getDeclaredFields(); //获取列 int physicalNumberOfCells = row.getPhysicalNumberOfCells(); if (physicalNumberOfCells >= mapHeader.size()) { for (String s : mapHeader.keySet()) { HSSFCell cell = row.getCell(Integer.parseInt(s)); for (Field f:fields) { if (mapHeader.get(s).equals(f.getName())) { //获取私有变量 f.setAccessible(true); f.set(object, cell.getStringCellValue()); } else { throw new Exception("模板属性名与对象属性不符,请检查模板是否正确配置。"); } } } } else { throw new Exception("表格列数量与实际要导出的列数不符,无法获取某些列数据,请检查模板或者表格文件是否正确。"); } tList.add(object); } } } return tList; }
后:
> 是不是很简单,模板我们可以随时调整,如果后期需要做集成,我们完全可以想办法和前端进行交互,使工具类的扩展性再提一个层次。前期业务量小的话完全可以自定义模板,不影响使用效果的。?
> 至于导出我们如何做处理,其实大致思路和上面是一样的,只不过现在已经半夜0:08,早睡保命要紧,明天还要早起吃早点,还要工作。。。那就拖到周六日给大家分享吧(或许拖更久,别急:trollface: )
> 其实这个博客在电脑上看效果是最好的,但是大家平时还是看手机比较多,所以微信公众号随后也会完成更新推送,欢迎关注留言讨论(*~~留言了我也不一定回复~~*)。睡,晚安各位。
上一篇: 6.数据类型的选择
下一篇: 带头结点的线性链表基本操作以及归并操作