Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring 3.0 FileUpload only with POST?

I am trying to upload a File with one parameter using spring 3.

This is my controller method which should enable this service:

@RequestMapping(value="/{id}", method = RequestMethod.PUT, headers="content-type=multipart/form-data")
public ResponseEntity<String> uploadImageWithJsonParamater(@PathVariable("id") Long id, @RequestParam String json, @RequestParam MultipartFile customerSignFile) {
    //...
}

The problem is, that the server cannot dispatch to this method: MissingServletRequestParameterException: Required String parameter 'json' is not present

If I change the RequestMethod from PUT to POST, everything is fine. So does anybody know the problem?

It seems that it isn't allowed to transmit form-data via PUT.

I debugged a little bit and the following method returns false in the PUT case but true in the POST case:

public boolean isMultipart(HttpServletRequest request) {
    return (request != null && ServletFileUpload.isMultipartContent(request));
}

I would appreciate any help!

Thanks in advance!

like image 940
Alexander Avatar asked Nov 02 '11 14:11

Alexander


2 Answers

You can accomplish this using spring's HiddenHttpMethodFilter, but you will need to ensure that you put a Spring MultipartFilter before the HiddenHttpMethodFilter in your web.xml filter chain.

For example: In your web.xml

<filter>
    <filter-name>MultipartFilter</filter-name>
    <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
    <init-param>
        <param-name>multipartResolverBeanName</param-name>
        <param-value>filterMultipartResolver</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>MultipartFilter</filter-name>
    <servlet-name>/*</servlet-name>
</filter-mapping>
<filter>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <servlet-name>/*</servlet-name>
</filter-mapping>

Then in your spring-config.xml add a reference to CommonsMultipartResolver:

<bean id="filterMultipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>

Note that, if you don't add the spring-config.xml entry your MultipartFilter will default to using a MultipartResolver that uses servlet spec 3.0 implementation and will throw error like: NoSuchMethodError HttpServletRequest.getParts() if you're not using 3.0.

like image 186
Jason Buchanan Avatar answered Sep 26 '22 04:09

Jason Buchanan


I run into the same problem. My solution was implementing an ExtendedMultipartResolver which accept multiparts sent via http method PUT as well. Just copy the CommonsMultipartResolver code, rename the class and change the implementation of the isMultipart() function to your needs:

private boolean isMultipartContent(HttpServletRequest request) {
  String httpMethod = request.getMethod().toLowerCase();
  // test for allowed methods here...
  String contentType = request.getContentType();
  return (contentType != null && contentType.toLowerCase().startsWith("multipart"));
}


public boolean isMultipart(HttpServletRequest request) {
      return (request != null && isMultipartContent(request));
}

You could check for POST, PUT or other HTTP methods here. In my case, all methods will be accepted, as my controller annotations will filter to the allowed methods.

Dont forget to configure the bean in the spring web context:

<bean id="multipartResolver" class="sample.package.ExtendedMultipartResolver"/>

hope that helps.

cheers chris

like image 24
chris Avatar answered Sep 22 '22 04:09

chris