11

I am using spring boot for uploading files. The files sizes are usually about 2GB and we cannot use the default spring boot StandardServletMultipartResolver or CommonsMultipartResolver since the server have limited resource (disk space) or memory for buffering. So we would like to get the file inputsteam and store the file directly to the cloud storage.

I know spring boot has the multipart.enabled property so I can set it to false to skip the spring MultipartResolver. But this disables multipart globally. Does any one know if there is a way to disable multipart by controller/method?

M. Deinum
  • 115,695
  • 22
  • 220
  • 224
Dave Chen
  • 121
  • 1
  • 1
  • 5
  • 1
    You either enable it or disable it you cannot have both. Unless you define 2 separate `DispatcherServlet`s one with multipart and one without. The easiest is to just disable it and handle file uploads yourself. You can probably create a helper class to make it easier. – M. Deinum Jul 01 '16 at 06:24

4 Answers4

6

If you enable resolve-lazily, the result is exactly what I think you're asking for.

spring.servlet.multipart.enabled = true
spring.servlet.multipart.resolve-lazily = true

Now you can write controllers with either form of signature.

Pre-parsing by the built-in multipart resolver...

@PostMapping("/upload1")
public ResponseEntity<Void> postUpload1(
    @RequestParam("metadata") MultipartFile metadata,
    @RequestParam("payload") MultipartFile payload)

Or post-parsing (which you can parse yourself)...

@PostMapping(path = "/upload2", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Void> postUpload2(HttpServletRequest rawRequest)
Brent Bradburn
  • 51,587
  • 17
  • 154
  • 173
  • 1
    spring.servlet.multipart.enabled = true, postUpload2 not work – free斩 Dec 18 '18 at 07:18
  • Although this proposed answer looks good, I had no success in running MultiPart and non-Multipart based Controllers at the same time, because there is only one DispatcherServlet. and the config is mutually exclusive. – yglodt Apr 24 '20 at 19:32
1

It's actually possible to conditionally disable multipary with a custom MultipartResolver, but you should do it at request level.

With multipart enabled, the files are stored locally on the server, and with multipart off, your controller has to do the parsing manually.

Since I read so much conflicting information on this topic, I decided to go into the details here https://youtu.be/OpJ0jKRBa1g where I illustrate how to have both strategies coexist at the same time.

Gzorg
  • 809
  • 4
  • 10
  • 25
1

This thread is quite old yet, but here is a working solution (Spring Boot 2):

application.properties:

spring.servlet.multipart.enabled=false

config:

@Bean
public MultipartResolver customMultipartResolver() {
  final CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
  multipartResolver.setResolveLazily(true);
  return multipartResolver;
}

Controller (manual handling):

  @PostMapping(consumes = { "multipart/form-data" })
  public ResponseEntity<> manualHandling(
      HttpServletRequest request) throws FileUploadException, IOException {

    final FileItemIterator iterStream = new ServletFileUpload().getItemIterator(request);

    ...
  }

Controller (standard multipart):

  @PostMapping(value = "file", consumes = { "multipart/form-data" })
  public ResponseEntity<> multipartHandling(MultipartHttpServletRequest request) throws IOException {

    final Map<String, MultipartFile> files = request.getMultiFileMap().toSingleValueMap();

    Iterator<MultipartFile> iter =files.values().iterator();

    ...
  }
Selindek
  • 3,269
  • 1
  • 18
  • 25
-1

This shows how it can be done :

springboot-large-streaming-file-upload-using-apache-commons-fileupload

Look at the answer of balajeerc

Community
  • 1
  • 1
  • 3
    The parent comment mentions they're aware of this approach, but are looking for something that doesn't disable multipart globally. – mrPjer Apr 23 '18 at 13:10