Http Post with request content type form not working in Spring MVC 3

Bobo picture Bobo · Dec 2, 2010 · Viewed 98.8k times · Source

code snippet:

@RequestMapping(method = RequestMethod.POST)//,  headers = "content-type=application/x-www-form-urlencoded")
public ModelAndView create(@RequestBody UserAccountBean account) {
    try{
        accounts.put(account.assignId(), account);
    }catch(RuntimeException ex)
    {
        return new ModelAndView("account/registerError");
    }
    return new ModelAndView("account/userVerification");
}

After receiving request, What I got is Http Status code 415: The server refused this request because the request entity is in a format not supported by the requested resource for the requested method ().

If I change the code to this:

code snippet:

@RequestMapping(method = RequestMethod.POST,headers = "content-type=application/x-www-form-urlencoded")
public ModelAndView create(@RequestBody UserAccountBean account) {
    try{
        accounts.put(account.assignId(), account);
    }catch(RuntimeException ex)
    {
        return new ModelAndView("account/registerError");
    }
    return new ModelAndView("account/userVerification");
}

I will get 405 Method not allowed. Funny thing is in the allow header of response, it lists GET and POST as allowed methods.

I do have a class that does JOSN mapping:

@Component
public class JacksonConversionServiceConfigurer implements BeanPostProcessor {

private final ConversionService conversionService;

@Autowired
public JacksonConversionServiceConfigurer(ConversionService conversionService) {
    this.conversionService = conversionService;
}

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    return bean;
}

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if (bean instanceof AnnotationMethodHandlerAdapter) {
        AnnotationMethodHandlerAdapter adapter = (AnnotationMethodHandlerAdapter) bean;
        HttpMessageConverter<?>[] converters = adapter.getMessageConverters();
        for (HttpMessageConverter<?> converter : converters) {
            if (converter instanceof MappingJacksonHttpMessageConverter) {
                MappingJacksonHttpMessageConverter jsonConverter = (MappingJacksonHttpMessageConverter) converter;
                jsonConverter.setObjectMapper(new ConversionServiceAwareObjectMapper(this.conversionService));
            }               
        }
    }
    return bean;
}

}

Copied from Spring examples. works great with JSON content-type.

A more general question is how to make spring mvc request handlers work with different request content-types. Any advice would be greatly appreciated.

Answer

axtavt picture axtavt · Dec 2, 2010

Unfortunately FormHttpMessageConverter (which is used for @RequestBody-annotated parameters when content type is application/x-www-form-urlencoded) cannot bind target classes (as @ModelAttribute can).

Therefore you need @ModelAttribute instead of @RequestBody. If you don't need to pass different content types to that method you can simply replace the annotation:

@RequestMapping(method = RequestMethod.POST)
public ModelAndView create(@ModelAttribute UserAccountBean account) { ... }

Otherwise I guess you can create a separate method form processing form data with the appropriate headers attribute:

@RequestMapping(method = RequestMethod.POST, 
    headers = "content-type=application/x-www-form-urlencoded") 
public ModelAndView createFromForm(@ModelAttribute UserAccountBean account) { ... }

EDIT: Another possible option is to implement your own HttpMessageConverter by combining FormHttpMessageConverter (to convert input message to the map of parameters) and WebDataBinder (to convert map of parameters to the target object).