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