Spring Boot doesn't use CommonsMultipartResolver?

纵然是瞬间 提交于 2021-02-19 03:36:06

问题


I have a problem with REST web service running with Spring Boot (Jetty). One of my REST method is file upload and I'm guessing that CommonsMultipartResolver is not using during multipart requests.

Signature of this upload 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 like 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'm calling this method I got an 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 in this stack trace I cannot see any CommonsMultipartResolver calls. Another thing is that exactly the same code was working in GlassFish environment - I could upload files with no problem. What changed is that multipartResolver bean in GlassFish was defined in dispatcher-servlet.xml and in Spring Boot I initialize it in BootApplication class. I also tried to left multipartResolver in dispatcher-servlet.xml which I'm also loading for configuration but none of this solution worked.

When I'm looking at /beans endpoint in Spring Boot I can see multipartResolver bean. No other bean has dependency to this multipartResolver bean - maybe this is wrong, but I have no idea how to configure it properly.

Below you have my dispatcher-servlet.xml if it will help :

<?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>

回答1:


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

Spring Boot by default already configures file uploading so you can remove your definition. If you want to control certain values you can configure those by adding properties to the application.properties. See this section of the reference guide.

I would suggest removing your dispatcher-servlet.xml because Spring Boot already enables MVC configuration and you enabling it interferes with the auto configuration. Assuming that your BootApplication is inside the com.my.package you can already remove the file as it adds nothing, if the BootApplication is in a different package add @ComponentScan("com.my.package") to the configuration.

To import the applicationContext.xml add a @ImportResource to your BootApplication instead of what you are doing now. However depending on what is in there (probably some datasource, JPA, etc. configuration you might 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 is that you are disabling part of the Spring Boot auto configuration to properly let it configure things.




回答2:


I think they have resolved the issue 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's MulipartAutoConfiguration.class

@EnableAutoConfiguration(exclude = {MultipartAutoConfiguration.class})

This worked for me.



来源:https://stackoverflow.com/questions/31178160/spring-boot-doesnt-use-commonsmultipartresolver

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!