使用POI读取Excel空单元格问题:空单元格被填充为上一单元格内容
Apache POI 4.1.2读取Excel时空单元格被填充为上一行内容的问题及解决
问题现象
- Excel文件中部分行的月份列存在空单元格,但读取后存入数据库时,这些空单元格被自动填充为上一行对应列的内容
- 数据库存储结果显示原本为空的单元格被上一行的数值覆盖
使用的Apache POI依赖
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.1.2</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.1.2</version> </dependency>
问题代码
@RequestMapping("/mng/mngSaupExcelUpload14.do") public ModelAndView mngBizApplyExcelUpload14(MultipartHttpServletRequest request, HttpServletResponse response, HttpSession session, INDEYearVO attach) throws IOException, ParseException { Iterator<String> iterator = request.getFileNames(); int actResult = 0; ModelAndView mav = new ModelAndView(); response.setContentType("text/html"); response.setCharacterEncoding("UTF-8"); PrintWriter out = response.getWriter(); MultipartFile mFile = null; while (iterator.hasNext()) { String uploadFileName = iterator.next(); mFile = request.getFile(uploadFileName); } XSSFWorkbook workbook = new XSSFWorkbook(mFile.getInputStream()); for (int sheetNum = 0; sheetNum < workbook.getNumberOfSheets(); sheetNum++) { XSSFSheet sheet = workbook.getSheetAt(sheetNum); int rows = sheet.getPhysicalNumberOfRows(); int rowindex = 0; int columnindex = 0; if (sheetNum == 0) { for (rowindex = 1; rowindex < rows; rowindex++) { sheet = workbook.getSheetAt(0); XSSFRow row = sheet.getRow(rowindex); if (row != null) { int cells = row.getPhysicalNumberOfCells(); for (columnindex = 0; columnindex <= cells; columnindex++) { XSSFCell cell = row.getCell(columnindex); String value = ""; if (cell == null) { continue; } else { switch (cell.getCellType()) { case FORMULA: value = cell.getCellFormula(); break; case NUMERIC: double cellValue = cell.getNumericCellValue(); if (cellValue == Math.rint(cellValue)) { value = String.valueOf((int) cellValue); } else { value = String.valueOf(cellValue); } break; case STRING: value = cell.getStringCellValue() + ""; break; case BLANK: value = null; break; case ERROR: value = cell.getErrorCellValue() + ""; break; default: } if (columnindex == 0) { attach.setSn(Integer.parseInt(value)); } else if (columnindex == 1) { attach.setYear(Integer.parseInt(value)); } else if (columnindex == 2) { attach.setSigngu(value); } else if (columnindex == 3) { attach.setJan(Integer.parseInt(value)); } else if (columnindex == 4) { attach.setFeb(Integer.parseInt(value)); } else if (columnindex == 5) { attach.setMar(Integer.parseInt(value)); } else if (columnindex == 6) { attach.setApr(Integer.parseInt(value)); } else if (columnindex == 7) { attach.setMay(Integer.parseInt(value)); } else if (columnindex == 8) { attach.setJne(Integer.parseInt(value)); } else if (columnindex == 9) { attach.setJly(Integer.parseInt(value)); } else if (columnindex == 10) { attach.setAug(Integer.parseInt(value)); } else if (columnindex == 11) { attach.setSep(Integer.parseInt(value)); } else if (columnindex == 12) { attach.setOct(Integer.parseInt(value)); } else if (columnindex == 13) { attach.setNov(Integer.parseInt(value)); } else if (columnindex == 14) { if ("false".equals(value) || "".equals(value) || "0".equals(value) || value == null ) { attach.setDec(Integer.parseInt("")); } else { attach.setDec(Integer.parseInt(value)); } } } } actResult = attachFileService.fileInsertActForExcel14(attach); } } } } if (actResult > 0) { out.println("<script>"); out.println("alert('등록에 성공 하였습니다.');"); out.println("location.replace('" + request.getContextPath() + "attachFile.do');"); out.println("</script>"); out.flush(); out.close(); return null; } else { out.println("<script>"); out.println("alert('등록 중 오류가 발생했습니다.');"); out.println("location.replace('" + request.getContextPath() + "attachFile.do');"); out.println("</script>"); out.flush(); out.close(); return null; } }
问题原因
- 复用VO对象:方法参数传入的
INDEYearVO attach被所有行复用,每一行处理时如果某个单元格为空(或未被遍历到),该属性会保留上一行设置的值,导致存入数据库时出现上一行的内容。 - 单元格遍历逻辑缺陷:
row.getPhysicalNumberOfCells()仅返回当前行中有实际数据的单元格数量,对于空单元格(未被创建的cell)会直接跳过,没有对对应的VO属性进行清空操作。 - 空单元格处理不完善:当cell为null时直接
continue,没有处理对应的VO属性;BLANK类型设置value为null,但部分属性赋值时没有处理null情况,导致旧值残留。
解决办法
1. 每行创建新的VO实例
在处理每一行数据前,创建新的INDEYearVO对象,避免复用旧对象的属性值。
2. 遍历所有需要处理的列
固定遍历0到14列(对应业务中的所有字段),而不是仅遍历存在数据的单元格,确保每一列都被处理,包括空单元格。
3. 完善空单元格的赋值逻辑
对于空单元格(cell为null或BLANK类型),明确设置对应的VO属性为null或默认值,避免旧值残留。
修改后的核心代码示例
if (sheetNum == 0) { for (rowindex = 1; rowindex < rows; rowindex++) { // 每行创建新的VO实例 INDEYearVO attach = new INDEYearVO(); XSSFRow row = sheet.getRow(rowindex); if (row != null) { // 遍历所有需要处理的列(0到14) for (columnindex = 0; columnindex <= 14; columnindex++) { XSSFCell cell = row.getCell(columnindex); String value = ""; if (cell == null || cell.getCellType() == CellType.BLANK) { // 空单元格设置value为null value = null; } else { switch (cell.getCellType()) { case FORMULA: value = cell.getCellFormula(); break; case NUMERIC: double cellValue = cell.getNumericCellValue(); if (cellValue == Math.rint(cellValue)) { value = String.valueOf((int) cellValue); } else { value = String.valueOf(cellValue); } break; case STRING: value = cell.getStringCellValue().trim(); break; case ERROR: value = String.valueOf(cell.getErrorCellValue()); break; default: value = null; } } // 根据列索引设置VO属性,处理null情况 if (columnindex == 0) { attach.setSn(value != null ? Integer.parseInt(value) : null); } else if (columnindex == 1) { attach.setYear(value != null ? Integer.parseInt(value) : null); } else if (columnindex == 2) { attach.setSigngu(value); } else if (columnindex == 3) { attach.setJan(value != null ? Integer.parseInt(value) : null); } else if (columnindex == 4) { attach.setFeb(value != null ? Integer.parseInt(value) : null); } else if (columnindex == 5) { attach.setMar(value != null ? Integer.parseInt(value) : null); } else if (columnindex == 6) { attach.setApr(value != null ? Integer.parseInt(value) : null); } else if (columnindex == 7) { attach.setMay(value != null ? Integer.parseInt(value) : null); } else if (columnindex == 8) { attach.setJne(value != null ? Integer.parseInt(value) : null); } else if (columnindex == 9) { attach.setJly(value != null ? Integer.parseInt(value) : null); } else if (columnindex == 10) { attach.setAug(value != null ? Integer.parseInt(value) : null); } else if (columnindex == 11) { attach.setSep(value != null ? Integer.parseInt(value) : null); } else if (columnindex == 12) { attach.setOct(value != null ? Integer.parseInt(value) : null); } else if (columnindex == 13) { attach.setNov(value != null ? Integer.parseInt(value) : null); } else if (columnindex == 14) { if (value == null || "false".equals(value) || "".equals(value) || "0".equals(value)) { attach.setDec(null); } else { attach.setDec(Integer.parseInt(value)); } } } actResult = attachFileService.fileInsertActForExcel14(attach); } } }
额外注意事项
- 确保
INDEYearVO的属性支持null值(对应数据库字段允许为空),否则需要设置默认值(如0)。 - 处理
Integer.parseInt时,要确保value不为null且是有效数字,避免抛出NumberFormatException,可以添加异常捕获或提前校验。
内容的提问来源于stack exchange,提问作者hayley
相关产品推荐
相关产品推荐

