springboot中的序列化与反序列化有一个相对比较复杂的转换过程,它主要是HTTP请求、响应的信息类型转换,包含编码、信息类型、信息转换器、注解方法的处理适配器、请求接收的信息处理器等等。我们就先从大家常用的RequestBody和ResponseBody说起。
一、引入jackson:
小D在练习搭建springMvc框架时,遇到一个Controller接收实体参数问题:method为post,content-type为application/json; charset=utf-8的http请求,Controller接收
是@RequestBody ,但无法序列化为Object类型,其它类型却可以,并且报415错误Unsupported Media Type,可以排除注解未开启、请求内容类型不一致问题,那么最有可能是jackson包没引用或者与spring版本号不一致。Spring5.x引用jackson 2.9版本,Spring4.x引用jackson 2.6,Spring3.x引用jackson 1.9版本都是可以的。
二、RequestBody 中到的处理适配器:
老L目前公司用的框架为springboot-1.0,对应的jackson为2.8。打开@RequestBody,里有个很重要的提示@see …
* @author Arjen Poutsma
* @since 3.0
* @see RequestHeader
* @see ResponseBody
* @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
* @see org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestBody {
这个版本里,RequestMappingHandlerAdapter代替了
AnnotationMethodHandlerAdapter,它主要是处理请求和响应,在项目启动时会执行它的构造函数,初始化默认的HttpMessageConverter(核心的转换器),再执行WebMvcConfiguraionSupport类里的createRequestMappingHandlerAdapter去创建请求的处理器,并去执行下面的注入方法
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
adapter.setContentNegotiationManager(mvcContentNegotiationManager());
adapter.setMessageConverters(getMessageConverters());
adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
adapter.setCustomArgumentResolvers(getArgumentResolvers());
其中getMessageConverters里的configureMessageConverters为添加转换器。
三、添加信息转换器的几种方式:
1. 注解Bean形式:
// 这样做springboot会把我们自定义的converter放在顺序上的最高优先级(List的头部)
// 即有多个converter都满足Accpet/ContentType/MediaType的规则时,优先使用我们这个
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){
return new MappingJackson2HttpMessageConverter();
}
2. springboot通过继承WebMvcConfigurerAdapter,重写configureMessageConverters。
(Spring3.x 用MappingJacksonHttpMessageConverter
Spring4.x 用MappingJackson2HttpMessageConverter)
// 通常在只有一个自定义WebMvcConfigurerAdapter时,会把这个方法里面添加的converter(s)依次放在最高优先级(List的头部)
// 虽然第一种方式的代码先执行,但是bean的添加比这种方式晚,所以方式二的优先级 大于 方式一
@Configuration
@EnableWebMvc
public class WebMvcConfigure extends WebMvcConfigurerAdapter {
@Override
public void configureMessageConverters(List> converters){
MappingJackson2HttpMessageConverter mjhmc=new MappingJackson2HttpMessageConverter(objectMapper());
converters.add(mjhmc);
}
@Bean
public ObjectMapper objectMapper(){
ObjectMapper om= Jackson2ObjectMapperBuilder.json().build();
om.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE,ToStringSerializer.instance);
simpleModule.addSerializer(SwordsAbstractModel.class,new CustomerJpaModelSerializer());
om.registerModule(simpleModule);
return om;
}
}
并且针对项目对ObjectMapper自定义配置,反序列化时禁止对忽略的属性和未知的属性报错,以及对没有匹配的属性名称时不作失败处理(MapperFeature.AUTO_DETECT_FIELDS) 等等。
SimpleModule则在序列化和反序列化的情况下,才会使用其规则。截图中是在序列化时将Long类型转化为String类型。而下面这种写法可以用注解来代替
simpleModule.addSerializer(SwordsAbstractModel.class,new CustomerJpaModelSerializer());
@JsonSerialize(
using = CustomerJpaModelSerializer.class
)
public abstract class SwordsAbstractModel implements Serializable {
还有许多Json的注解可以简便配置,给大家提供个链接
https://blog.csdn.net/tanga842428/article/details/79201937
3. extendMessageConverters方式:
// 添加converter的第三种方式
// 同一个WebMvcConfigurerAdapter中的configureMessageConverters方法先于extendMessageConverters方法执行
// 可以理解为是三种方式中最后执行的一种,不过这里可以通过add指定顺序来调整优先级,也可以使用remove/clear来删除converter,功能强大
// 使用converters.add(xxx)会放在最低优先级(List的尾部)
// 使用converters.add(0,xxx)会放在最高优先级(List的头部)
@Override
public void extendMessageConverters(List> converters) {
converters.add(new MappingJackson2HttpMessageConverter());
}
以上简单讲述了项目运行时jackson解析原理。
四、Http请求处理器:
具体Http请求是通过RequestResponseBodyMethodProcessor类去处理的,接收请求是通过readWithMessageConverters方法,其核心还是通过之前配置的HttpMessageConverter进行数据转换为对象。如果返回请求为**@ResponseBody**,则会调用该类里handleReturnValue方法,将对象转换为相应的信息。
欢迎大家可以关注我,联系我进行技术讨论。