@RequestBody 与 HttpMessageConverter、JSON 序列化
HTTP 请求体和响应体本质都是字节流。@RequestBody 负责把请求体反序列化成 Java 对象,@ResponseBody 负责把对象序列化成响应体,背后的执行者是 HttpMessageConverter。
一个注解看懂读写
@RestController
public class UserApi {
@PostMapping("/api/users")
public User create(@RequestBody User user) { // 读:JSON → User
user.setId(1L);
return user; // 写:User → JSON
}
}
// 请求体:{"name":"张三","age":20}
// 响应体:{"id":1,"name":"张三","age":20}
User 类只要提供无参构造、字段和 getter/setter 即可,字段名与 JSON key 对应。
HttpMessageConverter 是幕后的搬运工
MessageConverter 负责两种方向的转换:
public interface HttpMessageConverter<T> {
boolean canRead(Class<?> clazz, MediaType mediaType); // 能不能读这种类型/媒体类型
boolean canWrite(Class<?> clazz, MediaType mediaType); // 能不能写
T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException;
void write(T t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException;
}
- 读请求体:按请求的 Content-Type 挑转换器。application/json → Jackson(MappingJackson2HttpMessageConverter,类路径有 Jackson 且开了 @EnableWebMvc 时默认注册)。
- 写响应体:按客户端 Accept(经内容协商)挑转换器。
- 常见的还有 StringHttpMessageConverter(text/plain)、ByteArrayHttpMessageConverter、FormHttpMessageConverter(表单),默认注册清单以官方文档为准。
一个请求体对应一个 @RequestBody
一个方法只能有一个 @RequestBody 参数。整个请求体被反序列化成一个对象;要同时收 JSON 和文件请用 @RequestPart(第 31 章)。
自定义 JSON 行为:ObjectMapper
序列化规则由 Jackson 的 ObjectMapper 决定,例如日期格式、忽略未知字段:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
.featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_FIELDS);
converters.add(0, new MappingJackson2HttpMessageConverter(builder.build()));
}
}
// 说明:Spring Boot 对 Jackson 有独立自动配置,本文按原生 Spring MVC 处理
常见配套依赖:Jackson 本体是 jackson-databind;序列化 java.time 类型需 jackson-datatype-jsr310(JavaTimeModule,默认处理 LocalDate/LocalDateTime 等)。
写一个自定义 Converter
特殊格式(如 XML 之外的自定义协议)可以实现 HttpMessageConverter 并注册到 converters 列表首位。日常开发里更常见的是用 Gson:
// 依赖 Gson 时,Spring 提供了现成的 GsonHttpMessageConverter(gson 在类路径即可)
converters.add(0, new GsonHttpMessageConverter());
典型错误码
- 请求体不是合法 JSON / 类型对不上:HttpMessageNotReadableException,默认映射 400。
- 请求 Content-Type 没有可用转换器:HttpMediaTypeNotSupportedException(415)。
- 写响应时 Accept 无匹配媒体类型:HttpMediaTypeNotAcceptableException(406)。
@RequestBody/@ResponseBody 只是入口,真正的活是 HttpMessageConverter 干的。写接口时记住三点:对象要能被反序列化(无参构造 + setter)、日期格式先定好、Content-Type 与 Accept 要和转换器对得上。