java读取Excel导入去除空行

问题:
在Java读取Excel导入操作时, sheet.getLastRowNum()会统计带有格式的空白行,导致获取的最大行数不准确,数据导入失败。
在这里插入图片描述

在这里插入图片描述
解决:
在操作过程中删除存在样式的空白行
可通过将空白行(内容为空,但是存在样式)进行sheet.removeRow删除后
再调用getLastRowNum()进行行数统计,getAccuracyContextNum()方法中。

@Transactional(rollbackFor =  Exception.class)
	public Map<String,Object> importWeb(Workbook wb,String skillName,String skilltype,String office) {
		StringBuilder msg = new StringBuilder();
		Map<String, Object> reMap = new HashMap<>();
		Sheet sheet = wb.getSheetAt(0);
		Row titleRow = sheet.getRow(0);
		if (titleRow.getLastCellNum() != 3 || !"项目名称".equals(getCellValue(titleRow.getCell(0)))
				|| !"操作要点".equals(getCellValue(titleRow.getCell(1))) || !"总分".equals(getCellValue(titleRow.getCell(2)))){
			reMap.put("flag",false);
			reMap.put("msg","模板错误");
			return reMap;
		}

		//获取合并单元格信息的hashmap
		Map<String,Integer[]> mergedRegionMap = getMergedRegionMap(sheet);

		//拿到excel的最后一行的索引
//		int lastRowNum = sheet.getLastRowNum();
		sheet=getAccuracyContextNum(wb,mergedRegionMap);
		int lastRowNum=sheet.getLastRowNum();
		List<Map<String, Object>> projectNameList = new ArrayList<>();
		List<Map<String, Object>> mainPointsList = new ArrayList<>();
		//nursetrain_skill_oper表主键id
		String operId = IdGen.uuid();
		BigDecimal totalScore = new BigDecimal(0);
		//从excel的第二行索行开始,遍历到最后一行(第一行是标题,直接跳过不读取)
		for(int i = 1; i<=lastRowNum ; i++) {
			//拿到excel的行对象
			Row row = sheet.getRow(i);
			//获取excel的行中有多个列
			int cellNum = row.getLastCellNum();

			if (cellNum > 3){
				reMap.put("flag",false);
				reMap.put("msg","数据列超出标题范围");
				return reMap;
			}

			Map<String, Object> projectMap = new LinkedHashMap<>();
			Map<String, Object> mainPointsMap = new LinkedHashMap<>();
			//对每行进行列遍历,即一列一列的进行解析
			for(int j=0; j < cellNum; j++) {
				//拿到了excel的列对象
				Cell cell = row.getCell(j);

				//将列对象的行号和列号+下划线组成key去hashmap中查询,不为空说明当前的cell是合并单元列
				Integer[] firstRowNumberAndCellNumber = mergedRegionMap.get(i+"_"+j);

				//如果是合并单元列,就取合并单元格的首行和首列所在位置读数据,否则就是直接读数据
				if(firstRowNumberAndCellNumber != null) {
					Row rowTmp = sheet.getRow(firstRowNumberAndCellNumber[0]);
					Cell cellTmp = rowTmp.getCell(firstRowNumberAndCellNumber[1]);
					if (j == 0 ){
						projectMap.put("NAME", getCellValue(cellTmp));
						if(StringUtils.isEmpty(getCellValue(cellTmp))) {
							msg.append("第").append(i + 1).append("行项目名称不能为空").append("<br>");
						}
					}
					if (j == 1){
						mainPointsMap.put("NAME", getCellValue(cellTmp));
						if(StringUtils.isEmpty(getCellValue(cellTmp))) {
							msg.append("第").append(i + 1).append("行操作要点不能为空").append("<br>");
						}
					}
					if (j == 2){
						mainPointsMap.put("SCORE", getCellValue(cellTmp));
						if(StringUtils.isEmpty(getCellValue(cellTmp))) {
							msg.append("第").append(i + 1).append("行总分不能为空").append("<br>");
						}else{
							try{
								BigDecimal score = new BigDecimal(getCellValue(cellTmp)).setScale(2,RoundingMode.DOWN);
								totalScore = totalScore.add(score);
							}catch (Exception e){
								msg.append("第").append(i + 1).append("行总分只能为数字").append("<br>");
							}
						}
					}
					mainPointsMap.put("order", i);
				}else{
					if (j == 0 ){
						projectMap.put("NAME", getCellValue(cell));
						if(StringUtils.isEmpty(getCellValue(cell))) {
							msg.append("第").append(i + 1).append("行项目名称不能为空").append("<br>");
						}
					}
					if (j == 1){
						mainPointsMap.put("NAME", getCellValue(cell));
						if(StringUtils.isEmpty(getCellValue(cell))) {
							msg.append("第").append(i + 1).append("行操作要点不能为空").append("<br>");
						}
					}
					if (j == 2){
						mainPointsMap.put("SCORE", getCellValue(cell));
						if(StringUtils.isEmpty(getCellValue(cell))) {
							msg.append("第").append(i + 1).append("行总分不能为空").append("<br>");
						}else {
							try{
								BigDecimal score = new BigDecimal(String.valueOf(getCellValue(cell))).setScale(2,RoundingMode.UP);
								totalScore = totalScore.add(score);
							}catch (Exception e){
								msg.append("第").append(i + 1).append("行总分只能为数字").append("<br>");
							}
						}
					}
					mainPointsMap.put("order", i);
				}
			}
			``````
		try {
			//插入nursetrain_skill_oper表
			//插入nursetrain_skill_oper_item表
			//插入nursetrain_skill_oper_item_step表
			reMap.put("flag",true);
			reMap.put("msg","导入成功");
		}catch (Exception e){
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			reMap.put("flag",false);
			reMap.put("msg","导入失败,请联系系统管理员");
		}
		return reMap;
	}
//获取准确的文件行数
	public Sheet getAccuracyContextNum(Workbook workbook,Map<String,Integer[]> mergedRegionMap) {
		// 取第一个sheet
		Sheet sheet = workbook.getSheetAt(0);
		// 删除空行
		for (int i = 0; i <= sheet.getLastRowNum(); i++) {
			Row row = sheet.getRow(i);
			int cellNum = row.getLastCellNum();
			boolean flag=false;
			for(int j=0; j < cellNum; j++) {
				Integer[] firstRowNumberAndCellNumber = mergedRegionMap.get(i+"_"+j);
				if(firstRowNumberAndCellNumber != null){
					flag=true;
				}
			}
			if (this.isRowEmpty(row) && !flag) {
			// 删除空行
			if (this.isRowEmpty(row)) {
				int lastRowNum = sheet.getLastRowNum();
				if (i >= 0 && i < lastRowNum) {
					sheet.shiftRows(i + 1, lastRowNum, -1);// 将行号为i+1一直到行号为lastRowNum的单元格全部上移一行,以便删除i行
				}
				if (i == lastRowNum) {
					if (row != null) {
						sheet.removeRow(row);
					}
				}
				i--;
			}
		}
		return sheet;
	}
	/**
	 * 判断是否有空行
	 * @param row
	 * @return
	 */
	private  boolean isRowEmpty(Row row) {
		for (int c = row.getFirstCellNum(); c < row.getLastCellNum(); c++) {
			Cell cell = row.getCell(c);
			if (cell != null && cell.getCellType() != Cell.CELL_TYPE_BLANK) {
				return false;
			}
		}
		return true;
	}
	//将存在合并单元格的列记录入put进hashmap并返回
	public Map<String,Integer[]> getMergedRegionMap(Sheet sheet){

		Map<String,Integer[]> result = new HashMap<String,Integer[]>();

		//获取excel中的所有合并单元格信息
		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();

			//构造一个开始行和开始列组成的数组
			Integer[] firstRowNumberAndCellNumber = new Integer[]{firstRow,firstColumn};

			//遍历,将单元格中的所有行和所有列处理成由行号和下划线和列号组成的key,然后放在hashmap中
			for(int currentRowNumber = firstRow; currentRowNumber <= lastRow; currentRowNumber++) {

				for(int currentCellNumber = firstColumn; currentCellNumber <= lastColumn; currentCellNumber ++) {
					result.put(currentRowNumber+"_"+currentCellNumber, firstRowNumberAndCellNumber);
				}
			}
		}
		return result;
	}
  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
优化这段代码 public static LinkedHashMap<String, String> excelToShopIdList(InputStream inputStream) { LinkedHashMap<String, String> res = new LinkedHashMap<>(); try { Workbook sheets = WorkbookFactory.create(inputStream); inputStream.close(); Sheet sheetAt = sheets.getSheetAt(0); // 获取设备编码 res.put("deviceCode", sheetAt.getSheetName()); int lastRowNum = sheetAt.getLastRowNum() + 1; // 标识 从该行开始解析 String[] ar = new String[]{"name", "base", "decimal", "description", "disable", "mult"}; int isTrueNum = 0; for (int i = 0; i < lastRowNum; i++) { Row row = sheetAt.getRow(i); // 空行直接跳过 if (ObjectUtils.isEmpty(row)) { isTrueNum = 0; continue; } // isTrueNum < 6 说明 和标识行没有完全匹配 if (isTrueNum < 6) { isTrueNum = 0; //和 标识行进行匹配 for (int j = 0; j < ar.length; j++) { if (ObjectUtils.isNotEmpty(row.getCell(j) ) && row.getCell(j).getCellType().equals(CellType.STRING) && ar[j].equals(row.getCell(j).getStringCellValue())) { isTrueNum++; continue; } } } else { Cell nameCell = row.getCell(0); Cell desCell = row.getCell(3); Cell typeCell = row.getCell(13); if (ObjectUtils.isEmpty(nameCell)) { continue; } if (CellType.STRING.equals(nameCell.getCellType()) && StringUtils.isEmpty(nameCell.getStringCellValue())) { continue; } // 结束标识行 if ("var_name".equals(nameCell.getStringCellValue())) { break; } res.put(nameCell.getStringCellValue(), desCell.getStringCellValue()); res.put(nameCell.getStringCellValue()+"_type#", typeCell.getStringCellValue()); } } } catch (IOException e) { e.printStackTrace(); } return res; }
06-03
这段代码可以进行如下优化: 1. 使用try-with-resources语句,自动关闭输入流。 2. 可以将Sheet对象的获取和解析逻辑单独抽出来作为一个方法,提高代码的可读性和可维护性。 3. 使用常量来代替魔法值,提高代码的可读性。 4. 使用StringUtils.isNotBlank()代替ObjectUtils.isNotEmpty()和StringUtils.isNotEmpty(),代码更简洁。 改进后的代码如下: ``` private static final String[] COLUMN_NAMES = {"name", "base", "decimal", "description", "disable", "mult"}; private static final String VAR_NAME_COLUMN_NAME = "var_name"; private static final int COLUMN_NAME_INDEX = 0; private static final int DESCRIPTION_INDEX = 3; private static final int TYPE_INDEX = 13; public static LinkedHashMap<String, String> excelToShopIdList(InputStream inputStream) { LinkedHashMap<String, String> res = new LinkedHashMap<>(); try (Workbook workbook = WorkbookFactory.create(inputStream)) { Sheet sheet = workbook.getSheetAt(0); String deviceCode = sheet.getSheetName(); res.put("deviceCode", deviceCode); int lastRowIndex = sheet.getLastRowNum() + 1; int matchedColumnCount = 0; for (int i = 0; i < lastRowIndex; i++) { Row row = sheet.getRow(i); if (row == null) { matchedColumnCount = 0; continue; } if (matchedColumnCount < COLUMN_NAMES.length) { matchedColumnCount = matchColumnNames(row); } else { Cell nameCell = row.getCell(COLUMN_NAME_INDEX); if (nameCell == null || StringUtils.isBlank(nameCell.getStringCellValue())) { continue; } if (VAR_NAME_COLUMN_NAME.equals(nameCell.getStringCellValue())) { break; } Cell descriptionCell = row.getCell(DESCRIPTION_INDEX); Cell typeCell = row.getCell(TYPE_INDEX); res.put(nameCell.getStringCellValue(), descriptionCell.getStringCellValue()); res.put(nameCell.getStringCellValue() + "_type#", typeCell.getStringCellValue()); } } } catch (IOException e) { e.printStackTrace(); } return res; } private static int matchColumnNames(Row row) { int matchedColumnCount = 0; for (int j = 0; j < COLUMN_NAMES.length; j++) { Cell cell = row.getCell(j); if (cell != null && cell.getCellType() == CellType.STRING && COLUMN_NAMES[j].equals(cell.getStringCellValue())) { matchedColumnCount++; } } return matchedColumnCount; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值