How to handle MaxUploadSizeExceededException
Asked Answered
B

5

58

MaxUploadSizeExceededException exception appears when I upload a file whose size exceeds the maximum allowed. I want to show an error message when this exception appears (like a validation error message). How can I handle this exception to do something like this in Spring 3?

Thanks.

Bevash answered 22/4, 2010 at 10:32 Comment(3)
By catching the exception in Java and showing an error page?Eldred
@Eldred I'd prefer to go back to the form page and show there the error, but the exception is thrown before it reaches the controller where the model attribute is populatedBevash
Have a look at the HandlerExceptionResolver: static.springsource.org/spring/docs/3.0.x/…Retinitis
H
34

I finally figured out a solution that works using a HandlerExceptionResolver.

Add multipart resolver to your Spring config:

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">    
   <!--  the maximum size of an uploaded file in bytes -->
   <!-- <property name="maxUploadSize" value="10000000"/> -->
   <property name="maxUploadSize" value="1000"/>
</bean>   

Model - UploadedFile.java:

package com.mypkg.models;

import org.springframework.web.multipart.commons.CommonsMultipartFile;

public class UploadedFile
{
    private String title;

    private CommonsMultipartFile fileData;

    public String getTitle()
    {
        return title;
    }

    public void setTitle(String title)
    {
        this.title = title;
    }

    public CommonsMultipartFile getFileData()
    {
        return fileData;
    }

    public void setFileData(CommonsMultipartFile fileData)
    {
        this.fileData = fileData;
    }

}

View - /upload.jsp:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
    <head>
        <title>Test File Upload</title>
    </head>
    <body>
        <h1>Select a file to upload</h1>
        <c:if test="${not empty errors}">
            <h2 style="color:red;">${errors}.</h2>
        </c:if>
        <form:form modelAttribute="uploadedFile" method="post" enctype="multipart/form-data" name="uploadedFileform" id="uploadedFileform">
            <table width="600" border="0" align="left" cellpadding="0" cellspacing="0" id="pdf_upload_form">
                <tr>
                    <td width="180"><label class="title">Title:</label></td>
                    <td width="420"><form:input id="title" path="title" cssClass="areaInput" size="30" maxlength="128"/></td>
                </tr>
                <tr>
                    <td width="180"><label class="title">File:</label></td>
                    <td width="420"><form:input id="fileData" path="fileData" type="file" /></td>
                 </tr>
                 <tr>
                    <td width="180"></td>
                    <td width="420"><input type="submit" value="Upload File" /></td>
                 </tr>
            </table>
        </form:form>
    </body>
</html>

Controller - FileUploadController.java: package com.mypkg.controllers;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import com.mypkg.models.UploadedFile;

@Controller
public class FileUploadController  implements HandlerExceptionResolver
{
    @RequestMapping(value = "/upload", method = RequestMethod.GET)
    public String getUploadForm(Model model)
    {
        model.addAttribute("uploadedFile", new UploadedFile());
        return "/upload";
    }

    @RequestMapping(value = "/upload", method = RequestMethod.POST)
    public String create(UploadedFile uploadedFile, BindingResult result)
    {
        // Do something with the file
        System.out.println("#########  File Uploaded with Title: " + uploadedFile.getTitle());
        System.out.println("#########  Creating local file: /var/test-file-upload/" + uploadedFile.getFileData().getOriginalFilename());

        try
        {

            InputStream in = uploadedFile.getFileData().getInputStream();
            FileOutputStream f = new FileOutputStream(
                    "/var/test-file-upload/" + uploadedFile.getFileData().getOriginalFilename());
            int ch = 0;
            while ((ch = in.read()) != -1)
            {
                f.write(ch);
            }
            f.flush();
            f.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }

        return "redirect:/";
    }

    /*** Trap Exceptions during the upload and show errors back in view form ***/
    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("errors", exception.getMessage());
        } else
        {
            model.put("errors", "Unexpected error: " + exception.getMessage());
        }
        model.put("uploadedFile", new UploadedFile());
        return new ModelAndView("/upload", model);
    }

}

========================================================================
Hexangular answered 12/7, 2010 at 16:42 Comment(9)
I am working on this issue as well. However, I find that the request is not filled with any other parameters, even though they are in my form.Lurlene
If all controllers implement this HandlerExceptionResolver, then they will all be called when exceptions occurs?Alcott
I have tried to put the same approach into practice but nothing worked. Also tried the same approach as mentioned on this post. The method resolveException() is never invoked even though the exception occurs. I want to show a user-friendly error message on the same page but I'm getting the full stack trace on the web page. Am I missing something with Spring 3.2.0?Busch
How can I effectively handle MaxUploadSizeExceededException in an ajax based context ? I am uploading file by ajax request, so when file uploading failed I want to show a javascript alert in the browser, instead of redirecting to some error page. How can I do this ?Lemmon
@faizi see my answer,code format is so bad in comments,so i write a new answerPhifer
This does not work for some people. Is there some sort of discrepancy between Spring versions?Loris
This method will wrap every exception ... even exceptions in other pages/controllersViipuri
I cant edit my previous answer but you should return null for default processing of other exceptionsViipuri
@JohnathanAu Not really. You require the Apache Commons FileUpload dependency to get this CommonsMultipartResolver to work, due to the fact that Spring Boot uses the default Servlet 3.0 support for file uploads, NOT commons-fileupload. Also, if you use the Apache Commons, the spring.http.multipart.* properties will no longer work.Squash
S
81

This is an old question so I'm adding it for the future people (including future me) who are struggling to get this working with Spring Boot 2.

At first you need to configure the spring application (in properties file):

spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB

If you're using embedded Tomcat (and most likely you are, as it comes as standard) it's also important to configure Tomcat not to cancel the request with large body

server.tomcat.max-swallow-size=-1

or at least set it to relatively big size

server.tomcat.max-swallow-size=100MB

If you will not set maxSwallowSize for Tomcat, you might waste lots of hours debugging why the error is handled but browser gets no response - that's because without this configuration Tomcat will cancel the request, and even though you'll see in the logs that application is handling the error, the browser already received cancellation of request from Tomcat and isn't listening for the response anymore.

And to handle the MaxUploadSizeExceededException you can add ControllerAdvice with ExceptionHandler.

Here's a quick example in Kotlin that simply sets a flash attribute with an error and redirects to some page:

@ControllerAdvice
class FileSizeExceptionAdvice {
    @ExceptionHandler(MaxUploadSizeExceededException::class)
    fun handleFileSizeException(
        e: MaxUploadSizeExceededException, 
        redirectAttributes: RedirectAttributes
    ): String {
        redirectAttributes.addFlashAttribute("error", "File is too big")
        return "redirect:/"
    }
}

NOTE: if you want to handle MaxUploadSizeExceededException with ExceptionHandler directly in your controller class, you should configure following property:

spring.servlet.multipart.resolve-lazily=true

otherwise that exception will be triggered before the request is mapped to controller.

Selective answered 28/1, 2019 at 15:35 Comment(6)
Thank you so much. This is exactly what i was wasting my morning on! Straight to the point.Bargeman
The property spring.servlet.multipart.resolve-lazily really helped. Thanks!Irate
You deserve a gold medal and to have this marked as the right answer.Confuse
@Selective I tried your approach and using resolve-lazily..., but it still doesn't work. Could you please be more specific how I can handle the exception in my controller class?Bultman
Thank you, I love Kotlin and your solution is so smart many thanks manHalsy
I run into this : [ERR] Resource exhaustion event: the JVM was unable to allocate memory from the heap. So, I increased jvm memory to address it.Wamble
H
34

I finally figured out a solution that works using a HandlerExceptionResolver.

Add multipart resolver to your Spring config:

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">    
   <!--  the maximum size of an uploaded file in bytes -->
   <!-- <property name="maxUploadSize" value="10000000"/> -->
   <property name="maxUploadSize" value="1000"/>
</bean>   

Model - UploadedFile.java:

package com.mypkg.models;

import org.springframework.web.multipart.commons.CommonsMultipartFile;

public class UploadedFile
{
    private String title;

    private CommonsMultipartFile fileData;

    public String getTitle()
    {
        return title;
    }

    public void setTitle(String title)
    {
        this.title = title;
    }

    public CommonsMultipartFile getFileData()
    {
        return fileData;
    }

    public void setFileData(CommonsMultipartFile fileData)
    {
        this.fileData = fileData;
    }

}

View - /upload.jsp:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
    <head>
        <title>Test File Upload</title>
    </head>
    <body>
        <h1>Select a file to upload</h1>
        <c:if test="${not empty errors}">
            <h2 style="color:red;">${errors}.</h2>
        </c:if>
        <form:form modelAttribute="uploadedFile" method="post" enctype="multipart/form-data" name="uploadedFileform" id="uploadedFileform">
            <table width="600" border="0" align="left" cellpadding="0" cellspacing="0" id="pdf_upload_form">
                <tr>
                    <td width="180"><label class="title">Title:</label></td>
                    <td width="420"><form:input id="title" path="title" cssClass="areaInput" size="30" maxlength="128"/></td>
                </tr>
                <tr>
                    <td width="180"><label class="title">File:</label></td>
                    <td width="420"><form:input id="fileData" path="fileData" type="file" /></td>
                 </tr>
                 <tr>
                    <td width="180"></td>
                    <td width="420"><input type="submit" value="Upload File" /></td>
                 </tr>
            </table>
        </form:form>
    </body>
</html>

Controller - FileUploadController.java: package com.mypkg.controllers;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import com.mypkg.models.UploadedFile;

@Controller
public class FileUploadController  implements HandlerExceptionResolver
{
    @RequestMapping(value = "/upload", method = RequestMethod.GET)
    public String getUploadForm(Model model)
    {
        model.addAttribute("uploadedFile", new UploadedFile());
        return "/upload";
    }

    @RequestMapping(value = "/upload", method = RequestMethod.POST)
    public String create(UploadedFile uploadedFile, BindingResult result)
    {
        // Do something with the file
        System.out.println("#########  File Uploaded with Title: " + uploadedFile.getTitle());
        System.out.println("#########  Creating local file: /var/test-file-upload/" + uploadedFile.getFileData().getOriginalFilename());

        try
        {

            InputStream in = uploadedFile.getFileData().getInputStream();
            FileOutputStream f = new FileOutputStream(
                    "/var/test-file-upload/" + uploadedFile.getFileData().getOriginalFilename());
            int ch = 0;
            while ((ch = in.read()) != -1)
            {
                f.write(ch);
            }
            f.flush();
            f.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }

        return "redirect:/";
    }

    /*** Trap Exceptions during the upload and show errors back in view form ***/
    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("errors", exception.getMessage());
        } else
        {
            model.put("errors", "Unexpected error: " + exception.getMessage());
        }
        model.put("uploadedFile", new UploadedFile());
        return new ModelAndView("/upload", model);
    }

}

========================================================================
Hexangular answered 12/7, 2010 at 16:42 Comment(9)
I am working on this issue as well. However, I find that the request is not filled with any other parameters, even though they are in my form.Lurlene
If all controllers implement this HandlerExceptionResolver, then they will all be called when exceptions occurs?Alcott
I have tried to put the same approach into practice but nothing worked. Also tried the same approach as mentioned on this post. The method resolveException() is never invoked even though the exception occurs. I want to show a user-friendly error message on the same page but I'm getting the full stack trace on the web page. Am I missing something with Spring 3.2.0?Busch
How can I effectively handle MaxUploadSizeExceededException in an ajax based context ? I am uploading file by ajax request, so when file uploading failed I want to show a javascript alert in the browser, instead of redirecting to some error page. How can I do this ?Lemmon
@faizi see my answer,code format is so bad in comments,so i write a new answerPhifer
This does not work for some people. Is there some sort of discrepancy between Spring versions?Loris
This method will wrap every exception ... even exceptions in other pages/controllersViipuri
I cant edit my previous answer but you should return null for default processing of other exceptionsViipuri
@JohnathanAu Not really. You require the Apache Commons FileUpload dependency to get this CommonsMultipartResolver to work, due to the fact that Spring Boot uses the default Servlet 3.0 support for file uploads, NOT commons-fileupload. Also, if you use the Apache Commons, the spring.http.multipart.* properties will no longer work.Squash
B
8

Thanks for solving this Steve. I banged around trying to solve for several hours.

The key is to have the controller implement HandlerExceptionResolver and add the resolveException method.

--Bob

Bailment answered 5/12, 2010 at 21:3 Comment(1)
the best! i was just about to close this tab but then spotted this! thanks!Godless
K
7

Use controller advice

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public ModelAndView handleMaxUploadException(MaxUploadSizeExceededException e, HttpServletRequest request, HttpServletResponse response){
        ModelAndView mav = new ModelAndView();
        boolean isJson = request.getRequestURL().toString().contains(".json");
        if (isJson) {
            mav.setView(new MappingJacksonJsonView());
            mav.addObject("result", "nok");
        }
        else mav.setViewName("uploadError");
        return mav;
    }
}
Kuvasz answered 22/5, 2014 at 1:48 Comment(0)
P
2

if using ajax,need to response json,can response json in resolveException method

@Override
  public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
      Object handler, Exception ex) {
    ModelAndView view = new ModelAndView();
    view.setView(new MappingJacksonJsonView());
    APIResponseData apiResponseData = new APIResponseData();

    if (ex instanceof MaxUploadSizeExceededException) {
      apiResponseData.markFail("error message");
      view.addObject(apiResponseData);
      return view;
    }
    return null;
  }
Phifer answered 31/3, 2015 at 7:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.