Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling MultipartException with Spring Boot and display error page

I have a very simple file upload set up with Spring Boot. I was wondering if there was an easy way to display an error page when the maximum file size is exceeded.

I have uploaded a very simple example of what I'm trying to achieve on github.

Basically, the idea is to catch the MultipartException in a global Spring exception handler:

@ControllerAdvice
public class UploadExceptionHandler {

  @ExceptionHandler(MultipartException.class)
  public ModelAndView handleError(MultipartException exception) {
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("error", exception.getMessage());
    modelAndView.setViewName("uploadPage");
    return modelAndView;
  }
}

The controller which handles the file upload is really simple:

@RequestMapping("/")
public String uploadPage() {
    return "uploadPage";
}

@RequestMapping(value = "/", method = RequestMethod.POST)
public String onUpload(@RequestParam MultipartFile file) {
    System.out.println(file.getOriginalFilename());
    return "uploadPage";
}

And the uploadPage.html thymeleaf template associated with it too:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en">
    <title>Upload</title>
</head>
<body>

<div style="color: red" th:text="${error}" th:if="${error}">
    Error during upload
</div>

<form th:action="@{/}" method="post" enctype="multipart/form-data">
  <input type="file" id="file" name="file"/>
  <button type="submit" name="save">Submit</button>
</form>
</body>
</html>

The idea is to display an error message in the same upload page when the file is too big.

It was my understanding that one would configure Spring's MultipartResolver to resolve exceptions lazily and be able to catch those exceptions at Spring's level (MVC exception handlers) but this code does not seem to help:

@Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
public StandardServletMultipartResolver multipartResolver() {
    StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();
    multipartResolver.setResolveLazily(true);
    return multipartResolver;
}

So before I resort to extreme measures like a filter or extending the MultipartResolver...

Do you know a clean way to handle those exceptions with Spring MVC?

Answer

Thanks to @rossen-stoyanchev. Here is what I ended up doing:

@RequestMapping("uploadError")
public ModelAndView onUploadError(HttpServletRequest request) {
    ModelAndView modelAndView = new ModelAndView("uploadPage");
    modelAndView.addObject("error", request.getAttribute(WebUtils.ERROR_MESSAGE_ATTRIBUTE));
    return modelAndView;
}

@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
    return container -> container.addErrorPages(new ErrorPage(MultipartException.class, "/uploadError"));
}

Works like a charm and feels like an elegant solution. I updated the project on github if someone is interested. Many thanks!

like image 826
Geoffroy Warin Avatar asked Mar 31 '15 08:03

Geoffroy Warin


1 Answers

Multipart request parsing happens before a handler is selected and hence there is no @Controller and therefore no @ControllerAdvice to speak of yet. You can use an ErrorController (see http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-web-applications.html#boot-features-error-handling) for that.

BTW you don't need @RequestParam. It's enough that the argument type is MultipartFile.

like image 165
Rossen Stoyanchev Avatar answered Oct 13 '22 17:10

Rossen Stoyanchev