17

I have simple SpringBoot app file uploading functionality where max file upload file size is 2 MB.

I have configured multipart.max-file-size=2MB it is working fine. But when I try to upload files with larger than 2 MB size I want to handle that error and show the error message.

For that I have my controller implements HandlerExceptionResolver with resolveException() implementation as follows:

public ModelAndView resolveException(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception exception)
    {        
        Map<String, Object> model = new HashMap<String, Object>();
        if (exception instanceof MaxUploadSizeExceededException)
        {
            model.put("msg", exception.getMessage());
        } else
        {
            model.put("msg", "Unexpected error: " + exception.getMessage());
        }

        return new ModelAndView("homepage", model);
    }

The problem is the Exception Im getting is MultipartException instead of MaxUploadSizeExceededException.

The stacktrace is: Could not parse multipart servlet request; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.FileUploadBase$FileSizeLimitExceededException: The field myFile exceeds its maximum permitted size of 2097152 bytes.

In the case of file size exceeds why not I am getting MaxUploadSizeExceededException? I am getting its parent Exception MultipartException which can be occured for many other reasons in addition to File Size exceeds.

Any thoughts on this?

K. Siva Prasad Reddy
  • 11,786
  • 12
  • 68
  • 95

3 Answers3

7

I faced the same issue, it looks like only the MultipartResolver of Commons File Upload implementation throws MaxUploadSizeExceededException but not the MultipartResolver Servlet 3.0 implementation.

Here's what I have done so far. The key here was to allow the file to be check on the controller, then you can validate size and set an error.

  1. set multipart properties below multipart: max-file-size: -1 max-request-size: -1

  2. set Tomcat 8 (maxSwallowSize="-1")

  3. on controller, add logic to check size

    if(fileAttachment.getSize() > 10485760 ) { throw new MaxUploadSizeExceededException(fileAttachment.getSize()); }

Ojonugwa Jude Ochalifu
  • 26,627
  • 26
  • 120
  • 132
aalmero
  • 345
  • 2
  • 18
3

It's not great, but my quick and dirty solution was to check to see if the MultipartException message String contained the text SizeLimitExceededException and extract the maximum file size information from that message.

In my case, the exception being thrown on tomcat 8.0.x was org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (177351) exceeds the configured maximum (2048)

Keep in mind, as aalmero pointed out, if you use the CommonsMultipartResolver rather than the StandardServletMultipartResolver, a MaxUploadSizeExceededException would be thrown which is much nicer to handle. The following code handles a MultipartException thrown by either multipart resolver strategy:

@ControllerAdvice
public class MultipartExceptionExceptionHandler {
  @ExceptionHandler(MultipartException.class)
  public String handleMultipartException(MultipartException ex, RedirectAttributes ra) {
    String maxFileSize = getMaxUploadFileSize(ex);
    if (maxFileSize != null) {
      ra.addFlashAttribute("errors", "Uploaded file is too large.  File size cannot exceed " + maxFileSize + ".");
    }
    else {
      ra.addFlashAttribute("errors", ex.getMessage());
    }
    return "redirect:/";
  }

  private String getMaxUploadFileSize(MultipartException ex) {
    if (ex instanceof MaxUploadSizeExceededException) {
      return asReadableFileSize(((MaxUploadSizeExceededException)ex).getMaxUploadSize());
    }
    String msg = ex.getMessage();
    if (msg.contains("SizeLimitExceededException")) {
      String maxFileSize = msg.substring(msg.indexOf("maximum")).replaceAll("\\D+", "");
      if (StringUtils.isNumeric(maxFileSize)) {
        return asReadableFileSize(Long.valueOf(maxFileSize));
      }
    }

    return null;
  }

  // http://stackoverflow.com/a/5599842/225217
  private static String asReadableFileSize(long size) {
    if(size <= 0) return "0";
    final String[] units = new String[] { "B", "kB", "MB", "GB", "TB" };
    int digitGroups = (int) (Math.log10(size)/Math.log10(1024));
    return new DecimalFormat("#,##0.#").format(size/Math.pow(1024, digitGroups)) + " " + units[digitGroups];
  }
}
Brice Roncace
  • 10,110
  • 9
  • 60
  • 69
1

following values in application.properties worked for me. It seems it make acceptable file size unlimited

multipart.maxFileSize=-1

multipart.maxRequestSize=-1

Now you need to add logic at your controller side.

@PostMapping("/upload")
    public String handleFileUpload(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) {

        long size = file.getSize();

        if(size > 10000000)
        {
            redirectAttributes.addFlashAttribute("message",
                    "You file " + file.getOriginalFilename() + "! has not been successfully uploaded. Requires less than 10 MB size.");
            return "redirect:/upload";
        }
        }
AndroidHacker
  • 3,596
  • 1
  • 25
  • 45
Amol
  • 835
  • 6
  • 5
  • 1
    This doesn't seem to answer the question as written which is about how to catch the exception if a large file is uploaded and not about how to upload an arbitrary sized file. – Robert Longson May 21 '16 at 07:24