Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SpringBoot When file upload size limit exceeds getting MultipartException instead of MaxUploadSizeExceededException

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?

like image 391
K. Siva Prasad Reddy Avatar asked Feb 13 '16 12:02

K. Siva Prasad Reddy


2 Answers

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()); }

like image 96
aalmero Avatar answered Oct 20 '22 18:10

aalmero


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];
  }
}
like image 43
Brice Roncace Avatar answered Oct 20 '22 17:10

Brice Roncace