Spring Boot接口中同名Excel文件多次上传时文件保存异常的解决方案咨询
问题分析与解决方案
首先,咱们先定位问题核心:你每次上传的Excel数据都能成功插入数据库,但同名文件只有第一次能保存到本地。这说明数据库操作的逻辑是正常的,但文件保存环节在重复上传同名文件时出现了异常,而这个异常没有被你及时发现。
为什么会出现这个问题?
看你的代码,文件保存部分是这样的:
String destination = "C:\\Users\\anar.memmedov\\Desktop\\app\\" + filePath.getOriginalFilename(); File file1 = new File(destination); filePath.transferTo(file1);
transferTo方法在目标文件已经存在时,默认会抛出IOException(不同Servlet容器的实现可能略有差异,但大部分都会阻止覆盖已存在的文件)。而你的代码里,这部分逻辑放在了包含数据库操作的try块中:
- 数据库操作在文件保存之前执行,所以即使后面文件保存失败,数据已经成功插入了数据库。
- 异常被catch块捕获后,只是打印了栈信息,你没有收到明确的错误反馈,误以为接口正常执行,但实际上文件保存失败了。
解决方案
针对这个问题,有几种常见的处理方式,你可以根据业务需求选择:
1. 生成唯一文件名(推荐,避免文件覆盖)
给每个上传的文件添加唯一标识(比如时间戳、UUID),确保即使文件名相同,保存到本地的路径也不一样。示例代码:
// 获取原文件名 String originalFileName = filePath.getOriginalFilename(); // 生成唯一文件名:时间戳 + 原文件名,避免冲突 String uniqueFileName = System.currentTimeMillis() + "_" + originalFileName; String destination = "C:\\Users\\anar.memmedov\\Desktop\\app\\" + uniqueFileName; File file1 = new File(destination); filePath.transferTo(file1);
2. 强制覆盖已存在的文件
如果你确实需要保留原文件名,并且允许覆盖旧文件,可以在保存前先删除已存在的文件,或者使用Files.copy并指定覆盖选项:
方式A:先删除再保存
String destination = "C:\\Users\\anar.memmedov\\Desktop\\app\\" + filePath.getOriginalFilename(); File file1 = new File(destination); // 如果文件已存在,先删除 if (file1.exists()) { if (!file1.delete()) { throw new IOException("无法删除已存在的文件,请检查文件权限或是否被占用"); } } filePath.transferTo(file1);
方式B:使用Files.copy强制覆盖
import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; // ... String destination = "C:\\Users\\anar.memmedov\\Desktop\\app\\" + filePath.getOriginalFilename(); // 使用Files.copy并指定REPLACE_EXISTING选项强制覆盖 Files.copy(filePath.getInputStream(), Paths.get(destination), StandardCopyOption.REPLACE_EXISTING);
3. 优化异常处理
另外,你当前的异常处理逻辑不够完善,建议在catch块中返回明确的错误响应,而不是只打印栈信息:
catch (IOException e) { e.printStackTrace(); return new ResponseEntity<>(new ErrorResponse("文件保存失败: " + e.getMessage(), 500), HttpStatus.INTERNAL_SERVER_ERROR); }
额外的代码优化建议
除了文件保存的问题,你的Excel单元格处理逻辑也有潜在问题:
while (cellIterator.hasNext()) { Cell currentCell = cellIterator.next(); if (currentCell.getCellType() == CellType.NUMERIC) { phoneNumber = NumberToTextConverter.toText(currentCell.getNumericCellValue()); } else if (currentCell.getCellType() == CellType.STRING) { textMessage = String.valueOf(currentCell.getStringCellValue()); } }
这段代码会遍历一行中的所有单元格,最后一个数字单元格会覆盖phoneNumber,最后一个字符串单元格会覆盖textMessage——如果你的Excel是固定列(比如第一列是手机号,第二列是短信内容),建议按列索引来获取单元格,避免意外覆盖:
// 跳过表头行(如果你的Excel有表头的话) if (currentRow.getRowNum() == 0) { continue; } // 假设第0列是手机号,第1列是短信内容 Cell phoneCell = currentRow.getCell(0); if (phoneCell != null && phoneCell.getCellType() == CellType.NUMERIC) { phoneNumber = NumberToTextConverter.toText(phoneCell.getNumericCellValue()); } Cell messageCell = currentRow.getCell(1); if (messageCell != null && messageCell.getCellType() == CellType.STRING) { textMessage = messageCell.getStringCellValue(); }
另外,你用了try-with-resources来包裹InputStream excelFile,这会自动关闭流,所以手动调用excelFile.close()是多余的,可以去掉。
内容的提问来源于stack exchange,提问作者iwritecomeinmymind




