Handling MultipartException with Spring Boot and display error page
Asked Answered
H

1

7

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!

Hydatid answered 31/3, 2015 at 8:10 Comment(4)
Part of the problem might have to do with the fact that the multipart requests are not really linked to Spring MVC's lifecycle. I mean the exception handler can be called multiple times on the same page if the file is big enough. What's puzzling is it can work, sometimes, when actually not resolving exceptions lazily but this behavior does not seem to be consistent.Hydatid
The solution doesn't work for me. I have the error page for MultipartException added and I still get a crash when I try to upload a big file. Can you help me?Foreland
The repository is still up: github.com/geowarin/multipartException it should work :)Hydatid
I forked the repo and tried to validate this. I have observed that the @RequestMapping("uploadError") method is never called. I have created this issue github.com/Mastering-Spring-MVC-4/mastering-spring-mvc4/issues/….Mcspadden
P
3

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.

Perot answered 31/3, 2015 at 10:48 Comment(3)
But what to do if I want to return just object to ajax- not pagePapaya
@Papaya refer this for ajax validations - github.com/ajkr195/springbootajaxvalidation.gitFiscal
I want to validate the size of multipart and want to throw an exception in REST API. Can you please suggest a way for it?Apparent

© 2022 - 2024 — McMap. All rights reserved.