Solve the problem of MultipartFile. transferTo of dest reporting FileNotFoundExcep

  • 2021-10-15 10:39:46
  • OfStack

Spring Upload file Error FileNotFoundException

Environment:

Springboot 2.0.4 JDK8 Embedded Apache Tomcat/8. 5.32

Form, type=file of enctype and input is enough, and the example is uploaded by single file


<form enctype="multipart/form-data" method="POST"
 action="/file/fileUpload">
  Picture <input type="file" name="file" />
 <input type="submit" value=" Upload " />
</form>

@Controller
@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(path + "/" + fileName);
		if (!dest.getParentFile().exists()) { 
			dest.getParentFile().mkdirs();
		}
		try {
			file.transferTo(dest); //  Save a file 
			return "true";
		} catch (Exception e) {
			e.printStackTrace();
			return "false";
		}
	}
}

Running in the save file file. transferTo (dest) reports an error

Problem

dest is a relative path pointing to upload/doc20170816162034_001. jpg

When the file. transferTo method is called, it is judged that if it is a relative path, the temp directory is used as the parent directory

Therefore, the actual save location is C:\ Users\ xxxx\ AppData\ Temp\ tomcat.372873030384525225.8080\ work\ Tomcat\ localhost\ ROOT\ upload\ doc20170816162034_001.jpg

1, the location is wrong, and 2, there is no parent directory, so the above error occurs.

Solution

transferTo incoming parameters are defined as absolute paths


@Controller
@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); //  Save a file 
			return "true";
		} catch (Exception e) {
			e.printStackTrace();
			return "false";
		}
	}
}

Alternatively, file. getBytes () gets the byte array and OutputStream. write (byte [] bytes) writes itself to the output stream.

Supplementary method

Adding configuration item in application. properties


spring.servlet.multipart.location= # Intermediate location of uploaded files.

Access to uploaded files

1. Add a custom ResourceHandler to publish the directory


//  Write 1 A Java Config 
@Configuration
public class webMvcConfig implements org.springframework.web.servlet.config.annotation.WebMvcConfigurer{
	//  Defined in application.properties
	@Value("${file.upload.path}")
	private String path = "upload/";
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		String p = new File(path).getAbsolutePath() + File.separator;// Gets the absolute path in the server 
		System.out.println("Mapping /upload/** from " + p);
		registry.addResourceHandler("/upload/**") //  External access address 
			.addResourceLocations("file:" + p)// springboot Need to increase file Protocol prefix 
			.setCacheControl(CacheControl.maxAge(30, TimeUnit.MINUTES));//  Setting Browser Cache 30 Minutes 
	}
}

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

Actual storage directory

D:/upload/2019/03081625111.jpg

Access address (assuming the application is published at http://www.a.com/)

http://www.a.com/upload/2019/03081625111.jpg

2. Add an RequestMapping to Controller and output the file to the output stream


@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){
		//  Usually uploaded files will have 1 Data tables are stored, and the returned id It's a record id
		UploadFile file = conversionService.convert(id, UploadFile.class);//  This step can also be written in the request parameters 
		if(file==null){
			throw new RuntimeException(" No files ");
		}
		
		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;
	}
}

MultipartFile. transferTo (dest) File not found

Today, using transferTo this method to upload files, we found some problems in 1 path and found the problem in 1 record

Front-end upload web pages, using a single file upload method


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
    <form enctype="multipart/form-data" method="post" action="/upload">
         Documents: <input type="file" name="head_img">
         Name: <input type="text" name="name">
        <input type="submit" value=" Upload ">
    </form>
</body>
</html>

Background web page


@Controller
@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(path + "/" + fileName);
        if (!dest.getParentFile().exists()) { 
            dest.getParentFile().mkdirs();
        }
        try {
            file.transferTo(dest); //  Save a file 
            return "true";
        } catch (Exception e) {
            e.printStackTrace();
            return "false";
        }
    }
}

There are some problems with this

The path is wrong

dest is a relative path pointing to upload/doc20170816162034_001. jpg

When the file. transferTo method is called, it is judged that if it is a relative path, the temp directory is used as the parent directory

Therefore, the actual save location is C:\ Users\ xxxx\ AppData\ Local\ Temp\ tomcat.3728730303845252255.8080\ work\ Tomcat\ localhost\ ROOT\ upload\ doc20170816162034_001.jpg

So it is changed to:


@Controller
@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); //  Save a file 
            return "true";
        } catch (Exception e) {
            e.printStackTrace();
            return "false";
        }
    }
}

Related articles: