Spring @MVC and the @RequestBody annotation with x-www-form-urlencoded data?

34,470

Solution 1

Have you tried turning up logging on 'org.springframework.web' to find out the reason for the returned status code? There should be an exception raised and logged before it's translated to a 415.

Also if sending form data, why not just leave out the @RequestBody. You'll then be use data binding (i.e. @ModelAttribute) that will apply Servlet request parameters to object fields. This is preferable to using the FormHttpMessageConverter.

Solution 2

As the Spring Docs of @RequestBody says, the request body would be converted to your object by HttpMessageConverter.

There are 4 default HttpMessageConverters:

To convert the url encoded form, which is ajax.serialize() create, it's the job of FormHttpMessageConverter. Since you have a HttpMediaTypeNotSupportedException exception, I guess that you didn't configure FormHttpMessageConverter. Check your spring configuration file, here is an example :

< bean class ="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" >
   < property name= "messageConverters" >
         < list>
             < ref bean= "mappingJacksonHttpMessageConverter" />
             < ref bean= "stringHttpMessageConverter" /> 
             <!-- Do you have this converter ? -->
             < ref bean= "formHttpMessageConverter" />
         </ list>
    </ property>
</ bean>
Share:
34,470
devdavid
Author by

devdavid

I am the Linux administrator at Clayton State University in Morrow, GA. I deal primarily with RHEL server administration, but I do a fair amount of scripting and web development as well. But programming is more of a hobby for me than day job. My current interest is in Node.js.

Updated on July 16, 2022

Comments

  • devdavid
    devdavid almost 2 years

    I am trying to figure out why I can't receive a request from a jQuery.ajax call when then Spring @Controller handler method includes a @RequestBody annotation. Consider the following:

    HTML/JavaScript:

    <form id="foo" action="/baz">
      <input name="bar">
    </form>
    
    <script>
      $(function() {
        var $fooForm = $('#foo');
    
        $fooForm.on('submit', function(evt) {
          evt.preventDefault();
    
          $.ajax({
            url: $fooForm.action,
            data: $fooForm.serialize(),
            dataType: 'json',
            type: 'POST',
            success: function(data) { console.log(data); }
          });
        });
      });
    </script>
    

    Java:

    @RequestMapping(
      value = "/baz",
      method = RequestMethod.POST,
      consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
      produces = MediatType.APPLICATION_JSON_VALUE
    )
    public @ResponseBody SearchResults[] jqueryPostHandler(
      @RequestBody FormDataObject formData)
    {
      return this.searchService.find(formData);
    }
    

    The above will fail with the @RequestBody annotation present and return a 415 error (no exception will be generated). But if the @RequestBody annotation is removed (i.e. the parameter signature is just FormDataObject formData) then the method will be called and JSON will be returned to the JavaScript.

    Why is this the case? A POST request includes the data in the body of the request. Shouldn't the annotation process such a request?

    I realize that I could change the content type sent by the JavaScript to application/json and the consumes property to MediaType.APPLICATION_JSON_VALUE to make the annotation work correctly. But why doesn't it work with a normal form request?

    Note: I am using Spring 3.1.4.

  • devdavid
    devdavid almost 11 years
    Turning up logging shows that with the @RequestBody annotation in place it does map to the right method, but it throws "org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported".
  • devdavid
    devdavid almost 11 years
    From my limited understanding, the annotation @RequestBody implies that the data to be processed will be in the body of the request. This informs the compiler and the person reading the code. So, leaving it makes for ambiguous code. That's why I want to know why this is failing.
  • usr-local-ΕΨΗΕΛΩΝ
    usr-local-ΕΨΗΕΛΩΝ over 8 years
    The above did not work for me, even if I added all converters. I had to use the custom converter at stackoverflow.com/a/31083802/471213 to make it work
  • Qianyue
    Qianyue over 8 years
    @usr-local-ΕΨΗΕΛΩΝ is your problem the same as this question? my answer is for this question, and if yours is different, or maybe your should ask a new question to explain more details.
  • usr-local-ΕΨΗΕΛΩΝ
    usr-local-ΕΨΗΕΛΩΝ over 8 years
    Not the same exact problem: I have error 406 when submitting form and success when submitting JSON. However, before I debugged with code from Spring, I did not understand that the request entity must someway implement MultiValueMap in order to work with FormHttpMessageConverter. So now I am starting to think that either the OP's FormDataObject implements that interface or else I am having the same problem as the OP but adding that converter doesn't work. And by the way I am using Spring 4.2
  • Qianyue
    Qianyue over 8 years
    @usr-local-ΕΨΗΕΛΩΝ I suggest you to ask a new question for your problem, in this comment, not enough information is provided.
  • Sidney de Moraes
    Sidney de Moraes about 7 years
    Using FormHttpMessageConverter means I cannot bind the form to a custom Object? It will always convert to MultiValueMap?
  • Qianyue
    Qianyue about 7 years
    @SidneydeMoraes, it should be that case. But you can convert the MultiValueMap to Object by yourself.