POI导入数据解决多表头,合并单元格数据读取问题

POI导入数据解决多表头,合并单元格,适配表格列可拓展数据读取问题

关于java开发,涉及使用POI读取excel数据,尤其涉及多分类的表头以及合并单元格的导入会遇到很多困扰的问题,今天我就将在开发中遇到的导入问题进行讲解。

1.首先说下我们今天要实现的功能,我们要将带有多分类,多合并单元格进行数据转存,以及需要适配不同列的数据解析导入,具体的表格如下:
在这里插入图片描述
表格中圈出的区域为:
(1)第一行为:合并单元格主标题
(2)第二行为:合并的性别类
(3)第三行为:产品分类
(4)第四行为:产品子级分类
上述的罗列的几个都是以合并单元格的形式进行展示,首先我们要解决的就是如何进行合并单元格的数据读取
第一步:pom文件引入关于poi相应的文件包,具体如图所示:
在这里插入图片描述
第二步:我们需要解决的就是关于合并单元格的数据读取,获取表格中合并单元格的数量,判断是否是单元格,以及获取合并单元格的跨列数。通过以上几点的思路我们来进行逻辑的实现,首先步入代码:

获取单元格合并列数:

    public static int GetMergeNum(Cell cell, Sheet sheet) {
    	int mergeSize = 1;
    	List<CellRangeAddress> mergedRegions = sheet.getMergedRegions();
    	for (CellRangeAddress cellRangeAddress : mergedRegions) {
    		if (cellRangeAddress.isInRange(cell)) {				
	    		mergeSize =	cellRangeAddress.getFirstRow()-cellRangeAddress.getLastRow()+1;//获取合并的列数	
	    		break;
    		}
    	}
    	return mergeSize;
    }

判断是否是单元格方法

    public 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 String getMergedRegionValue(Sheet sheet ,int row , int column){
        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);
                    return getCellValue(fCell) ;
                }
            }
        }
        return null ;
    }
        public String getCellValue(Cell cell){
        	if(cell == null) return "";
         return cell.getStringCellValue();
    }

上述的几个属于实现功能的基本代码,现在我们整体来看下业务实现流程的完成代码:

 public synchronized ResultMap rateImportExcel(HttpServletRequest request, HttpServletResponse response,Integer type) {
  	String msg="";
      try {
          // @RequestParam("file") MultipartFile file 是用来接收前端传递过来的文件
          // 1.创建workbook对象,读取整个文档
          // 转类型接受file
          MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
          MultipartFile file = multipartRequest.getFile("excelFile");
          // 获取登陆账户信息
          // 获取携带的参数
          InputStream inputStream = file.getInputStream();
          Workbook wb = null;
          if (file.getOriginalFilename().indexOf(".xlsx") == -1) {
              wb = new HSSFWorkbook(inputStream);
          }else {
          	wb = new XSSFWorkbook(inputStream);
          }
          // 2.读取页脚sheet
          Sheet sheetAt = wb.getSheetAt(0);
          String projectName="";//项目名称
          if(isMergedRegion(sheetAt,0 ,1)==true) {
          	projectName = getMergedRegionValue(sheetAt ,0 , 1);
          }
          InsuranceProdect  insuranceProdectInfo = insuranceProdectService.selectProdectInfoByName(projectName);
          if(insuranceProdectInfo==null) {
          	msg="系统内未找到对应产品信息,请检查!";
          }
          //编辑表格中的合并单元格的数量
          int sheetmergeCount = sheetAt.getNumMergedRegions();
          int maleFirstColumn = 0;//男性初始列
          int maleLastColumn = 0;//男性的结束列
          int girlFirstColumn = 0;//女性初始列
          int girlLastColumn = 0;//女性结束列
          int maleParentFirstColumn = 0;//男性父级分类初始列
          int maleParentLastColumn = 0;//男性父级分类结束列
          int maleParent1FirstColumn = 0;//男性父级分类2初始列
          int maleParent1LastColumn = 0;//男性父级分类2结束列
          int girlParentFirstColumn = 0;//女性父级分类初始列
          int grilParentLastColumn = 0;//女性父级分类结束列
          int girlParent1FirstColumn = 0;//女性父级分类2初始列
          int girlParent1LastColumn = 0;//女性父级分类2结束列
          //遍历合并单元格数量获取对应的初始列数,结束列数后续使用
          for (int i = 1; i <sheetmergeCount; i++) {
              CellRangeAddress range = sheetAt.getMergedRegion(i);
              if(i==1) {
              	 maleFirstColumn = range.getFirstColumn();
                 maleLastColumn = range.getLastColumn();
              }else if(i==2) {
              	 girlFirstColumn = range.getFirstColumn();
              	 girlLastColumn = range.getLastColumn();
              }else if(i==3) {
              	 maleParentFirstColumn = range.getFirstColumn();
              	 maleParentLastColumn = range.getLastColumn();
              }else if(i==4) {
              	 maleParent1FirstColumn = range.getFirstColumn();
              	 maleParent1LastColumn = range.getLastColumn();
              }else if(i==5) {
              	 girlParentFirstColumn = range.getFirstColumn();
              	 grilParentLastColumn = range.getLastColumn();
              }else if(i==6) {
              	 girlParent1FirstColumn = range.getFirstColumn();
              	 girlParent1LastColumn = range.getLastColumn();
              }
          }
          
          //获取二级分类的集合值
          List<String> typeList = new ArrayList<>();
          for(int i=maleFirstColumn+1;i<=maleLastColumn;i++) {
          	Row rowInfo = sheetAt.getRow(3);//有二级分类
          	typeList.add(rowInfo.getCell(i).getStringCellValue().trim());
          }
          
          String male = "";//男性信息
          if(isMergedRegion(sheetAt ,1,maleLastColumn)==true) {
          	male = getMergedRegionValue(sheetAt ,1 , maleLastColumn);
          }
          
          String femaleSex = "";//女性信息
          if(isMergedRegion(sheetAt,1,girlLastColumn)==true) {
          	femaleSex = getMergedRegionValue(sheetAt,1,girlLastColumn);
          }
          String parentName = "";//父级一信息
          String parent1Name = "";//父级二信息
          if(type==2) {
           if(isMergedRegion(sheetAt ,1,maleLastColumn)==true) {
           	parentName = getMergedRegionValue(sheetAt ,2 , maleParentLastColumn);
           }
           if(isMergedRegion(sheetAt,1,girlLastColumn)==true) {
           	parent1Name = getMergedRegionValue(sheetAt,2,maleParent1LastColumn);
           }
          }
          // 3.循环读取某一行
          int index=3;
          int rowNum = sheetAt.getLastRowNum();//有多少行
         	for (int i = index; i <= rowNum; i++) {
              Row row = sheetAt.getRow(i);//第i行
              if (row == null) {//过滤空行
                  continue;
              }
              // 4.读取每一行的单元格
              if (index ==3) {
                  index++;
                  continue;
              } else {
                  index++;
              }
              //初始化错误信息
              String age = "";//年龄
              try {
                  if (row.getCell(0) != null) {
                  	row.getCell(0).setCellType(CellType.STRING);
                  	age = row.getCell(0) == null ? "" : row.getCell(0).getStringCellValue().trim(); // 第一列数据
                  } else {
                      // 如果没有数据了 就跳出
                      break;
                  }
              } catch (Exception e) {
              }
              //根据男性的父级分类跨列数进行编辑循环,插入数据
              for(int k=maleParentFirstColumn+1;k<=maleParentLastColumn;k++) {
         			String maleValue="";
         			if(row.getCell(k)!=null) {
           		row.getCell(k).setCellType(CellType.STRING);
           		maleValue = row.getCell(k) == null ? "" : row.getCell(k).getStringCellValue().trim();//第一列数据
           		RateTypeEx info = rateTypeService.selectRateTypeInfoByName(typeList.get(k-1));
           		RateTypeEx parentInfo = rateTypeService.selectRateTypeInfoByName(parentName);
           		if(info==null) {
           			msg="系统内未找到对应分类信息,请检查!";
           		}else {
           			if(Utils.notBlank(maleValue)) {
           				//业务保存方法
           				saveRate(insuranceProdectInfo.getId(),parentInfo.getId(),info.getId(),2,maleValue,age,male);
           			}
           		}
           	}
         		}
              //根据男性的父级分类2跨列数进行编辑循环,插入数据
         		for(int k=maleParent1FirstColumn;k<=maleParent1LastColumn;k++) {
         			String maleValue="";
         			if(row.getCell(k)!=null) {
           		row.getCell(k).setCellType(CellType.STRING);
           		maleValue = row.getCell(k) == null ? "" : row.getCell(k).getStringCellValue().trim();//第一列数据
           		RateTypeEx info = rateTypeService.selectRateTypeInfoByName(typeList.get(k-1));
           		RateTypeEx parentInfo1 = rateTypeService.selectRateTypeInfoByName(parent1Name);
           		if(info==null) {
           			msg="系统内未找到对应分类信息,请检查!";
           		}else {
           			if(Utils.notBlank(maleValue)) {
           				//业务保存方法
           				saveRate(insuranceProdectInfo.getId(),parentInfo1.getId(),info.getId(),2,maleValue,age,male);
           			}
           		}
           	}
         		}
         		//根据女性的父级分类跨列数进行编辑循环,插入数据
         		for(int k=girlParentFirstColumn;k<=grilParentLastColumn;k++) {
             		String girlValue="";
         			if(row.getCell(k)!=null) {
           		row.getCell(k).setCellType(CellType.STRING);
           		girlValue = row.getCell(k) == null ? "" : row.getCell(k).getStringCellValue().trim();//第一列数据
           		RateTypeEx info = rateTypeService.selectRateTypeInfoByName(typeList.get(k-5));
           		RateTypeEx parentInfo = rateTypeService.selectRateTypeInfoByName(parentName);
           		if(info==null) {
           			msg="系统内未找到对应分类信息,请检查!";
           		}else {
           			if(Utils.notBlank(girlValue)) {
           				//业务保存方法
           				saveRate(insuranceProdectInfo.getId(),parentInfo.getId(),info.getId(),2,girlValue,age,femaleSex);
           			}
           		}
           	}
         		}
         		//根据女性的父级分类2跨列数进行编辑循环,插入数据
         		for(int k=girlParent1FirstColumn;k<=girlParent1LastColumn;k++) {
         			String girlValue="";
         			if(row.getCell(k)!=null) {
           		row.getCell(k).setCellType(CellType.STRING);
           		girlValue = row.getCell(k) == null ? "" : row.getCell(k).getStringCellValue().trim();//第一列数据
           		RateTypeEx info = rateTypeService.selectRateTypeInfoByName(typeList.get(k-7));
           		RateTypeEx parentInfo1 = rateTypeService.selectRateTypeInfoByName(parent1Name);
           		if(info==null) {
           			msg="系统内未找到对应分类信息,请检查!";
           		}else {
           			if(Utils.notBlank(girlValue)) {
           				//业务保存方法
           				saveRate(insuranceProdectInfo.getId(),parentInfo1.getId(),info.getId(),2,girlValue,age,femaleSex);
           			}
           		}
           	}
         		}
         	  }
         }catch (Exception e) {
          e.printStackTrace();
          if (StringUtils.isBlank(msg)) {
              msg +=msg;
          }
          TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
          return ResultMap.error(msg);
     }
     return ResultMap.success();
 }

以上就是大概的具体实现步骤,在开发过程中要思路明确,当遇到这种涉及读取跨列合并单元格的表格时,我们要掌握一开始上述所说的最基本的读取单元格,获取跨列数等系列方法,并且结合自己的业务需求进行处理即可,好了,今天就到这边了,希望大家给我支持,后续继续进行遇坑分享!

  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,针对您的问题,我可以给您提供一些思路。 首先,您可以使用POI这个Java库来生成Excel文件。POI提供了一系列的API来创建、修改和读取Excel文件。您可以通过POI来创建一个工作簿,然后在工作簿中创建一个工作表,接着设置工作表的表头合并单元格等。 其次,您需要将数据循环读取出来,然后按照您的需求填充到Excel文件中。您可以通过POI提供的API来设置单元格的值、样式等。在填充数据的过程中,根据您的需求来进行合并单元格,可以使用CellRangeAddress类来设置需要合并单元格。 最后,将生成的Excel文件写入到输出流中,这样就可以将Excel文件输出到客户端或者保存到服务器中了。 下面是一个简单的示例代码,仅供参考: ```java // 创建工作簿 Workbook workbook = new XSSFWorkbook(); // 创建工作表 Sheet sheet = workbook.createSheet("Sheet1"); // 设置表头 Row headerRow = sheet.createRow(0); Cell headerCell = headerRow.createCell(0); headerCell.setCellValue("表头"); // 合并单元格 CellRangeAddress region = new CellRangeAddress(0, 0, 0, 3); sheet.addMergedRegion(region); // 填充数据 for (int i = 0; i < dataList.size(); i++) { Row dataRow = sheet.createRow(i + 1); // 设置单元格的值 dataRow.createCell(0).setCellValue(dataList.get(i).getName()); dataRow.createCell(1).setCellValue(dataList.get(i).getAge()); dataRow.createCell(2).setCellValue(dataList.get(i).getGender()); dataRow.createCell(3).setCellValue(dataList.get(i).getAddress()); } // 将Excel文件写入输出流 ServletOutputStream outputStream = response.getOutputStream(); workbook.write(outputStream); outputStream.flush(); outputStream.close(); ``` 当然,这只是一个简单的示例代码,您需要根据实际需求来进行更加详细的实现。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值