I am trying to use CommonsMultipartResolver
in my Spring Boot application. I cannot use the StandardServletMultipartResolver
, as I want to handle exceptions (e.g. exceeding file size).
I have set up a dependency to commons-fileupload
. My spring configuration is:
@Autowired
private MultipartProperties multipartProperties = new MultipartProperties();
@Bean
public MultipartConfigElement multipartConfigElement() {
return this.multipartProperties.createMultipartConfig();
}
@Bean
public MultipartResolver multipartResolver() {
LOG.debug("initializing MultipartResolver");
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
return multipartResolver;
}
@Bean
public FilterRegistrationBean multipartFilterRegistrationBean() {
final MultipartFilter multipartFilter = new MultipartFilter();
final FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(multipartFilter);
multipartFilter.setMultipartResolverBeanName("multipartResolver");
filterRegistrationBean.setOrder(OrderedHiddenHttpMethodFilter.DEFAULT_ORDER-1);
return filterRegistrationBean;
}
When I set up the MultipartFilter
to be executed prior to the HiddenHttpMethodFilter
I get an IOException
:
Caused by: java.io.IOException: Missing content for multipart request
at org.eclipse.jetty.util.MultiPartInputStreamParser.parse(MultiPartInputStreamParser.java:491)
at org.eclipse.jetty.util.MultiPartInputStreamParser.getParts(MultiPartInputStreamParser.java:400)
at org.eclipse.jetty.server.Request.getParts(Request.java:2139)
at org.eclipse.jetty.server.Request.extractMultipartParameters(Request.java:385)
... 35 common frames omitted
Otherwise, I get an exception that the part parameter is not present in the request.
I believe I need to disable the servlet 3.0 handling of multipart requests, but I cannot figure out how to do it in spring boot.
The issue was caused by DefaultMultipartHttpServletRequest
throwing an exception on getParameter
which was called by HiddenHttpMethodFilter
, because the stream was already processed in MultipartFilter
:
@Override protected void doFilterInternal(HttpServletRequest request, >HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String paramValue = request.getParameter(this.methodParam); if ("POST".equals(request.getMethod()) && >StringUtils.hasLength(paramValue)) { String method = paramValue.toUpperCase(Locale.ENGLISH); HttpServletRequest wrapper = new >HttpMethodRequestWrapper(request, method); filterChain.doFilter(wrapper, response); } else { filterChain.doFilter(request, response); } }
My solution to this was to disable MultipartAutoConfiguration
, not define a MultipartConfigElement
bean in order to disable servlet 3.0 multipart parsing and not use the MultipartFiler
.
Now the configuration looks like the following:
@Autowired
private MultipartProperties multipartProperties = new MultipartProperties();
@Bean
public MultipartResolver multipartResolver() {
LOG.debug("initializing MultipartResolver");
MultipartConfigElement config = multipartProperties.createMultipartConfig();
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setResolveLazily(true);
multipartResolver.setMaxUploadSize(config.getMaxRequestSize());
multipartResolver.setMaxUploadSizePerFile(config.getMaxFileSize());
return multipartResolver;
}
Now it is even possible to use @ExceptionHandler advice to return the correct HTTP code when a file exceeds the maximum size allowed.