File upload working under Jetty but not under Tomcat
Asked Answered
B

2

4

I have a web application with spring in which I do some file upload. Under eclipse, using Jetty (the maven plugin) it works perfectly. But when I deploy the application under Tomcat it does not and I get the following Exception :

org.springframework.web.bind.MissingServletRequestParameterException: Required org.springframework.web.multipart.MultipartFile parameter 'file' is not present
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.raiseMissingParameterException(AnnotationMethodHandlerAdapter.java:545)
org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveRequestParam(HandlerMethodInvoker.java:336)
org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:207)
org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:132)
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:326)
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:313)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)

Here is my form :

<form method="post" action="../admin/import.html" id="import"
    enctype="multipart/form-data">
    <div id="importInmates" align="center">
        <input type="file" name="file" id="file"
            data-dojo-type="dijit.form.Button"
            label="<fmt:message key='import.file' />" />
        <button data-dojo-type="dijit.form.Button" id="importInmates"
            type="submit">
            <fmt:message key="import.import" />
        </button>
    </div>
    <input type="hidden" name="importType" value="inmates" />
</form>

And here is the intercepting method :

    @RequestMapping(value = IMPORT_PAGE, method = RequestMethod.POST)
public String recieveFile(@RequestParam("importType") String importType,
        @RequestParam("file") MultipartFile multipartFile, final HttpSession session)
{
    if (multipartFile.getSize() < 0)
    {
        LOGGER.debug("No file has been uploaded");
        return "redirect:.." + IMPORT_PAGE;
    }

    File file = new File("tmp");

    try
    {
        multipartFile.transferTo(file);
        BufferedReader lec = new BufferedReader(new FileReader(file));

        LOGGER.debug(lec.readLine());
        lec.close();

    }
    catch (Exception e)
    {
        LOGGER.error("An exception occured while reading " + importType + " file", e);
    }

    return "redirect:.." + IMPORT_PAGE;
}

I have added the following bean :

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

both in applicationContext.xml and mvc-servlet.xml even if I think that only the latter is important.

Any help would be appreciated.

Thanks.

Bryner answered 16/5, 2014 at 15:2 Comment(5)
There looks like a lot of Spring magic in there. It doesn't look like Tomcat has anything to do with this.Neodarwinism
In that case why is it working like a charm under Jetty ?Bryner
I dunno. But this is a Spring exception complaining about a Spring configuration that is evidently not correct. Why didn't you add the "Spring" tag to this question?Neodarwinism
Maybe because I think that tomcat is the cause of this problem. But thanks for adding the tag.Bryner
But why was it working in one case and not the other?Lesialesion
B
3

Thanks to @Bart I was able to find the following simple solution :

In the intercepting method, use @ModelAttribute instead of @RequestParam :

@RequestMapping(value = IMPORT_PAGE, method = RequestMethod.POST)
public String recieveFile(@RequestParam("importType") String importType,
        @ModelAttribute("file") UploadedFile uploadedFile, final HttpSession session)
{
    MultipartFile multipartFile = uploadedFile.getFile();

Where UploadedFile is the following class :

public class UploadedFile
{
    private String type;

    private MultipartFile file;

    public String getType()
    {
        return type;
    }

    public void setType(String type)
    {
        this.type = type;
    }

    public void setFile(MultipartFile file)
    {
        this.file = file;
    }

    public MultipartFile getFile()
    {
        return file;
    }
}

And it's working !!

Thanks everyone for your help.

Bryner answered 23/5, 2014 at 10:26 Comment(0)
P
1

Use @RequestPart instead of @RequestParam.

From the source:

Annotation that can be used to associate the part of a "multipart/form-data" request with a method argument. Supported method argument types include {@link MultipartFile} in conjunction with Spring's {@link MultipartResolver} abstraction, {@code javax.servlet.http.Part} in conjunction with Servlet 3.0 multipart requests, or otherwise for any other method argument, the content of the part is passed through an {@link HttpMessageConverter} taking into consideration the 'Content-Type' header of the request part. This is analogous to what @{@link RequestBody} does to resolve an argument based on the content of a non-multipart regular request.

Note that @{@link RequestParam} annotation can also be used to associate the part of a "multipart/form-data" request with a method argument supporting the same method argument types. The main difference is that when the method argument is not a String, @{@link RequestParam} relies on type conversion via a registered {@link Converter} or {@link PropertyEditor} while @{@link RequestPart} relies on {@link HttpMessageConverter}s taking into consideration the 'Content-Type' header of the request part. @{@link RequestParam} is likely to be used with name-value form fields while @{@link RequestPart} is likely to be used with parts containing more complex content (e.g. JSON, XML).

Peloquin answered 20/5, 2014 at 16:39 Comment(2)
Thanks @Peloquin for the reply, I tried to use RequestPart but it is included in spring 3.1 while I am using 2.5.6. So I went last night through a dependency configuration nightmare to upgrade to a higher version of spring but I couldn't do it due to other surprising errors so I came back to 2.5.6. Now, is there a way to enable/disable file upload via tomcat configuration ?Bryner
Tomcat won't do any file uploading stuff unless you are using the Servlet-3.0 annotations or web.xml directives affecting file upload. If you want to disable file uploads in Spring, I can't help you. (Sorry!)Neodarwinism

© 2022 - 2024 — McMap. All rights reserved.