Spring Boot not using CommonsMultipartResolver?

I have a problem with a REST web service running with Spring Boot (Jetty). One of my REST methods is file upload, and I am assuming CommonsMultipartResolver is not used during multipart requests.

The signature of this boot method is:

@ResponseBody
@RequestMapping(value = "/upload", method = RequestMethod.POST, produces = "application/json")
public BaseResponse upload(@RequestParam("login") String login, @RequestParam("passwd") String passwd,
        @RequestParam("partner") String partner, @RequestParam("fileName") String fName, 
        @RequestParam("length") int fLen, @RequestParam("file") MultipartFile file) throws IOException

      

I also have a root application class as shown below:

@SpringBootApplication
public class BootApplication {

    private static final Logger _logger = Logger.getLogger(BootApplication.class.getName());

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(BootApplication.class,
                new ClassPathResource("WEB-INF/applicationContext.xml"),
                new ClassPathResource("WEB-INF/dispatcher-servlet.xml"));
        app.run(args);
    }

    @Bean(name = "multipartResolver")
    public CommonsMultipartResolver multipartResolver(ServletContext servletContext) {
        _logger.log(Level.INFO, "[BootApplication] Fetching CommonsMultipartResolver");
        return new CommonsMultipartResolver(servletContext);
    }
}

      

When I call this method, I got the error:

org.springframework.web.bind.MissingServletRequestParameterException: Required MultipartFile parameter 'file' is not present
at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:253)
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:94)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:129)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:776)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:808)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1669)
at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:224)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration$ApplicationContextHeaderFilter.doFilterInternal(EndpointWebMvcAutoConfiguration.java:295)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:102)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:68)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
at org.eclipse.jetty.server.Server.handle(Server.java:497)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:310)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:540)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
at java.lang.Thread.run(Thread.java:745)

      

What's strange about this stack trace is I can't see any calls CommonsMultipartResolver

. Another thing is that exactly the same code worked in the GlassFish environment - I could upload files without problems. What changed is that the multipartResolver

bean in GlassFish was defined in dispatcher-servlet.xml

, and in Spring Boot, I initialized it in the class BootApplication

. I also tried leaving multipartResolver

in dispatcher-servlet.xml

, which I also load for config, but none of these solutions worked.

When I look at the endpoint /beans

in Spring Boot I see a multipartResolver

bean. No other bean is relevant to this multipartResolver

bean - it might be wrong, but I don't know how to set it up correctly.

Below you have dispatcher-servlet.xml

if it helps:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="
http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

    <context:annotation-config />
    <context:component-scan base-package="com.my.package" />
    <mvc:annotation-driven />
</beans>

      

+3


source to share


2 answers


You are using Spring Boot, then you are using it, you are trying to work around it.

Spring Boot already configures file upload by default, so you can remove your definition. If you want to control certain values, you can customize them by adding properties to application.properties

. See this section of the reference guide.

I would suggest removing yours dispatcher-servlet.xml

because Spring Boot already includes MVC configuration and you allow it to prevent auto-configuration. Assuming yours BootApplication

is inside com.my.package

, you can already delete the file as it doesn't add anything, if BootApplication

in another package add @ComponentScan("com.my.package")

to config.



To import applicationContext.xml

, add @ImportResource

to yours BootApplication

instead of what you are doing now. However, depending on what's in there (maybe with some data source configuration, JPA, etc., you could even remove it and replace it with some simple properties instead).

@SpringBootApplication
@ComponentScan("com.my.package")
@ImportResource("WEB-INF/applicationContext.xml")
public class BootApplication {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(BootApplication.class, args);
    }
}

      

The main problem is that you disable some of Spring Boot's auto-configuration to set it up correctly.

+3


source


I think they solved the problem in Spring-Boot 1.4.2.RELEASE

@Bean
public CommonsMultipartResolver multipartResolver() {
    CommonsMultipartResolver multipart = new CommonsMultipartResolver();
    multipart.setMaxUploadSize(3 * 1024 * 1024);
    return multipart;
}

@Bean
@Order(0)
public MultipartFilter multipartFilter() {
    MultipartFilter multipartFilter = new MultipartFilter();
    multipartFilter.setMultipartResolverBeanName("multipartResolver");
    return multipartFilter;
}

      

You also need to exclude Spring-Boot MulipartAutoConfiguration.class



@EnableAutoConfiguration (exclude = {MultipartAutoConfiguration.class})

This worked for me.

+1


source







All Articles