Java使用POI解析复杂Excel思维模式

来源:互联网 发布:淘宝化妆品店铺起名 编辑:程序博客网 时间:2024/06/04 19:20

功能需求:

   如图这样的Excel,要求解析出来,且存储到数据库中能够呈现出层级关系。且最后一级要有自己的几何非几何属性。

需求分析:

       1.首先我们发现这个Excel有这样一个规律,项目、IFD、是否标准这两个大类是样子是一一对应的,也就是说当我解析第一列的值、解析第五列的值、第十一列的值得函数可以是一样,同样第二列、第六列、第十二列也是可以一样的。。。

        2.我们发现只有当Excel类型表示其没有最后一列时,才可以对应其几何信息和非几何信息。

程序分析:

       1. Java中导出Excel,有两种方式,POI和JXL。优缺点就不用讲了。这里只阐述Java使用POI解析Excel

        2.程序中涉及到的POI中读取特定单元格的值,Excel读取合并单元格的值

       

    /**       * 获取合并单元格的值       * @param sheet       * @param row       * @param column       * @return       */        public static String getMergedRegionValueAndInfo(Sheet sheet ,int row , int column){        String MergedVal="";    String MergedInfo="";        int sheetMergeCount = sheet.getNumMergedRegions();            for(int i = 0 ; i < sheetMergeCount ; i++){                CellRangeAddress ca = sheet.getMergedRegion(i);                int firstColumn = ca.getFirstColumn();                int lastColumn = ca.getLastColumn();                int firstRow = ca.getFirstRow();                int lastRow = ca.getLastRow();                if(row >= firstRow && row <= lastRow){                    if(column >= firstColumn && column <= lastColumn){                        Row fRow = sheet.getRow(firstRow);                        Cell fCell = fRow.getCell(firstColumn);                        MergedVal=getCellValue(fCell);                    MergedInfo=String.valueOf(firstColumn)+","+String.valueOf(firstRow)+","+String.valueOf(lastColumn)+","+String.valueOf(lastRow);                    return MergedVal+"&"+MergedInfo ;                    }                }            }            return null ;        }         /**      * 判断合并了行      * @param sheet      * @param row  行    * @param column  列    * @return      */      private boolean isMergedRow(Sheet sheet,int row ,int column) {      int sheetMergeCount = sheet.getNumMergedRegions();      for (int i = 0; i < sheetMergeCount; i++) {      CellRangeAddress range = sheet.getMergedRegion(i);      int firstColumn = range.getFirstColumn();      int lastColumn = range.getLastColumn();      int firstRow = range.getFirstRow();      int lastRow = range.getLastRow();  // 0 0   3 1    if(row == firstRow && row == lastRow){      if(column >= firstColumn && column <= lastColumn){      return true;      }      }      }      return false;      }         /**  行合并    * 判断单元格向行方向合并    * 判断指定的单元格是否是合并单元格      * @param sheet       * @param row 行下标      * @param column 列下标      * @return      */      public static boolean isMergedRegion(Sheet sheet,int row ,int column) {      int sheetMergeCount = sheet.getNumMergedRegions();      for (int i = 0; i < sheetMergeCount; i++) {      CellRangeAddress range = sheet.getMergedRegion(i);      int firstColumn = range.getFirstColumn();      int lastColumn = range.getLastColumn();      int firstRow = range.getFirstRow();      int lastRow = range.getLastRow();      if(row >= firstRow && row <= lastRow){      if(column >= firstColumn && column <= lastColumn){      return true;      }      }      }      return false;      } 
    ---读取特定单元格的值

    

    public static String getCellVal(XSSFSheet sheet,int rowNum,int columnNum){    row=sheet.getRow(rowNum);    Cell cell=row.getCell(columnNum);    return getCellValue(cell);    } /**       * 获取单元格的值       * @param cell       * @return       */        public static String getCellValue(Cell cell){            if(cell == null){        return "";           }        if(cell.getCellType() == Cell.CELL_TYPE_STRING){    //字符串            return cell.getStringCellValue();            }else if(cell.getCellType() == Cell.CELL_TYPE_BOOLEAN){   //boolean             return String.valueOf(cell.getBooleanCellValue());            }else if(cell.getCellType() == Cell.CELL_TYPE_FORMULA){    //公式            return cell.getCellFormula() ;            }else if(cell.getCellType() == Cell.CELL_TYPE_NUMERIC){    //数字            return String.valueOf(cell.getNumericCellValue());            }else if(cell.getCellType() == Cell.CELL_TYPE_BLANK || cell.getCellType()==Cell.CELL_TYPE_ERROR){    //空值/故障        return "";        }else{    return "";    }        }  
    这个POI解析最基础的就是使用这两个方法。那么开始我们的分析

   1.程序开始解析第一列,并适时解析第五列、第十一列。然后按照他存储起来,是一条记录

   2.程序开始开始解析第二列时。这个时候就需要寻找他的父亲。

        思维一:我们通过IFD读取第五列的IFD给其第六列的数据定位其父亲的唯一性

        思维二:我们在数据中记录其父亲的所在行、列的二维坐标加上sheet的名称来实现父亲的唯一性

以上两种思维方式都对。但是呢?有缺陷,第一IFD是一串数字,数字编写上人为约定很有可能存在重复,那么你在寻找其父亲就没法做到唯一性。那么使用第二种?首先前提是,作为程序的编码者,要考虑用户为啥要使用Excel导入。因为客户不想麻烦,所以很有可能复制一个Excel改一改里面的某些内容,这个时候我们做到唯一性又加重了负担。

      从上述的两个思维来看,我们只有在当前导入的Excel中,确定了这个父亲的唯一性。而用户更换了下一个Excel后,他的唯一性任然存在。

      那么?Java中有什么方法可以实现定位到当前excel的父亲和儿子呢?

     MAP

     是的,我们交叉使用在第一列和第二列使用两个map,来记录其父子关系。第一个map的key是其行,value是他的值。第二个map也同样。当我们循环是,将其每一个行的值,和行号都存储,那么在儿子那一列时,我们就可以去父亲的map中用当前的key去取值。

---------------------------------------------------------------

    上面我们只是找到了其父子关系,那么作为层级关系的最后一级,需要给其赋值几何和非几何属性呢?

   这个逻辑灰常简单。就是确定其为最后一级

    情况一:这个Excel总共就只有4级,而第四列的任然有值存在,那么他就是最后一级

   情况二:我们以第二列的第五行为列。当for循环到这里时,发现其没有值,那么就要去寻找这一行的前一列是否有值,从而判断他是否为最后一列

   情况三:在情况的二的基础上的对立面。如果其有值,这个时候就要判断这一行的后一列是否有值,来判断其是否为最后一列

-----------------------------------------------升华篇

   我们在上诉的分析中,发现对于我们在寻找父子关系列时,使用了两个Map,我们可以假想其为奇偶map,这样对于父子判断就可以简化程序。

   还有分析Excel的列关系,我们发现他是3*n+2的数据几何关系。

    基于上诉的表达,我们就完全可以不怕用户的Excel变化。无论多少层级关系,我们都是剑在手。


    




0 0
原创粉丝点击