SpringBoot文件上传丢失Bug记录

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);
    }
}

从注释行可看出我们的文件路径被篡改了,这也是我们报错文件位置不一致的原因。

image-20230215131333209

去文件夹下查看也没有文件,这是因为上述代码并没有创建我们定义的ing文件夹,更改文件位置代码验证一下

image-20230215133011484

思路正确,但感觉location参数有点不明所以,去Spring官方看看有没有相关insser

When i use transferTo() to copy a uploadfile to a relative address,the file is missing

image-20230215142356348

跟进到#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);
    }
    
posted @ 2023-02-15 15:59  KMP  阅读(160)  评论(0编辑  收藏  举报