SpingBoot 1.5.2,MultipartFile保存图片时的不稳定异常(好像和内置tomcat有关)
最近项目上用到图片上传,一开始我都用的是SpringMVC自带的MultipartFile来处理的,不需要自己新建流来处理,
MultipartFile有个方法是void transferTo(File dest) throws IOException, IllegalStateException;
可以快速的处理。
做的项目是SpringBoot、和Spring、SpringMVC、Mybatis框架搭建的,如果使用MultipartFile的transferTo方法,会发现不太稳定。有时候会在执行这个方法时抛出异常,表示文件或者目录不存在
报错信息这会儿不好找了,
但报错的目录是Tomcat内部的一个目录,好像是Tomcat把用自己临时目录然后由组合了我们项目文件落地的目录去保存问价 这当然后报文件或者目录不存在。
/** * 保存上传文件到制定目录地址 * * @param file * 当前上传那文件 * @param filePath * 档期保存文件目录地址(全路径),带文件名的目录地址 * @return 返回当前保存后的文件 * @throws IOException */ public File saveFile(MultipartFile file, String filePath) throws IOException { LOGGER.info("ImageUtil's saveFile 进来了:{}", filePath); File tempFile = new File(filePath); if (!tempFile.getParentFile().exists()) { tempFile.getParentFile().mkdirs(); } if (!tempFile.exists()) { LOGGER.info("filePath exists 时 创建 {}", filePath); tempFile.createNewFile(); } file.transferTo(tempFile); return tempFile; }
深入到源码内部,发现是:org.apache.catalina.core.ApplicationPart中的
@Override public void write(String fileName) throws IOException { File file = new File(fileName); if (!file.isAbsolute()) { file = new File(location, fileName); } try { fileItem.write(file); } catch (Exception e) { throw new IOException(e); } }
这个方法抛出的错误,file.isAbsolute()认为我们的目录不是绝对路径,然后以为是相对路径,再去创建文件,肯定会导致报错。
本人亲测下来发现Windows下如果保存路径写得不正确肯定会出错;比如直接copy Windows目录下的E:\abc,而应该是写成:app.comment.image=E:\\abc
但是在Linux服务器环境下,有时候(概率比较低),也会出现这种情况;暂时我还没有发现为什么会这样,但是Linux下偶尔出错应该也是这个问题
记得之前有一次,慕名奇妙图片上传失败,这一块的代码没有动过,为什么会出现这种情况呢,我仔细查看原来是自从上次发布之后,突然之间图片就不能正常上传了,所以在没有深究原因的情况下,无奈的对运维说:要不把服务重启一下,这下还真的邪门了,服务重启之后,就可以正常的传图了
上次是生产环境的问题,后来在测试环境中无意中也出问题了。最后果断把这个方法给改掉了;
一劳永逸的解决这个问题:
自己用流来写:
/** * 保存上传文件到制定目录地址 * * @param file * 当前上传那文件 * @param filePath * 档期保存文件目录地址(全路径),带文件名的目录地址 * @return 返回当前保存后的文件 * @throws IOException */ public File saveFile(MultipartFile file, String filePath) throws IOException { LOGGER.info("ImageUtil's saveFile{}: ", filePath); // file.transferTo(tempFile); // return tempFile; File tempFile = new File(filePath); if (!tempFile.getParentFile().exists()) { boolean mkdirs = tempFile.getParentFile().mkdirs(); LOGGER.info("--------创建父目录:{}", mkdirs); } try (BufferedOutputStream buffStream = new BufferedOutputStream(new FileOutputStream(tempFile))) { byte[] bytes = file.getBytes(); buffStream.write(bytes); buffStream.flush(); } return tempFile; }