1

I need to parse a multipart request in a spring-mvc controller. Spring version is 4.1.6. Example of the request:

HEADER host: "localhost:8080"
HEADER accept: "*/*"
HEADER content-length: "539"
HEADER expect: "100-continue"
HEADER content-type: "multipart/form-data; boundary=------------------------2e2bf5fa2f7bbfbf"
BODY:
--------------------------2e2bf5fa2f7bbfbf
Content-Disposition: form-data; name="objectid"

160714.110239.GG
--------------------------2e2bf5fa2f7bbfbf--
Content-Disposition: form-data; name="geojson"

[a very long json string]
--------------------------2e2bf5fa2f7bbfbf

The exact formatting of the request is not under my control.

As long as I use the whole @RequestBody, my RequestMapping is resolved:

@RequestMapping(value = "/coordinates", method = RequestMethod.POST)
public @ResponseStatus(value = HttpStatus.OK)
void coordinates(final HttpServletRequest request,
                 final @RequestBody String body) {
  final Enumeration<String> headerNames = request.getHeaderNames();
  while (headerNames.hasMoreElements()) {
    final String element = headerNames.nextElement();
    System.out.println("HEADER " + element + ": \"" + request.getHeader(element) + "\"" );
  }
  System.out.println("BODY:");
  System.out.println(body);
}

But when I change the signature in order to get the parts directly, the client gets an error message, saying "Required String parameter 'objectid' is not present", and my mapping is not resolved anymore (tested with a breakpoint). This is the failing code:

@RequestMapping(value = "/coordinates", method = RequestMethod.POST)
public @ResponseStatus(value = HttpStatus.OK)
void coordinates(final HttpServletRequest request,
                 final @RequestParam("objectid") String objectid,
                 final @RequestParam("geojson") String geojson) {
  final String remoteAddr = request.getRemoteAddr();
  System.out.println("coordinates from " + remoteAddr
      + ":\nobjectid=" + objectid
      + "\ngeojson=" + geojson);
}

What am I doing wrong ?

Markus N.
  • 233
  • 4
  • 10
  • The one is web request parameter and the other is body. There is a difference. More information here: https://stackoverflow.com/questions/28039709/what-is-difference-between-requestbody-and-requestparam – Aleydin Karaimin Jun 28 '17 at 07:44
  • This is really curious, because all examples I found about multipart with spring are using @RequestParam for files as well as strings (e.g. file title), and at least the file can only be in the body. – Markus N. Jun 28 '17 at 08:00
  • Spring is reading the whole url String to get the request parameters. If they are not present in request url you cannot extract them as @RequestParameter. Your data is probably in the body. If you want different names, use jaxon for custom mapping – Aleydin Karaimin Jun 28 '17 at 08:04
  • Why can't you use @RequestBody? – Rana_S Jun 28 '17 at 21:03
  • Because the @RequestBody contains all of the fields, and then I would have to parse it in order to get the fields one by one. This also includes decoding NLS characters in the json string. I thought there is a way to let spring do this for me. – Markus N. Jun 29 '17 at 07:34

2 Answers2

1

Since you are submitting the data using POST method,multi-part content will go in the request body not as request parameters.

In second case, you annotated with request param object, spring will check for a parameter in the request url. If its not available spring will throw an error. Additionally you can make the request parameter as optional or you can give default value

Anil Paul
  • 31
  • 1
  • 3
  • OK, so I'm using the wrong annotation. Is there some annotation that splits the body into the fields, does the decoding of special characters and then gives me the fields as separate Strings ? – Markus N. Jun 30 '17 at 10:47
1

Resolved.

There was one thing missing in my spring configuration:

<bean id="multipartResolver"
      class="org.springframework.web.multipart.support.StandardServletMultipartResolver">
  <property name="maxUploadSize" value="100000"/>
</bean>

And with that resolver, the @RequestParam annotation (as in my second java source example) works. Yes, it's @RequestParam although the values are not part of the URL.

Markus N.
  • 233
  • 4
  • 10