Search code examples
spring-mvcrest-client

Spring controller with @RequestBody and @ModelAttribute for the same parameter


I want to create a controller method that can be called from html form or from a standalone client using resttemplate.

The method has this signature:

@RequestMapping(method = RequestMethod.POST)
public ModelAndView save(@RequestBody @ModelAttribute(value = "itemCreateRequest")
    ItemCreateRequest request, Model model) throws NoSuchMethodException,
    SecurityException, InstantiationException, IllegalAccessException,
    IllegalArgumentException, InvocationTargetException {
...
}

The problem is, that if I use the HTML form, everything works fine, but when I try to use the standalone client the values in the request parameter come in null.

ItemCreateRequest icr = new ItemCreateRequest();
icr.setItem(new ItemDTO(null, "23", "bla", "bla bla"));
restTemplate.postForLocation("http://localhost:8080/ims_ui/items.xml", icr);

If I try the method without the @ModelAttribute the standalone client works but the HTML form not.

This is the configuration of my servlet-context.xml

    <beans:bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
  <beans:bean id="handlerAdapter" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <beans:property name="messageConverters">
            <beans:list>
                <beans:bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
                    <beans:property name="marshaller" ref="marshaller"/>
                    <beans:property name="unmarshaller" ref="marshaller"/>
                </beans:bean>
                <beans:bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
                <beans:bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
            </beans:list>
        </beans:property>
    </beans:bean>

  <beans:bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <beans:property name="order" value="0" />
    <beans:property name="mediaTypes">
      <beans:map>
        <beans:entry key="jsp" value="application/html" />
        <beans:entry key="xml" value="application/xml" />
      </beans:map>
    </beans:property>

    <beans:property name="defaultViews">
      <beans:list>
        <!-- XML View -->
        <beans:bean class="org.springframework.web.servlet.view.xml.MarshallingView">
          <beans:constructor-arg ref="marshaller" />
        </beans:bean>
      </beans:list>
    </beans:property>
  </beans:bean>

  <beans:bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
    <beans:property name="contextPaths">
            <beans:array>
                <beans:value>net.franciscovillegas.summa.ims.dto</beans:value>
                <beans:value>net.franciscovillegas.summa.ims.service.requests</beans:value>
            </beans:array>
        </beans:property>
  </beans:bean>

Thanks in advance!


Solution

  • The answer is in you're post:

    If I try the method without the @ModelAttribute the standalone client works but the HTML form not.

    I think that, when you use the html application you send a request to the server with a map where all keys starts with itemCreateRequest.VARIABLE_NAME , but when you use stand alone application you send that request without the declared @ModelAttribute.

    The declared ModelAttribute, in you case "itemCreateRequest", should stand in front of each information sent to that controller.

    You can try something like this:

    restTemplate.postForLocation("http://localhost:8080/ims_ui/items.xml", new HashMap<String, Object>(){
                {
                    put("itemCreateRequest", icr);
                }
            });