Spring Boot不使用CommonsMultipartResolver?

时间:2015-07-02 07:28:59

标签: spring spring-mvc file-upload spring-boot multipartform-data

运行Spring Boot(Jetty)的REST Web服务存在问题。 我的一种REST方法是文件上传,我猜测CommonsMultipartResolver在多部分请求期间没有使用。

此上传方式的签名是:

@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

我还有一个如下所示的根应用程序类:

@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);
    }
}

当我调用此方法时出现错误:

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)

在这个堆栈跟踪中有什么奇怪的,我看不到任何CommonsMultipartResolver个电话。 另一件事是完全相同的代码在GlassFish环境中工作 - 我可以上传文件没有问题。更改的是GlassFish中的multipartResolver bean在dispatcher-servlet.xml中定义,在Spring Boot中我在BootApplication类中初始化它。我还尝试将multipartResolver留在dispatcher-servlet.xml中,我也在加载配置,但这个解决方案都没有。

当我在Spring Boot中查看/beans端点时,我可以看到multipartResolver bean。没有其他bean依赖于这个multipartResolver bean - 也许这是错误的,但我不知道如何正确配置它。

如果它有帮助,您可以在下面找到dispatcher-servlet.xml

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

2 个答案:

答案 0 :(得分:4)

您正在使用Spring Boot然后使用它,您正试图解决它。

Spring Boot默认情况下已配置文件上传,因此您可以删除您的定义。如果要控制某些值,可以通过向application.properties添加属性来配置这些值。请参阅参考指南的this section

我建议删除dispatcher-servlet.xml,因为Spring Boot已启用MVC配置,启用它会干扰自动配置。假设您的BootApplication位于com.my.package内,您可以删除该文件,因为它不会添加任何内容,如果BootApplication位于不同的包中,请将@ComponentScan("com.my.package")添加到配置中。

要导入applicationContext.xml,请将@ImportResource添加到BootApplication,而不是现在正在执行的操作。但是根据其中的内容(可能是某些数据源,JPA等配置,您甚至可以删除它并将其替换为一些简单的属性)。

@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);
    }
}

主要问题是您正在禁用部分Spring Boot自动配置以正确配置它。

答案 1 :(得分:1)

我认为他们已经在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;
}

您还需要排除Spring-Boot的MulipartAutoConfiguration.class

@EnableAutoConfiguration(exclude = {MultipartAutoConfiguration.class})

这对我有用。