How does one specify a temp directory for file uploads in Spring Boot?
Asked Answered
C

4

29

I'm using Spring Boot and need to let users upload files for processing. Right now, the file uploads to /home/username/git/myproject which is not great.

How do I make Spring put those file uploads into a temporary directory that will be periodically purged by application restart (or some other means)?

Here's what I've tried... but it doesn't work. File still saves to my working directory.

public class Application implements CommandLineRunner {

    /*
     * This doesn't seem to work.
     */
    @Bean
    MultipartConfigElement multipartConfigElement() {
        MultipartConfigFactory factory = new MultipartConfigFactory();
        factory.setMaxFileSize("128KB");
        factory.setMaxRequestSize("128KB");
        factory.setLocation(System.getProperty("java.io.tmpdir"));
        return factory.createMultipartConfig();
    }

/* other stuff, main(), etc */

}

PS I'm just running my app by executing Application and it's using embedded Tomcat.

UPDATE:

Ok I've got it sorted out. I was converting the incoming MultipartFile to a normal File like so:

private File convertMultipartFileToFile(MultipartFile file) throws IOException
    {    
        File convFile = new File(file.getOriginalFilename());
        convFile.createNewFile(); 
        FileOutputStream fos = new FileOutputStream(convFile); 
        fos.write(file.getBytes());
        fos.close(); 
        return convFile;
    }

Instead, I should have been creating a new File in the designated temporary directory like this:

private File convertMultipartFileToFile(MultipartFile file) throws IOException
    {    
        File convFile = File.createTempFile("temp", ".xlsx"); // choose your own extension I guess? Filename accessible with convFile.getAbsolutePath()
        FileOutputStream fos = new FileOutputStream(convFile); 
        fos.write(file.getBytes());
        fos.close(); 
        return convFile;
    }

Now you may be asking, "Well what about the 'multipart.location' setting of the application.properties file?" That setting, obvious in retrospect, controls only where the ephemeral multipart file goes. If you watch that directory with a script, you'll see that a 'upload_.tmp' file appears briefly and then disappears. 'multipart.location' has nothing to do with any persistent File objects you might create.

(Note, you may be able to use the MultipartBean snippet from above instead of application.properties, but I didn't try it and why would you want to?)

To change the value of your true temp directory, you can use "-Djava.io.tmp=/path/to/dir" VM argument to specify whatever you want before running your Spring Boot application.

Cataplexy answered 28/4, 2015 at 15:33 Comment(0)
G
25

in springboot 1.4.1.RELEASE

spring.http.multipart.max-file-size=10MB
spring.http.multipart.max-request-size=10MB
spring.http.multipart.enabled=true
spring.http.multipart.location= ..

will be ok.

Gytle answered 13/1, 2017 at 3:33 Comment(1)
As per current (2.7.2) Spring docs, the parameter is spring.servlet.multipart.enabledWithindoors
C
23

Since you are using Spring Boot it's easier to use the MultipartProperties in your application.properties file.

From documentation properties example:

# MULTIPART (MultipartProperties)
multipart.enabled=true
multipart.file-size-threshold=0 # Threshold after which files will be written to disk.
multipart.location= # Intermediate location of uploaded files.
multipart.max-file-size=1Mb # Max file size.
multipart.max-request-size=10Mb # Max request size.

Also you could read a detailed description from the MultipartProperties.

In order to configure to your system tmpdir, you could set:

multipart.location=${java.io.tmpdir}
Crashing answered 28/4, 2015 at 17:2 Comment(3)
multipart.enabled seems to be invalid. I think I've got the larger question solved though and will post above.Cataplexy
For comments on this thread + Spring documentation, there are three flavors for configuration: "spring.http.multipart.location", "multipart.location" and "spring.servlet.multipart.location". Why and how do they differ?Reg
@Reg https://mcmap.net/q/501810/-how-exactly-spring-http-multipart-enabled-is-different-from-spring-servlet-multipart-enabled/525036. For the one without spring prefix, it seems to be from Spring Boot 1.1 as linked in this answer. It was already changed to spring.http.multipart in 1.5 – I didn't check intermediate versions.Vaporific
E
4

If somebody is still looking for programmatic configuration:

@Configuration
public class ServletConfig {

  @Bean
  public ServletRegistrationBean dispatcherRegistration(DispatcherServlet dispatcherServlet) {
    final ServletRegistrationBean registration = new ServletRegistrationBean(dispatcherServlet);
    final String location = System.getProperty("java.io.tmpdir");
    final long maxFileSize = 128*1024;
    final long maxRequestSize = 128*1024;
    final MultipartConfigElement multipartConfig  = new MultipartConfigElement(location, maxFileSize, maxRequestSize, 0);
    registration.setMultipartConfig(multipartConfig);
    return registration;
  }

}
Enwreathe answered 9/8, 2017 at 21:59 Comment(0)
V
3

On windows versus linux the temp dir could have a trailing slash. Multipart held tmp files that caused new file names. creating my own tmp dir solved the issue.

    String tempDir = System.getProperty("java.io.tmpdir");
    if(  !tempDir.endsWith("/") && !tempDir.endsWith( "\\") ) {
        tempDir = tempDir+"/";
Vigilante answered 11/3, 2019 at 14:21 Comment(1)
Since Java 7 you can avoid this by using java.nio.file.Path e.g.: Path.of(System.getProperty("java.io.tmpdir"))Leontineleontyne

© 2022 - 2024 — McMap. All rights reserved.