SpringBoot@RequestBody报错('application/xwwwformurlencoded;charset=UTF8'notsupported)

coding

第一种:转https://blog.csdn.net/chenfei2341/article/details/83652586

在Spring boot 中使用 @RequestBody 会报错,提示错误 Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported,代码如下:

@RequestMapping(value = "/act/service/model/{modelId}/save", method = RequestMethod.POST)

publicvoid saveModel(@PathVariable String modelId, @RequestBody MultiValueMap<String, String> values) {

// 具体代码

}

这个在传统 spring MVC 中是有效的,但是在 Spring boot 中会报错。
传统是 Spring MVC 有效,是因为有 <mvc:annotation-driven> 注解,查资料,<mvc:annotation-driven> 注解配置了如下的内容
spring 3.1 版本:

<!-- 注解请求映射  -->

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">

<property name="interceptors">

<list>

<ref bean="logNDCInteceptor"/> <!-- 日志拦截器,这是你自定义的拦截器 -->

</list>

</property>

</bean>

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">

<property name="messageConverters">

<list>

<ref bean="byteArray_hmc" />

<ref bean="string_hmc" />

<ref bean="resource_hmc" />

<ref bean="source_hmc" />

<ref bean="xmlAwareForm_hmc" />

<ref bean="jaxb2RootElement_hmc" />

<ref bean="jackson_hmc" />

</list>

</property>

</bean>

<bean id="byteArray_hmc" class="org.springframework.http.converter.ByteArrayHttpMessageConverter" /><!-- 处理.. -->

<bean id="string_hmc" class="org.springframework.http.converter.StringHttpMessageConverter" /><!-- 处理.. -->

<bean id="resource_hmc" class="org.springframework.http.converter.ResourceHttpMessageConverter" /><!-- 处理.. -->

<bean id="source_hmc" class="org.springframework.http.converter.xml.SourceHttpMessageConverter" /><!-- 处理.. -->

<bean id="xmlAwareForm_hmc" class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter" /><!-- 处理.. -->

<bean id="jaxb2RootElement_hmc" class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter" /><!-- 处理.. -->

<bean id="jackson_hmc" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" /><!-- 处理json-->

转载:http://elf8848.iteye.com/blog/875830
这个找到的资料是 3.1 的,但是women可以看到,最后一个配置了 Jackson 的 json 处理程序,在更新的版本中,AnnotationMethodHandlerAdapter 已经废弃,使用的是 RequestMappingHandlerAdapter,看下 RequestMappingHandlerAdapter 的源码。

public RequestMappingHandlerAdapter() {

StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();

stringHttpMessageConverter.setWriteAcceptCharset(false); // see SPR-7316

this.messageConverters = new ArrayList<HttpMessageConverter<?>>(4);

this.messageConverters.add(new ByteArrayHttpMessageConverter());

this.messageConverters.add(stringHttpMessageConverter);

this.messageConverters.add(new SourceHttpMessageConverter<Source>());

this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());

}

这里面没有了 json 的处理过程,我们把它加上

@EnableWebMvc

@Configuration

publicclass WebMvcConfig extends WebMvcConfigurerAdapter {

@Bean

public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {

RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();

List<HttpMessageConverter<?>> converters = adapter.getMessageConverters();

MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();

List<MediaType> supportedMediaTypes = new ArrayList<MediaType>();

MediaType textMedia = new MediaType(MediaType.TEXT_PLAIN, Charset.forName("UTF-8"));

supportedMediaTypes.add(textMedia);

MediaType jsonMedia = new MediaType(MediaType.APPLICATION_JSON, Charset.forName("UTF-8"));

supportedMediaTypes.add(jsonMedia);jsonConverter.setSupportedMediaTypes(supportedMediaTypes);

converters.add(jsonConverter);

adapter.setMessageConverters(converters);

return adapter;

}

}

成功,报错消除,正确获取到了参数

第二种 转自https://blog.csdn.net/justry_deng/article/details/99875548

SpringBoot自定义参数解析器,使被@RequestBody标注的参数能额外接收Content-Type为application/x-www-form-urlencoded的请求

基础知识介绍:
       在SpringBoot里,若Controller层里方法的形参前使用了@RequestBody注解,那么该参数将会被RequestResponseBodyMethodProcessor解析器进行解析,若此时Content-Type为application/x-www-form-urlencoded,那么会报Unsupported Media Type错误,这就要求:请求的Content-Type必须为application/json了。

       一般的,若Controller层里方法的形参前(不管有没有其它注解,只要)没使用@RequestBody注解,那么该参数几乎都是符合ServletModelAttributeMethodProcessor解析器要求的,进而会使用ServletModelAttributeMethodProcessor解析器进行解析;当请求的Content-Type为application/x-www-form-urlencoded时,几乎用的都是ServletModelAttributeMethodProcessor解析器。

注:参数符合RequestResponseBodyMethodProcessor解析器要求的条件是
       parameter.hasParameterAnnotation(RequestBody.class)。可详见
       RequestResponseBodyMethodProcessor类源码。

注:参数符合ServletModelAttributeMethodProcessor解析器要求的条件是
       parameter.hasParameterAnnotation(ModelAttribute.class) ||
       this.annotationNotRequired && !BeanUtils.isSimpleProperty(parameter.getParameterType())。
       可详见ModelAttributeMethodProcessor类源码。

需求介绍及实现方式说明:
声明:本文通过实现下述需求,进行示例。

需求介绍:

       实现被@RequestBody注解的参数,既能接收Content-Type为application/json的请求的参数值,又能接收Content-Type为application/x-www-form-urlencoded的请求的参数值。

实现方式概述:

       自定义参数解析器,当参数前有@RequestBody时,使用该解析器;在该解析器的内部,判断Content-Type,若Content-Type为application/x-www-form-urlencoded,那么采用ServletModelAttributeMethodProcessor解析器;否者采用RequestResponseBodyMethodProcessor解析器。

注:即相当于对RequestResponseBodyMethodProcessor解析器进行了简单的封装。

具体实现代码示例:

自定义参数解析器:

import org.springframework.core.MethodParameter;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.support.WebDataBinderFactory;

import org.springframework.web.context.request.NativeWebRequest;

import org.springframework.web.method.support.HandlerMethodArgumentResolver;

import org.springframework.web.method.support.ModelAndViewContainer;

import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;

import org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor;

import javax.servlet.http.HttpServletRequest;

/**

* 自定义参数解析器

*

* 注: 自定义参数解析器, 实现对RequestResponseBodyMethodProcessor的扩展

*

* 提示: 此解析器要实现的功能是: 若controller方法的参数前, 使用了@RequestBody注解, 那么解析此参数时,

* 1、若Content-Type为application/x-www-form-urlencoded,

* 那么走ServletModelAttributeMethodProcessor解析器

* 2、若Content-Type不为application/x-www-form-urlencoded,

* 那么走本应该走的RequestResponseBodyMethodProcessor解析器

*

* @author JustryDeng

* @date 2019/8/19 19:47

*/

publicclass MyHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {

/**

* 解析Content-Type为application/json的默认解析器是RequestResponseBodyMethodProcessor

*/

private RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor;

/**

* 解析Content-Type为application/x-www-form-urlencoded的默认解析器是ServletModelAttributeMethodProcessor

*/

private ServletModelAttributeMethodProcessor servletModelAttributeMethodProcessor;

/**

* 全参构造

*/

public MyHandlerMethodArgumentResolver(RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor,

ServletModelAttributeMethodProcessor servletModelAttributeMethodProcessor) {

this.requestResponseBodyMethodProcessor = requestResponseBodyMethodProcessor;

this.servletModelAttributeMethodProcessor = servletModelAttributeMethodProcessor;

}

/**

* 当参数前有@RequestBody注解时, 解析该参数 会使用此 解析器

*

* 注:此方法的返回值将决定:是否使用此解析器解析该参数

*/

@Override

publicboolean supportsParameter(MethodParameter methodParameter) {

return methodParameter.hasParameterAnnotation(RequestBody.class);

}

/**

* 解析参数

*/

@Override

public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,

NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory)

throws Exception {

final String applicationXwwwFormUrlencoded = "application/x-www-form-urlencoded";

HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);

if (request == null) {

thrownew RuntimeException(" request must not be null!");

}

String contentType = request.getContentType();

/*

* 如果ContentType是application/x-www-form-urlencoded,那么使用ServletModelAttributeMethodProcessor解析器

*

* 注:其实默认的,当系统识别到参数前有@RequestBody注解时,就会走RequestResponseBodyMethodProcessor解析器;这里就

* 相当于在走默认的解析器前走了个判断而已。

*/

if (applicationXwwwFormUrlencoded.equals(contentType)) {

return servletModelAttributeMethodProcessor.resolveArgument(methodParameter,

modelAndViewContainer, nativeWebRequest, webDataBinderFactory);

}

return requestResponseBodyMethodProcessor.resolveArgument(methodParameter,

modelAndViewContainer, nativeWebRequest, webDataBinderFactory);

}

}

注册该参数解析器:

import org.springframework.context.annotation.Configuration;

import org.springframework.web.method.support.HandlerMethodArgumentResolver;

import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;

import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;

import org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor;

import javax.annotation.PostConstruct;

import java.util.ArrayList;

import java.util.List;

/**

* 配置注册参数解析器

*

* @author JustryDeng

* @date 2019/8/20 10:13

*/

@Configuration

publicclass ConfigArgumentResolvers {

privatefinal RequestMappingHandlerAdapter requestMappingHandlerAdapter;

public ConfigArgumentResolvers(RequestMappingHandlerAdapter requestMappingHandlerAdapter) {

this.requestMappingHandlerAdapter = requestMappingHandlerAdapter;

}

@PostConstruct

privatevoid addArgumentResolvers() {

// 获取到的是不可变的集合

List<HandlerMethodArgumentResolver> argumentResolvers =

requestMappingHandlerAdapter.getArgumentResolvers();

MyHandlerMethodArgumentResolver myHandlerMethodArgumentResolver =

getMyHandlerMethodArgumentResolver(argumentResolvers);

// ha.getArgumentResolvers()获取到的是不可变的集合,所以我们需要新建一个集合来放置参数解析器

List<HandlerMethodArgumentResolver> myArgumentResolvers =

new ArrayList<>(argumentResolvers.size() + 1);

// 将自定义的解析器,放置在第一个; 并保留原来的解析器

myArgumentResolvers.add(myHandlerMethodArgumentResolver);

myArgumentResolvers.addAll(argumentResolvers);

requestMappingHandlerAdapter.setArgumentResolvers(myArgumentResolvers);

}

/**

* 获取MyHandlerMethodArgumentResolver实例

*/

private MyHandlerMethodArgumentResolver getMyHandlerMethodArgumentResolver(

List<HandlerMethodArgumentResolver> argumentResolversList) {

// 解析Content-Type为application/json的默认解析器

RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor = null;

// 解析Content-Type为application/x-www-form-urlencoded的默认解析器

ServletModelAttributeMethodProcessor servletModelAttributeMethodProcessor = null;

if (argumentResolversList == null) {

thrownew RuntimeException("argumentResolverList must not be null!");

}

for (HandlerMethodArgumentResolver argumentResolver : argumentResolversList) {

if (requestResponseBodyMethodProcessor != null && servletModelAttributeMethodProcessor != null) {

break;

}

if (argumentResolver instanceof RequestResponseBodyMethodProcessor) {

requestResponseBodyMethodProcessor = (RequestResponseBodyMethodProcessor)argumentResolver;

continue;

}

if (argumentResolver instanceof ServletModelAttributeMethodProcessor) {

servletModelAttributeMethodProcessor = (ServletModelAttributeMethodProcessor)argumentResolver;

}

}

if (requestResponseBodyMethodProcessor == null || servletModelAttributeMethodProcessor == null) {

thrownew RuntimeException("requestResponseBodyMethodProcessor and "

+ " servletModelAttributeMethodProcessor must not be null!");

}

returnnew MyHandlerMethodArgumentResolver(requestResponseBodyMethodProcessor,

servletModelAttributeMethodProcessor);

}

以上是 SpringBoot@RequestBody报错(&#039;application/xwwwformurlencoded;charset=UTF8&#039;notsupported) 的全部内容, 来源链接: utcz.com/z/509128.html

回到顶部