springBoot的序列化与反序列化

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方法,将对象转换为相应的信息。


欢迎大家可以关注我,联系我进行技术讨论。

你可能感兴趣的:(技术,springboot,jackson,415,requestBody,原理)