文件上傳時,MultipartFile.transferTo() 方法報 FileNotFoundException


Spring Upload File 報錯FileNotFoundException

環境: Springboot 2.0.4 JDK1.8 內嵌 Apache Tomcat/8.5.32

1、前端代碼

前端上傳網頁表單,enctype 和 input 的type=file 即可,使用單文件上傳舉例:

<form enctype="multipart/form-data" method="POST"
    action="/file/fileUpload">
    圖片<input type="file" name="file" />
    <input type="submit" value="上傳" />
</form>

2、后端代碼

@RestController
@RequestMapping("/file")
public class UploadFileController {
    @Value("${file.upload.path}")
    private String path = "upload/";

    @RequestMapping(value = "fileUpload", method = RequestMethod.POST)
    @ResponseBody
    public String fileUpload(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return "false";
        }
        String fileName = file.getOriginalFilename();
        File saveFile = new File(path + "/" + fileName);
        if (!saveFile.getParentFile().exists()) { 
            saveFile.getParentFile().mkdirs();
        }
        try {
            file.transferTo(saveFile); // 保存文件
            return "true";
        } catch (Exception e) {
            e.printStackTrace();
            return "false";
        }
    }
}

3、問題分析與解決

按照上面配置運行時,在保存文件 file.transferTo(saveFile) 報錯

3.1 問題原因分析:

saveFile是相對路徑,指向 upload/doc20170816162034_001.jpg
file.transferTo 方法調用時,判斷如果是相對路徑,則使用temp目錄,為父目錄
因此,實際保存位置為 C:\Users\xxxx\AppData\Local\Temp\tomcat.372873030384525225.8080\work\Tomcat\localhost\ROOT\upload\doc20170816162034_001.jpg

一則,位置不對,二則沒有父目錄存在,因此產生上述錯誤。

3.2 問題解決

transferTo 傳入參數 定義為絕對路徑
@RestController
@RequestMapping("/file")
public class UploadFileController {
    @Value("${file.upload.path}")
    private String path = "upload/";

    @RequestMapping(value = "fileUpload", method = RequestMethod.POST)
    @ResponseBody
    public String fileUpload(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return "false";
        }
        String fileName = file.getOriginalFilename();
        File dest = new File(new File(path).getAbsolutePath()+ "/" + fileName);
        if (!dest.getParentFile().exists()) { 
            dest.getParentFile().mkdirs();
        }
        try {
            file.transferTo(dest); // 保存文件
            return "true";
        } catch (Exception e) {
            e.printStackTrace();
            return "false";
        }
    }
}
也可以 file.getBytes() 獲得字節數組,OutputStream.write(byte[] bytes)自己寫到輸出流中。

4、補充方法

application.properties 中增加配置項
spring.servlet.multipart.location= # Intermediate location of uploaded files.

關於上傳文件的訪問

增加一個自定義的ResourceHandler把目錄公布出去

// 寫一個Java Config 
@Configuration
public class webMvcConfig implements org.springframework.web.servlet.config.annotation.WebMvcConfigurer{
    // 定義在application.properties
    @Value("${file.upload.path}")
    private String path = "upload/";
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        String p = new File(path).getAbsolutePath() + File.separator;//取得在服務器中的絕對路徑
        System.out.println("Mapping /upload/** from " + p);
        registry.addResourceHandler("/upload/**") // 外部訪問地址
            .addResourceLocations("file:" + p)// springboot需要增加file協議前綴
            .setCacheControl(CacheControl.maxAge(30, TimeUnit.MINUTES));// 設置瀏覽器緩存30分鍾
    }
}

application.properties 中 file.upload.path=upload/

實際存儲目錄
D:/upload/2019/03081625111.jpg

訪問地址(假設應用發布在http://www.a.com/)
http://www.a.com/upload/2019/03081625111.jpg

在Controller中增加一個RequestMapping,把文件輸出到輸出流中

@RestController
@RequestMapping("/file")
public class UploadFileController {
    @Autowired
    protected HttpServletRequest request;
    @Autowired
    protected HttpServletResponse response;
    @Autowired
    protected ConversionService conversionService;

    @Value("${file.upload.path}")
    private String path = "upload/";    

    @RequestMapping(value="/view", method = RequestMethod.GET)
    public Object view(@RequestParam("id") Integer id){
        // 通常上傳的文件會有一個數據表來存儲,這里返回的id是記錄id
        UploadFile file = conversionService.convert(id, UploadFile.class);// 這步也可以寫在請求參數中
        if(file==null){
            throw new RuntimeException("沒有文件");
        }
        
        File source= new File(new File(path).getAbsolutePath()+ "/" + file.getPath());
        response.setContentType(contentType);

        try {
            FileCopyUtils.copy(new FileInputStream(source), response.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM