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

功能需求:

   如图这样的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变化。无论多少层级关系,我们都是剑在手。


    




  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值