SpringBoot文件上传丢失Bug记录
报错如下:
java.io.FileNotFoundException: C:\Users\zbz12\AppData\Local\Temp\tomcat.708075972435741143.8080\work\Tomcat\localhost\community.\img\c1e0c03994754a278d56b5abd67f2f06.jpg (系统找不到指定的路径。)
实际文件位置:
community:
path:
domain: http://localhost:8080 #域名
upload: ./img # 默认本地文件存储位置
涉及程序段:
// 生成随机文件名
fileName = CommunityUtil.generateUUID() + suffix;
// 确定文件存放的路径
File tmpFile = new File(uploadPath + "/" + fileName);
try {
if (!tmpFile.exists()) {
new File(uploadPath).mkdirs();
}
// 存储文件
headerImage.transferTo(tmpFile);
} catch (IOException e) {
log.error("上传文件失败: " + e.getMessage());
throw new RuntimeException("上传文件失败,服务器发生异常!", e);
}
从上面配置等内容我们可知,Spring存储文件的位置和我们配置的位置并不一致,而去配置文件夹下可发现对应文件夹已经创建,这应该是MultipartFile方法执行的问题。所以我们在transferTo(tmpFile)
行打断点进行错误排查。
打断点进行Dbug调试
@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
this.part.write(dest.getPath());
if (dest.isAbsolute() && !dest.exists()) {//文件路径是绝对路径且非空
// Servlet 3.0 Part.write is not guaranteed to support absolute file paths:
// may translate the given path to a relative location within a temp dir
// (e.g. on Jetty whereas Tomcat and Undertow detect absolute paths).
// At least we offloaded the file from memory storage; it'll get deleted
// from the temp dir eventually in any case. And for our user's purposes,
// we can manually copy it to the requested location as a fallback.
// 翻译:Servlet 3.0 Part.write不保证支持绝对文件路径: 可以将给定路径转换为临时目录内的相对位置 (例如,在Jetty上,而Tomcat和Undertow检测绝对路径)。至少我们从内存存储中卸载了文件; 无论如何,它最终都会从临时目录中删除。为了我们用户的目的,我们可以手动将其复制到请求的位置作为后备。
FileCopyUtils.copy(this.part.getInputStream(), Files.newOutputStream(dest.toPath()));
}
从上面我们可以看出part.write(dest.getPath());
是相对路径执行的方法,而我配置的就是相对路径,进入write
继续查看。
@Override
public void write(String fileName) throws IOException {
File file = new File(fileName);
if (!file.isAbsolute()) {
file = new File(location, fileName);//多出一个参数 location
}
try {
fileItem.write(file);
} catch (Exception e) {
throw new IOException(e);
}
}
从注释行可看出我们的文件路径被篡改了,这也是我们报错文件位置不一致的原因。
去文件夹下查看也没有文件,这是因为上述代码并没有创建我们定义的ing文件夹,更改文件位置代码验证一下
思路正确,但感觉location参数有点不明所以,去Spring官方看看有没有相关insser
When i use transferTo() to copy a uploadfile to a relative address,the file is missing
跟进到#19822,大致了解了这样操作的原因,但我还是想用相对路径操作
解决办法如下:
-
使用
public void transferTo(Path dest)
方法,代码如下:// 确定文件存放的路径 Path path = Paths.get(uploadPath + "/" + fileName); File tmpFile = new File(uploadPath); try { if (!tmpFile.exists()) { tmpFile.mkdirs(); } // 存储文件 headerImage.transferTo(path); } catch (IOException e) { log.error("上传文件失败: " + e.getMessage()); throw new RuntimeException("上传文件失败,服务器发生异常!", e); }