本次的项目环境为 Running with Spring Boot v1.5.10.RELEASE, Spring v4.3.14.RELEASE, 服务器环境为CentOS7.0.
我们在上传文件的时候会用到 transferTo 这个方法,
 transferTo 是 package org.springframework.web.multipart; 帮我们已经封装好,所以我们上传文件的时候是很方便的,只需要一行代码。 
Spring 大哥真的是强大。
今天我们上传的时候老是报错,错误提示
 java.io.IOException: java.io.FileNotFoundException: /opt/xxxxxxx/xxx.png (Is a directory) 
 
 
 蹩脚的英文好好的翻译一下,xxx.png 是一个目录。
对的,看到这里大家大概就明吧了。
  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 ,参数是文件的路径。 
好了,来一步步调试看源码。
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));
            }
        }
 
 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 ,这个图片被当成文件夹了,在这里创建了一个文件夹,而不是图片。 
解决方法
    @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的源码中不会根据你给的路径自动创建图片的上一层路径。 
写这个就是要说明,遇到问题的时候要多读源码,一步步的调试。
当你一步步接近真相的时候,你会感觉到很有成就感,就像爬过一座山头一样。
 多读源码 ,不要只是拷贝,很多场景拷贝的时候细节问题不一样的。