一:背景
自己有两个项目,一个项目中使用@RequestBody
注解是有效的,而另一个项目中无效,一直报异常:
2021-04-07 18:56:48.483 WARN 11484 --- [io-8288-exec-10] .[org.springframework.web.HttpMediaTypeNotSupportedException:
Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported]
网上找到的解决办法大都是说依赖未添加正确,还有其他一些办法都没有有效的解决问题。无果之后自己从源码入手,找到了出问题的原因。
二:如何使用@RequestBody注解
1.前端传递参数时需设置数据类型为applicaition/json
格式,如果使用的是axios
,代码如下所示
axios({
method: 'post',
headers: {
'Content-Type': 'application/json'
},
url: 'http://localhost:8288/test',
data: {name: 'zhangsan',age:10},
}).then(res => {});
2.后端使用@RequestBody
注解接收,代码如下所示:
@RequestMapping("/test")
public String test(@RequestBody User user){
return "success";
}
3.springboot
默认添加了jackson
依赖,不需要我们进行额外的引入,网上很多解决办法说需要引入该依赖。。
三: @RequestBody注解无效、后台报异常的原因
项目中出现@RequestBody
注解无效的情况后,首先检查了前端是否设置了正确的'Content-Type': 'application/json'
,然后检查了后端是否使用正确的方式接收。经确定,两者都是正确的。经过百度问题无法解决后,从源码入手找到了问题的原因:自己配置文件中的一段代码覆盖了springboot
默认加载的配置。如下图代码所示:
public class MyWebConfig extends WebMvcConfigurationSupport {
@Bean
public HttpMessageConverter responseBodyConverter(){
//解决返回值中文乱码
StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
return converter;
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(responseBodyConverter());
}
}
上述代码是在网上百度到的一段解决请求返回中文乱码的代码。在看了官方的注释文档之后发现该代码会springboot
默认加载的默认转换器。原文如下:
/**
* Override this method to add custom {@link HttpMessageConverter HttpMessageConverters}
* to use with the {@link RequestMappingHandlerAdapter} and the
* {@link ExceptionHandlerExceptionResolver}.
* <p>Adding converters to the list turns off the default converters that would
* otherwise be registered by default. Also see {@link #addDefaultHttpMessageConverters}
* for adding default message converters.
* @param converters a list to add message converters to (initially an empty list)
*/
这段话的大致意思就是覆盖configureMessageConverters
这个方法会导致springboot
默认的converters(数据转换器)
关闭,只保留我在代码中添加的StringHttpMessageConverter
这个转换器。
很明显可以看出,它只支持String
类型转换,不支持json
,这就是问题出现的原因。那么如何解决该问题呢:经查看源码,还有一个方法可以将默认的转换器添加进去,代码如下:
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(responseBodyConverter());
//加载默认的数据转换器至转换器列表中
super.addDefaultHttpMessageConverters(converters);
}
我们查看addDefaultHttpMessageConverters
这个方法的内容:
protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
messageConverters.add(new ByteArrayHttpMessageConverter());
messageConverters.add(new StringHttpMessageConverter());
messageConverters.add(new ResourceHttpMessageConverter());
messageConverters.add(new ResourceRegionHttpMessageConverter());
if (!shouldIgnoreXml) {
try {
messageConverters.add(new SourceHttpMessageConverter<>());
}
catch (Throwable ex) {
// Ignore when no TransformerFactory implementation is available...
}
}
messageConverters.add(new AllEncompassingFormHttpMessageConverter());
if (romePresent) {
messageConverters.add(new AtomFeedHttpMessageConverter());
messageConverters.add(new RssChannelHttpMessageConverter());
}
if (!shouldIgnoreXml) {
if (jackson2XmlPresent) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.xml();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.build()));
}
else if (jaxb2Present) {
messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
}
if (kotlinSerializationJsonPresent) {
messageConverters.add(new KotlinSerializationJsonHttpMessageConverter());
}
if (jackson2Present) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}
else if (gsonPresent) {
messageConverters.add(new GsonHttpMessageConverter());
}
else if (jsonbPresent) {
messageConverters.add(new JsonbHttpMessageConverter());
}
if (jackson2SmilePresent) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.smile();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2SmileHttpMessageConverter(builder.build()));
}
if (jackson2CborPresent) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.cbor();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2CborHttpMessageConverter(builder.build()));
}
}
可以发现,这个方法添加的许多类型转换器,其中的MappingJackson2HttpMessageConverter
这个就是我们需要的json
转换器,查看这个类可以发现,它的注释文档中有以下一段话:
/**
* Implementation of {@link org.springframework.http.converter.HttpMessageConverter} that can read and
* write JSON using <a href="https://github.com/FasterXML/jackson">Jackson 2.x's</a> {@link ObjectMapper}.
*
* <p>This converter can be used to bind to typed beans, or untyped {@code HashMap} instances.
*
* <p>By default, this converter supports {@code application/json} and {@code application/*+json}
* with {@code UTF-8} character set. This can be overridden by setting the
* {@link #setSupportedMediaTypes supportedMediaTypes} property.
*
*/
大概意思就是它支持json
类型的数据在转换。