Java实现Excel表读取数据并入库
慢慢学习慢慢成长
先介绍一下需求:现在有一张Excel表,表里面数据并不是统一的,而是有三个数据库表对应的数据类似如图:
类似于这样的一张表。分别对应三张数据库表,下面先说一下我的思路。用的是POI的jar包。
<dependencies> <!-- https://mvnrepository.com/artifact/org.apache.poi/poi --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.17</version> </dependency>
1.想要操作Excel表,那么我们肯定需要先拿到这张表对象。
2.在对内容未知的情况下,我们不确定这张表共有多少页。所以通过Excel对象去拿到页长度
3.循环页数组取出每一页
4:通过当前页拿到当前页的所有行,注意有个坑
5.循环取出每一行
坑:POI的坑就在于,空行不算有效行,所以如果数据与数据之间存在空行的情况下,你不做出改变,数据就可能造成丢失
解决思路:我去判断当前行如果是空行的情况下,我就将总行数再去+1,然后跳过这一行去下一行
接下来需要自己理解了,因为每个人的需求不同,所以做的功能也不同,只能从别人的经验中吸取对自己有用的
5.根据改行的第一列的值判断我接下来的数据对什么表操作,注意也有一个坑,解决思路后面说
坑:因为需求原因,我需要操作的表不同,所以字段数量也不相同,但是就和获取有效行一样,获取有效列也只能获取到有
数据的列,比如我有10个字段需要获取,但是有两个存在null的情况。那我能获取到的列的有效长度就是8,就丢了两个,这样数据乱了
解决思路:我定义三个状态,一张表对应一个状态,只能有一个状态是true,通过状态决定操作什么表,并且因为表头是不会存在空值的情况,那么我就可以根据表头来决定有效列的长度,并且在没有遇到下一个表头的情况下,这个值不变,这样我就能获取完整的一条数据了,不管他有多少列的null数据。
遇到的第三个坑:空指针,因为我之前没有想过定义状态,就是通过获取第一列的值来决定操作什么表
但是没有考虑到第一列为null的情况,如果第一列为空我却使用null对象调用了方法。所以才决定使用状态来判断,避
开这个坑。
中间还遇到了许多问题,不过都是因为需求原因,所以就不多说了。希望能对看到这篇帖子的你起到帮助,那就够了。
上完整代码,注释都还在。因为我就很讨厌那些没有注释的帖子。看不懂才不尴尬,但是思路都没有才是最尴尬的!!!!!
import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.ss.usermodel.Cell; 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.xssf.usermodel.XSSFWorkbook; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class ExcelUtilTest { /** * Excel 三张表导入思想 * 1.拿到Excel表对象 √ * 2.拿到这个对象的总页数 √ * 3.计算当前页的有效行数,注意空行不算有效行数 * (这种情况就需要排除空行所以每次遇到空行的时候有效行数在循环过程中需要+1,通过这样来避免数据取不完) * 4.获取当前行的第一列的值,如果是所指定的内容,就获取改行的有效列。因为这是每张表的表头 * 作为表头不会存在空列的情况,后面的数据都以表头的总列数循环 * * 5.将数据根据判断的内容不同添加到不同的List集合中 * 6.循环结束条件为一个变量,连续遇到指定数量的空行以后,默认为全部读取完毕。 * 7.数据入库 * 8。结束 */ public static void main(String[] args)throws Exception{ List<Map<String,Object>> listPD = new ArrayList<Map<String,Object>>(); boolean statePD=false; List<Map<String,Object>> listPDD = new ArrayList<Map<String,Object>>(); boolean statePDD=false; List<Map<String,Object>> listPDP = new ArrayList<Map<String,Object>>(); boolean statePDP=false; int nullCount = 0; /**1.拿到Excel表*/ File excelFile = new File("D:\\ImportFile\\dataCheck\\Test.xlsx"); InputStream is = new FileInputStream(excelFile); Workbook wb = new XSSFWorkbook(is); /**2.拿到这个对象的总页数*/ int sheeetNum = wb.getNumberOfSheets();//总页数 for (int i = 0;i < sheeetNum;i ++){ /**2-1.拿到当前页对象*/ Sheet sheetObj = wb.getSheetAt(i);//当前页对象 /**3.拿到当前页的有效行数*/ int rowNum = sheetObj.getLastRowNum();//有效行数 int cellNum = 0; for (int j = 0;j < rowNum;j ++){///////////循环的是每一行 /**3-1.拿到当前行对象*/ Row rowObj = sheetObj.getRow(j);//行级对象 /**这种情况就需要排除空行所以每次遇到空行的时候有效行数在循环过程中需要+1,通过这样来避免数据取不完)*/ if (rowObj == null) { rowNum++; nullCount++;//出现的空值数量计数器 if (nullCount>3)break;//如果连续遇到三次或者指定次数的空行,代表这张表已经读取完了就break跳过本次循环去下一页 continue; }else{ nullCount=0;//只要不是连续空值,就刷新计数器 } /**4.获取当前行的第一列的值,如果这个值不是空值,我就拿出来对比一下是不是符合我的要求符合我就改变我所定义的状态*/ if (rowObj.getCell(0) != null) { Cell cell = null; rowObj.getCell(0).setCellType(HSSFCell.CELL_TYPE_STRING); cell = rowObj.getCell(0); if (cell.toString().indexOf("对等")>-1 || cell.toString().indexOf("注册")>-1) { statePD=true; statePDD=false; statePDP=false; cellNum = rowObj.getLastCellNum();//只有在符合我所定的条件的时候我才去查询当前行的有效列数然后因为不对表头做操作,所以可以直接跳过这一行 continue; }else if (cell.toString().indexOf("起始电路号")>-1) { statePD=false; statePDD=true; statePDP=false; cellNum = rowObj.getLastCellNum();//只有在符合我所定的条件的时候我才去查询当前行的有效列数然后因为不对表头做操作,所以可以直接跳过这一行 continue; }else if (cell.toString().indexOf("目的")>-1 || cell.toString().indexOf("索引")>-1) { statePD=false; statePDD=false; statePDP=true; cellNum = rowObj.getLastCellNum();//只有在符合我所定的条件的时候我才去查询当前行的有效列数然后因为不对表头做操作,所以可以直接跳过这一行 continue; } } /**那么现在我就不需要考虑了,什么表的状态是true我就对什么表做数据添加,因为如果为true说明这张表的数据还没有读取完*/ /**4-1.获取作为表头行所在行的有效列*/ if (statePD){//如果true就说明第一张表的数据还没有取完 Map<String,Object> mapPD = new HashMap<String,Object>();//最长的 for (int k = 0; k < cellNum; k++) {/////////循环的是每一列 if (rowObj.getCell(k) != null ) rowObj.getCell(k).setCellType(HSSFCell.CELL_TYPE_STRING); Cell cellObj = rowObj.getCell(k); insertMapPD(cellObj,k,mapPD); } listPD.add(mapPD); }else if (statePDD){ Map<String,Object> mapPDD = new HashMap<String,Object>();//最短的 for (int k = 0; k < cellNum; k++) {/////////循环的是每一列 if (rowObj.getCell(k) != null ) rowObj.getCell(k).setCellType(HSSFCell.CELL_TYPE_STRING); Cell cellObj = rowObj.getCell(k); insertMapPDD(cellObj,k,mapPDD); } listPDD.add(mapPDD); mapPDD.clear(); }else if (statePDP){ Map<String,Object> mapPDP = new HashMap<String,Object>();//中间的 for (int k = 0; k < cellNum; k++) {/////////循环的是每一列 if (rowObj.getCell(k) != null ) rowObj.getCell(k).setCellType(HSSFCell.CELL_TYPE_STRING); Cell cellObj = rowObj.getCell(k); insertMapPDP(cellObj,k,mapPDP); } listPDP.add(mapPDP); mapPDP.clear(); } } } } //这个位置的注释我就干掉了!因为是公司的表。我想这个也不需要去怎么理解。看下就懂了。就是一个数据的保存方法; public static void insertMapPD(Object obj,int i,Map mapPD){ i+=1; switch (i){ case 1: mapPD.put("FD_TYPE",obj); break; case 2: mapPD.put("FD_OFCNAME",obj); break; case 3: mapPD.put("FD_INTERID",obj); break; case 4: mapPD.put("FD_INTERTYPE",obj); break; case 5: mapPD.put("FD_INTERGTN",obj); break; case 6: mapPD.put("FD_PORT",obj); break; case 7: mapPD.put("FD_SIGNSLOT",obj); break; case 8: mapPD.put("FD_PARAMSPF9",obj); break; case 9: mapPD.put("FD_SUBSPF",obj); break; case 10: mapPD.put("FD_MODULE",obj); break; case 11: mapPD.put("FD_LINK",obj); break; case 12: mapPD.put("FD_TRUNK",obj); break; case 13: mapPD.put("FD_CALL",obj); break; case 14: mapPD.put("FD_MINL",obj); break; case 15: mapPD.put("FD_MAXL",obj); break; case 16: mapPD.put("FD_MGWID",obj); break; } } public static void insertMapPDD(Object obj,int i,Map mapPDD){ i+=1; switch (i){ case 1: mapPDD.put("FD_SID",obj); break; case 2: mapPDD.put("FD_EID",obj); break; case 3: mapPDD.put("FD_TERMID",obj); break; } } public static void insertMapPDP(Object obj,int i,Map mapPD){ i+=1; switch (i){ case 1: mapPD.put("FD_SIGNINDEX",obj); break; case 2: mapPD.put("FD_SIGN",obj); break; case 3: mapPD.put("FD_BSGMODULE",obj); break; case 4: mapPD.put("FD_M2UA",obj); break; case 5: mapPD.put("FD_TID",obj); break; case 6: mapPD.put("FD_SOURSIGN",obj); break; case 7: mapPD.put("FD_ROUTE",obj); break; case 8: mapPD.put("FD_NUM",obj); break; } } }
祝愿大家越努力越幸运!!!!!!!!!2019/4/12