Spring mvc 请求内容类型为表单的Http Post在Spring MVC 3中不起作用

Spring mvc 请求内容类型为表单的Http Post在Spring MVC 3中不起作用,spring-mvc,content-type,Spring Mvc,Content Type,代码段: @RequestMapping(method = RequestMethod.POST)//, headers = "content-type=application/x-www-form-urlencoded") public ModelAndView create(@RequestBody UserAccountBean account) { try{ accounts.put(account.assignId(), account); }catc

代码段:

@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");
}
@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");
}
收到请求后,我得到的是Http状态码415: 服务器拒绝了此请求,因为请求实体的格式不受请求方法()的请求资源的支持

如果我将代码更改为:

代码段:

@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");
}
@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");
}
我将得到405方法不允许。有趣的是在响应的allow头中,它列出了GET和POST作为允许的方法

我有一个类可以进行JOSN映射:

@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;
}

}
@组件
公共类JacksonConversionServiceConfigure实现BeanPostProcessor{
私有最终转换服务转换服务;
@自动连线
公共JacksonConversionService配置器(转换服务转换服务){
this.conversionService=conversionService;
}
公共对象后处理BeforeInitialization(对象bean、字符串beanName)抛出BeanException{
返回豆;
}
公共对象后处理初始化后(对象bean、字符串beanName)抛出BeansException{
if(AnnotationMethodHandlerAdapter的bean实例){
AnnotationMethodHandlerAdapter=(AnnotationMethodHandlerAdapter)bean;
HttpMessageConverter[]converters=adapter.getMessageConverters();
用于(HttpMessageConverter转换器:转换器){
if(映射JacksonHttpMessageConverter的转换器实例){
MappingJacksonHttpMessageConverter jsonConverter=(MappingJacksonHttpMessageConverter)转换器;
jsonConverter.setObjectMapper(新的ConversionServiceWareObjectMapper(this.conversionService));
}               
}
}
返回豆;
}
}
复制自Spring示例。非常适合JSON内容类型

一个更普遍的问题是如何使SpringMVC请求处理程序处理不同的请求内容类型。
如有任何建议,将不胜感激

不幸的是
FormHttpMessageConverter
(当内容类型为
应用程序/x-www-form-urlencoded
时用于
@RequestBody
-带注释的参数)无法绑定目标类(正如
@modeldattribute
可以绑定的那样)

因此,您需要
@modeldattribute
而不是
@RequestBody
。如果不需要将不同的内容类型传递给该方法,只需替换注释即可:

@RequestMapping(method = RequestMethod.POST)
public ModelAndView create(@ModelAttribute UserAccountBean account) { ... }
否则,我想您可以创建一个单独的方法表单,使用适当的
headers
属性处理表单数据:

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

编辑:另一种可能的选择是通过组合
FormHttpMessageConverter
(将输入消息转换为参数映射)和
WebDataBinder
(将参数映射转换为目标对象)来实现您自己的
HttpMessageConverter
.

使用@modeldattribute确实是处理表单参数的首选方法。

我的HTTP响应代码是415

当我将内容类型添加到请求头时,我的问题得到了解决

e、 g


“Content-Type:application/json”

使用json对我来说也很有效,我想它会让json解释器从主体中获取数据。 我试着用PUT,这有点难。 你可以阅读我的帖子。

下面的文章为我工作

在服务器端:

 @RequestMapping(value = "test", method = RequestMethod.POST, consumes = {"application/xml", "application/json"})
        @ResponseStatus(HttpStatus.OK)
        public @ResponseBody
        String methodName(@RequestBody EntityClassName entity) {
在客户端:

String json = new JSONStringer().object()
                        .key("key").value("value")
                        .endObject()
                        .toString();
StringEntity se = new StringEntity(json);
se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
request.setEntity(se);
HttpResponse response = client.execute(request);

问题的核心是,我们希望使用相同的请求处理程序接受application/json和application/x-www-form-urlencoded内容类型

为此,我使用@RequestBody,它已经在为我的application/json工作(通常还有我找到的线程中的其他线程),但是还有额外的工作,因此application/x-www-form-urlencoded可以与@RequestBody一起使用

首先,创建一个能够将请求输入更改为对象的新HttpMessageConverter。我通过重用FormHttpMessageConverter来实现这一点,FormHttpMessageConverter已经能够将输入更改为多值映射。然后,我将多值映射更改为常规映射,并使用Jackson将映射转换为所需的对象

以下是HttpMessageConverter的代码:

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * <p>Converts HTTP requests with bodies that are application/x-www-form-urlencoded or multipart/form-data to an Object
 * annotated with {@link org.springframework.web.bind.annotation.RequestBody} in the the handler method.
 *
 * @author Jesse Swidler
 */
public class ObjectHttpMessageConverter implements HttpMessageConverter<Object> {

    private final FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter();
    private final ObjectMapper objectMapper = new ObjectMapper();

    private static final LinkedMultiValueMap<String, String> LINKED_MULTI_VALUE_MAP = new LinkedMultiValueMap<>();
    private static final Class<? extends MultiValueMap<String, ?>> LINKED_MULTI_VALUE_MAP_CLASS
            = (Class<? extends MultiValueMap<String, ?>>) LINKED_MULTI_VALUE_MAP.getClass();

    @Override
    public boolean canRead(Class clazz, MediaType mediaType) {
        return objectMapper.canSerialize(clazz) && formHttpMessageConverter.canRead(MultiValueMap.class, mediaType);
    }

    @Override
    public boolean canWrite(Class clazz, MediaType mediaType) {
        return false;
    }

    @Override
    public List<MediaType> getSupportedMediaTypes() {
        return formHttpMessageConverter.getSupportedMediaTypes();
    }

    @Override
    public Object read(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        Map<String, String> input = formHttpMessageConverter.read(LINKED_MULTI_VALUE_MAP_CLASS, inputMessage).toSingleValueMap();
        return objectMapper.convertValue(input, clazz);
    }

    @Override
    public void write(Object o, MediaType contentType, HttpOutputMessage outputMessage) throws UnsupportedOperationException {
        throw new UnsupportedOperationException("");
    }
}
import com.fasterxml.jackson.databind.ObjectMapper;
导入org.springframework.http.HttpInputMessage;
导入org.springframework.http.HttpOutputMessage;
导入org.springframework.http.MediaType;
导入org.springframework.http.converter.FormHttpMessageConverter;
导入org.springframework.http.converter.HttpMessageConverter;
导入org.springframework.http.converter.httpmessagenoteradableexception;
导入org.springframework.util.LinkedMultiValueMap;
导入org.springframework.util.MultiValueMap;
导入java.io.IOException;
导入java.util.List;
导入java.util.Map;
/**
*将具有应用程序/x-www-form-urlencoded或多部分/form数据体的HTTP请求转换为对象
*在处理程序方法中使用{@link org.springframework.web.bind.annotation.RequestBody}进行注释。
*
*@作者杰西·斯威德勒
*/
公共类ObjectHttpMessageConverter实现HttpMessageConverter{
私有最终FormHttpMessageConverter FormHttpMessageConverter=新FormHttpMessageConverter();
私有最终ObjectMapper ObjectMapper=新ObjectMapper();
私有静态最终LinkedMultiValueMap LINKED_MULTI_VALUE_MAP=新LinkedMultiValueMap();
私有静态最终类>链接的多值映射类
=(类>)链接的多值映射。getClass();
@凌驾
公共布尔canRead(类clazz,MediaType-MediaType){
返回objectMapper.canSerialize(clazz)和&formHttpMessageConverter.canRead(MultiValueMap.class,mediaType);
}
@凌驾
公共布尔canWrite(类clazz,MediaType-MediaType){
返回false;
}
@凌驾
公共列表getSupportedMediaTypes(){
返回formHttpMessageConverter.getSupportedMediaTypes();
}
@凌驾
公共对象读取(类clazz,HttpInputMessage-inputMessage)引发IOException,HttpMessageGenetradableExc