Spring MVC@RequestBody处理JSONObject失效,Spring Boot正常的原因排查
为什么Spring MVC会报错,Spring Boot却正常?
这个差异本质上是消息转换器的配置和依赖环境不同导致的:
1. Spring MVC的问题根源
你的纯Spring MVC项目中,只引入了com.googlecode.json-simple:json-simple依赖,没有添加Jackson相关的JSON处理依赖。Spring MVC默认不会自动注册处理application/json类型的核心转换器MappingJackson2HttpMessageConverter,同时也没有其他内置转换器能直接将请求的JSON字符串转换为json-simple的JSONObject。
当Spring MVC接收到Content-Type: application/json的请求,却找不到能将请求体转换为JSONObject类型的转换器时,就会抛出HttpMediaTypeNotSupportedException异常。
2. Spring Boot能正常运行的原因
Spring Boot的spring-boot-starter-web依赖默认包含了Jackson的jackson-databind库,并且会自动配置MappingJackson2HttpMessageConverter作为JSON处理的核心转换器。
而json-simple的JSONObject类继承自HashMap且拥有默认构造函数,Jackson的ObjectMapper可以自动将JSON请求体反序列化为JSONObject实例,因此你的代码在Spring Boot环境下可以正常工作。
为什么改成@RequestBody String就能正常工作?
Spring MVC默认注册了StringHttpMessageConverter,这个转换器支持处理application/json类型的请求体,它会直接将请求中的JSON字符串原封不动地转换为String对象,所以切换成String参数时不会有问题。
你可以选择以下两种方式解决这个问题:
方式一:引入Jackson依赖并配置消息转换器
- 在Maven中添加Jackson依赖(版本选择与Spring 5.2.7.RELEASE兼容的版本,比如2.12.3):
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.3</version> </dependency>
- 在Spring MVC的配置类中注册
MappingJackson2HttpMessageConverter(如果没有自动注册的话):
@Configuration @EnableWebMvc public class WebMvcConfig implements WebMvcConfigurer { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { converters.add(new MappingJackson2HttpMessageConverter()); // 保留默认的转换器(比如StringHttpMessageConverter) WebMvcConfigurer.super.configureMessageConverters(converters); } }
方式二:自定义消息转换器处理json-simple的JSONObject
如果你不想引入Jackson,可以专门写一个转换器来处理json-simple的JSONObject:
- 自定义消息转换器类:
public class JsonSimpleHttpMessageConverter extends AbstractHttpMessageConverter<JSONObject> { public JsonSimpleHttpMessageConverter() { super(MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON_UTF8); } @Override protected boolean supports(Class<?> clazz) { return JSONObject.class.isAssignableFrom(clazz); } @Override protected JSONObject readInternal(Class<? extends JSONObject> clazz, HttpInputMessage inputMessage) throws IOException { String jsonStr = StreamUtils.copyToString(inputMessage.getBody(), StandardCharsets.UTF_8); return (JSONObject) JSONValue.parse(jsonStr); } @Override protected void writeInternal(JSONObject jsonObject, HttpOutputMessage outputMessage) throws IOException { String jsonStr = jsonObject.toJSONString(); outputMessage.getBody().write(jsonStr.getBytes(StandardCharsets.UTF_8)); } }
- 在WebMvc配置类中注册这个转换器:
@Configuration @EnableWebMvc public class WebMvcConfig implements WebMvcConfigurer { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { converters.add(new JsonSimpleHttpMessageConverter()); WebMvcConfigurer.super.configureMessageConverters(converters); } }
内容的提问来源于stack exchange,提问作者hcm64994

