7

I am try to upload the file using my spring boot API. The function is working fine when I am using small file (less than 1 MB), but when I upload large file it gives me an exception. I am using embedded Tomcat server.

Maximum upload size exceeded; 
nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException: The field file exceeds its maximum permitted size of 1048576 bytes.

I have tried the following code in my files but every time I am getting the error

1. application.property

server.tomcat.max-swallow-size=100MB
server.tomcat.max-http-post-size=100MB
spring.servlet.multipart.enabled=true 
spring.servlet.multipart.fileSizeThreshold=100MB
spring.servlet.multipart.max-file-size=100MB
spring.servlet.multipart.max-request-size=100MB

I have also tried

spring.servlet.multipart.maxFileSize=100MB
spring.servlet.multipart.maxRequestSize=100MB

2. The belove is my file uploading code

public RestDTO uploadFile(MultipartFile file, String subPath) {

    if (file.isEmpty()) {
        return new RestFailure("Failed to store empty file");
    }

    try {
        String fileName = new Date().getTime() + "_" + file.getOriginalFilename();
        String filePath = uploadPath + subPath + fileName;
        if (Objects.equals(file.getOriginalFilename(), "blob")) {
            filePath += ".png";
            fileName += ".png";
        }
        File uploadDir = new File(uploadPath + subPath);
        if (!uploadDir.exists()) {
            uploadDir.mkdirs();
        }
        FileOutputStream output = new FileOutputStream(filePath);
        output.write(file.getBytes());
        LOGGER.info("File path : " + filePath);

        MediaInfoDTO mediaInfoDTO = getThumbnailFromVideo(subPath, fileName);

        String convertedFileName = convertVideoToMP4(subPath, fileName);

        System.out.println("---------------->" + convertedFileName);

        return new RestData<>(new MediaDetailDTO(mediaInfoDTO.getMediaPath(), convertedFileName,
                mediaInfoDTO.getMediaType(), mediaInfoDTO.getMediaCodec(), mediaInfoDTO.getWidth(),
                mediaInfoDTO.getHeight(), mediaInfoDTO.getDuration()));
    } catch (IOException e) {
        LOGGER.info("Can't upload file: " + e.getMessage());
        return new RestFailure("Failed to store empty file");
    }
}

but every time I got the same exception.

Rishal
  • 1,480
  • 1
  • 11
  • 19
M Swapnil
  • 2,361
  • 3
  • 18
  • 33

2 Answers2

8

Apart from comment might I suggest creating a @Bean for Factory MultipartConfigurationElement This basically should override other restrictions if you have any from TomCat side.

@Bean
public MultipartConfigElement multipartConfigElement() {
    MultipartConfigFactory factory = new MultipartConfigFactory();
    factory.setMaxFileSize(DataSize.ofBytes(100000000L));
    factory.setMaxRequestSize(DataSize.ofBytes(100000000L));
    return factory.createMultipartConfig();
}

Here DataSize is of type org.springframework.util.unit.DataSize

Reference https://github.com/spring-projects/spring-boot/issues/11284

Another issue I suspect could be from TomCat maxSwallowSize see Baeldung's point #5 if above does not work. https://www.baeldung.com/spring-maxuploadsizeexceeded

Milan Desai
  • 1,228
  • 8
  • 23
  • 6
    There's no need to do this. Spring Boot will auto-configure a `MultipartConfigElement` using the `spring.servlet.multipart.*` properties. – Andy Wilkinson Mar 06 '20 at 16:09
2

After reviewing many examples and after several tests with no results. I have managed to solve the problem with the following configuration:

  1. Add to pom the follows dependencies:

    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.4</version>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.6</version>
    </dependency>
    
  2. Remove from yml:

    sprint:
      servlet:  
        multipart:
          enabled: true
          file-size-threshold: 2KB
          max-file-size: 10MB
          max-request-size: 10MB
    
  3. Add to yml:

    server:
      tomcat:
        max-swallow-size: -1
        max-http-form-post-size: -1
    
  4. And last but not least:

    @Bean
    public MultipartResolver multipartResolver() {
        CommonsMultipartResolver resolver
           = new CommonsMultipartResolver();
        resolver.setDefaultEncoding(StandardCharsets.UTF_8.displayName());
        resolver.setMaxUploadSize(52428800L); //50MB
        resolver.setMaxUploadSizePerFile(52428800L); //50MB
    
        return resolver;
    }
    
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public ResponseEntity<Object> handleFileUploadError(MaxUploadSizeExceededException ex) {
        return ResponseEntity.status(EXPECTATION_FAILED).body(
            CustomResponse.builder()
                .status(Status.ERROR)
                .message(ex.getMessage())
                .build());
    }
    
    // Where CustomResponse class is in my case:
    /**
      * The UploadResponse class
      * <p>
      * Contain the response body
      */
    @Getter
    @Builder(toBuilder = true)
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public class CustomResponse {
        /**
          * The status
          */
        private final Status status;
        /**
          * The message
          */
        private final String message;
        /**
          * The errors
          */
        private final Set<String> errors;
    }
    
  • 2
    The custom exception handler is nice, otherwise you get an ugly `500 Internal Server` error courtesy of Sprint's default exception handler. However, to increase the file size limit, all I had to do was add `spring.servlet.multipart.max-file-size=10485760` to my `application.properties`. No need to create a custom `MultipartResolver` bean. – Frans Nov 16 '21 at 09:55