文件上传transferTo一行代码的bug
transferTo
我们在上传文件的时候会用到transferTo 这个方法,
transferTo
是 package org.springframework.web.multipart;
帮我们已经封装好,所以我们上传文件的时候是很方便的,只需要一行代码。
Spring 大哥真的是强大。
今天我们上传的时候老是报错,错误提示
java.io.IOException: java.io.FileNotFoundException: /opt/xxxxxxx/xxx.png (Is a directory)
看到这里大家大概就明吧了。
String path = FILE_PATH + PATH_NAME + File.separator + dirName; String fileName = file.getOriginalFilename(); ======>注意这里等下要讲的 File targetFile = new File(path , fileName); if (!targetFile.exists()) { targetFile.mkdirs(); } boolean upState = false; try { file.transferTo(targetFile); upState = true; } catch (IOException e) { log.error("file transferTo e", e); e.printStackTrace(); }
分析下
其实这个这里上传文件只是一个方法,用到了 Spring
自己封装的MultipartFile
类,上传只是用到了transferTo,参数是文件的路径。
好了,来一步步调试看源码。
- 第一步看transferTo中的源码
public void transferTo(File dest) throws IOException, IllegalStateException { ======>注意这里调用的是part 类中的write 方法,参数是File的路径 this.part.write(dest.getPath()); if (dest.isAbsolute() && !dest.exists()) { FileCopyUtils.copy(this.part.getInputStream(), new FileOutputStream(dest)); } }
- 第二步看 ApplicationPart 中的write方法
public void write(String fileName) throws IOException { File file = new File(fileName); if (!file.isAbsolute()) { file = new File(this.location, fileName); } try { this.fileItem.write(file); } catch (Exception var4) { throw new IOException(var4); } }
大家注意看第二步中的 if (!file.isAbsolute())
,是的问题就在这里。
这时候如果!file.isAbsolute()成立,也就是我们没有使用绝对路径,那么file = new File(location,fileName);
这个时候会创建一个新的路径,看下面的代码
public File(File parent, String child) { if (child == null) { throw new NullPointerException(); } if (parent != null) { if (parent.path.equals("")) { this.path = fs.resolve(fs.getDefaultParent(), fs.normalize(child)); } else { this.path = fs.resolve(parent.path, fs.normalize(child)); } } else { this.path = fs.normalize(child); } this.prefixLength = fs.prefixLength(this.path); }
看到这里应该了解了/opt/xxxxxxx/xxx.png
,这个图片被当成文件夹了,在这里创建了一个文件夹,而不是图片。
解决方法
- 代码注入,修改源码中的location
@Bean MultipartConfigElement multipartConfigElement() { MultipartConfigFactory factory = new MultipartConfigFactory(); factory.setLocation(你的上传路径path); return factory.createMultipartConfig(); }
- 文件上传时候创建文件
String path = FILE_PATH + PATH_NAME + File.separator + dirName; String fileName = file.getOriginalFilename(); ======> 注意要先创建图片的目录mkdirs File sourceFile = new File(path); if (!sourceFile.exists()) { sourceFile.mkdirs(); } File targetFile = new File(path + File.separator + fileName); boolean upState = false; try { file.transferTo(targetFile); upState = true; } catch (IOException e) { log.error("file transferTo e", e); e.printStackTrace(); }
这里其实就是 new File(path + File.separator + fileName)
的问题,因为Spring的源码中不会根据你给的路径自动创建图片的上一层路径。