28

I'm trying to incorporate multiple file upload functionality in my Angular web application using angular-file-upload. Currently, the front end functionality works, but each upload attempt throws a

java.lang.IllegalStateException,java.io.IOException]: 
    java.lang.IllegalArgumentException: Expected MultipartHttpServletRequest: 
        is a MultipartResolver configured?

exception.

The Upload Controller is defined as

@Controller
@PropertySource("classpath:application.properties")
public class FileUploadController {

    @Resource
    private Environment env;

    @RequestMapping(value = "/fileupload", method = RequestMethod.POST)
    @ResponseBody
    public List<String> fileUpload(@RequestParam("file") MultipartFile[] uploadFiles) throws IllegalStateException, IOException {
        //file processing logic
    }
 }

In my AppConfig.java class, I declare the bean

@Bean
public CommonsMultipartResolver commonsMultipartResolver(){
    CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
    commonsMultipartResolver.setDefaultEncoding("utf-8");
    commonsMultipartResolver.setMaxUploadSize(50000000);
    return commonsMultipartResolver;
}

and start the web application with

@Override
public void onStartup(ServletContext servletContext) throws ServletException {

    AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
    ctx.register(AppConfig.class);
    servletContext.addListener(new ContextLoaderListener(ctx));

    ctx.setServletContext(servletContext);
    ctx.refresh();

    Dynamic servlet = servletContext.addServlet(SERVLET_NAME, new DispatcherServlet(ctx));
    servlet.addMapping("/");
    servlet.setLoadOnStartup(1);
    //servlet.setMultipartConfig(ctx.getBean(MultipartConfigElement.class));
}

I do not think it is due to the lack of a <form> element in my Angular view, because I can see that Content-Tyle is multipart/form-data and that the Request Payload is set appropriately.

Remote Address:192.168.33.10:80
Request URL:http://dev.jason.com/rest/fileupload
Request Method:POST
Status Code:500 Internal Server Error
Request Headers
  Accept:*/*
  Accept-Encoding:gzip,deflate
  Accept-Language:en-US,en;q=0.8
  Cache-Control:no-cache
  Connection:keep-alive
  Content-Length:415235
  Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryBHlsldPQysTVpvwZ
  Host:dev.jason.com
  Origin:http://dev.jason.com
  Pragma:no-cache
  Referer:http://dev.jason.com/
  User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36
Request Payload
   ------WebKitFormBoundaryBHlsldPQysTVpvwZ
   Content-Disposition: form-data; name="file"; filename="IMG_5072.jpg"
   Content-Type: image/jpeg

   ------WebKitFormBoundaryBHlsldPQysTVpvwZ--

Note that this issue still occurs when including

@Bean
public MultipartConfigElement multipartConfigElement(){
    MultipartConfigFactory multipartConfigFactory = new MultipartConfigFactory();
    multipartConfigFactory.setMaxFileSize("10MB");
    multipartConfigFactory.setMaxRequestSize("50MB");
    return multipartConfigFactory.createMultipartConfig();
}

in AppConfig.java and uncommenting the command

servlet.setMultipartConfig(ctx.getBean(MultipartConfigElement.class));

in my servlet initializer class.

Any help is appreciated!

Jason
  • 11,263
  • 21
  • 87
  • 181
  • For one, don't register the `ctx` context with both the `ContextLoaderListener` and the `DispatcherServlet`. – Sotirios Delimanolis Nov 20 '14 at 21:44
  • What is the reasoning behind that? – Jason Nov 20 '14 at 21:49
  • http://stackoverflow.com/questions/11708967/what-is-the-difference-between-applicationcontext-and-webapplicationcontext-in-s – Sotirios Delimanolis Nov 20 '14 at 21:50
  • ok, but what does that have to do with the current issue? – Jason Nov 20 '14 at 21:53
  • It doesn't. It's just advice. It may affect you negatively in other cases. – Sotirios Delimanolis Nov 20 '14 at 21:54
  • OK, appreciate it. I basically followed another application's configuration, and that one used the same `ctx` variable for both `ContextLoaderListener` and `DispatcherServlet`. So I wonder how common this kind of configuration is. – Jason Nov 20 '14 at 21:56
  • The `DispatcherServlet` some times goes to the `WebApplicationContext` loaded by the `ContextLoaderListener` for beans. If you're using the same context for both, you might end up with duplicate registrations. Are you sure they didn't re-initialize/assign the variable? – Sotirios Delimanolis Nov 20 '14 at 21:57

3 Answers3

33

Spring's MVC stack requires that the MultipartResolver bean be called multipartResolver. Change your @Bean method to

@Bean
public CommonsMultipartResolver multipartResolver(){

or

@Bean(name = "multipartResolver")
public CommonsMultipartResolver commonsMultipartResolver(){
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • Such a simple solution to a frustrating problem. Thanks! – Jason Nov 20 '14 at 22:01
  • @Jason What bugs me is that, other than the source code, there is no documentation specifying this. The examples provided in the docs simply use `multipartResolver` but don't make it clear (at least not what I've read) that the name has to be `multipartResolver`. – Sotirios Delimanolis Nov 20 '14 at 22:02
  • Agreed, though I should have caught this. Almost all of the examples I looked at for help had XML configuration with ` ... ` – Jason Nov 20 '14 at 22:07
  • 1
    +1 This is an unnecessary problem to be facing. I have no idea why the method name would have to be named exactly multipartResolver, and also no idea why this isn't all over the documentation. – John Smith Feb 07 '15 at 01:04
10

Just add this to servler-context.xml

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
 <property name="maxUploadSize" value="268435456"/>
</bean>

Nothing else needed.

Patrice
  • 1,404
  • 1
  • 14
  • 27
-1

You have to add in webmvc-context.xml this:

<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver"/>
Flavio Troia
  • 2,451
  • 1
  • 25
  • 27