Springboot 开发 -- 序列化与消息转换器

一、序列化与反序列化

1、认识序列化与反序列化

Java序列化是指把Java对象转换为字节序列的过程,而Java反序列化是指把字节序列恢复为Java对象的过程。

2、为什么要实现对象的序列化和反序列化?

(1)我们创建的Java对象被存储在Java堆中,当程序运行结束后,这些对象会被JVM回收。但在现实的应用中,可能会要求在程序运行结束之后还能读取这些对象,并在以后检索数据,这时就需要用到序列化。

(2)当Java对象通过网络进行传输的时候。因为数据只能够以二进制的形式在网络中进行传输,因此当把对象通过网络发送出去之前需要先序列化成二进制数据在接收端读到二进制数据之后反序列化成Java对象

二、Spring Boot中的序列化技术

Spring Boot 主要使用Jackson库来处理JSON的序列化和反序列化

1.引入 Jackson库 配置

<!--jackson-->
<dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId><!-- 注意版本应该与 Springboot版本匹配。看SpringBoot版本发布日期去Maven找对应的版本号 -->
</dependency>

当我们使用 spring-boot-starter-web 时,默认引入 jackson 库

2. Jackson ObjectMapper类配置

  1. ObjectMapper是Jackson中用于数据绑定的核心类。通过自定义ObjectMapper,我们可以控制序列化的行为:
ObjectMapper objectMapper = new ObjectMapper();
//去掉默认的时间戳格式     
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);//设置为东八区
objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));// 设置输入:禁止把POJO中值为null的字段映射到json字符串中
objectMapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);//空值不序列化
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);//反序列化时,属性不存在的兼容处理
objectMapper.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);//序列化时,日期的统一格式
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));//序列化日期时以timestamps输出,默认true
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);//序列化枚举是以toString()来输出,默认false,即默认以name()来输出
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING,true);//序列化枚举是以ordinal()来输出,默认false
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_INDEX,false);//类为空时,不要抛异常
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);//反序列化时,遇到未知属性时是否引起结果失败
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);//单引号处理
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);//解析器支持解析结束符
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
  1. 反序列化时陈列多余字段
    在默认情况下,如果Json数据中有多余的字段,那么在反序列化时Jackson发现无法找到对应的对象字段,便会抛出UnrecognizedPropertyException: Unrecognized field xxx异常,此时可以做如下配置:
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

3. 自定义序列化器和反序列化器

对于特殊的数据类型,可能需要自定义序列化器和反序列化器。通过实现JsonSerializer和JsonDeserializer接口,可以控制特定类型对象的序列化和反序列化过程。

配置 pojo 中 null 值转 空字符串示例:

  • 首先,你需要一个自定义的序列化器,用于处理 null 值的情况。以下是一个简单的例子,它使用了 JsonSerializer 来检查字段值,如果为 null,则写入空字符串:
import com.fasterxml.jackson.core.JsonGenerator;  
import com.fasterxml.jackson.databind.JsonSerializer;  
import com.fasterxml.jackson.databind.SerializerProvider;  
import java.io.IOException;  public class NullToEmptyStringSerializer extends JsonSerializer<Object> {  @Override  public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {  if (value == null) {  gen.writeString("");  } else {  // 默认序列化器处理非null值  serializers.defaultSerializeValue(value, gen);  }  }  
}
  • 上面的序列化器对于所有字段都使用相同的逻辑,这可能不是你想要的。你可能只想对某些字段进行此处理。为了实现这一点,你可以使用 @JsonSerialize 注解并指定你的自定义序列化器,如下所示:
import com.fasterxml.jackson.databind.annotation.JsonSerialize;  public class MyPojo {  private String field1;  @JsonSerialize(using = NullToEmptyStringSerializer.class)  private String field2; // 只有这个字段的null值会被转换为空字符串  // getters and setters  
}

4. 配置消息转换器的方式

  1. 注解 Bean 形式自定义消息转换器:
    可以通过实现Spring MVC中的HttpMessageConverter接口来创建自定义的消息转换器。但更常见的是,扩展或配置现有的消息转换器,如MappingJackson2HttpMessageConverter。
@Configuration  
public class WebConfig {  // 这样做springboot会把我们自定义的converter放在顺序上的最高优先级(List的头部)// 即有多个converter都满足Accpet/ContentType/MediaType的规则时,优先使用我们这个@Beanpublic MappingJackson2HttpMessageConverter  mappingJackson2HttpMessageConverter(){return new MappingJackson2HttpMessageConverter();}
}
  1. springboot通过继承WebMvcConfigurerAdapter,重写configureMessageConverters。
// 通常在只有一个自定义WebMvcConfigurerAdapter时,会把这个方法里面添加的converter(s)依次放在最高优先级(List的头部)
// 虽然第一种方式的代码先执行,但是bean的添加比这种方式晚,所以方式二的优先级 大于 方式一
@Configuration
@EnableWebMvc
public class WebMvcConfigure extends WebMvcConfigurerAdapter {@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters){MappingJackson2HttpMessageConverter convert = new MappingJackson2HttpMessageConverter(objectMapper());converters.add(convert);}@Beanpublic 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;}
}
  1. extendMessageConverters方式:

想要在不替换默认转换器的情况下添加或修改转换器,可以使用WebMvcConfigurer的extendMessageConverters方法。

@Configuration  
public class WebConfig implements WebMvcConfigurer {  @Override  public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {  for (int i = 0; i < converters.size(); i++) {  // 检查或修改现有的转换器  // 例如:如果找到MappingJackson2HttpMessageConverter,可以对其进行配置  }  // 也可以添加新的转换器  converters.add(new CustomHttpMessageConverter()); converters.add(new MappingJackson2HttpMessageConverter()); }  
}

5. 配置Jackson

如果主要关心的是JSON序列化和反序列化,可能不需要自定义整个HttpMessageConverter。相反,你可以配置默认的MappingJackson2HttpMessageConverter所使用的Jackson库。这可以通过在application.properties或application.yml中添加相关属性,或者通过编程方式配置ObjectMapper来实现。 例如,在application.properties中配置Jackson的日期格式:

spring.jackson.date-format=yyyy-MM-dd HH:mm:ss  
spring.jackson.time-zone=Asia/Shanghai

或者通过配置一个Jackson2ObjectMapperBuilderCustomizer bean来定制ObjectMapper:

@Configuration
public class JacksonConfig {@Beanpublic ObjectMapper objectMapper() {ObjectMapper mapper = new ObjectMapper();mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);mapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);// 其他配置...return mapper;}@Beanpublic MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();converter.setObjectMapper(objectMapper);return converter;}
}

三、 消息转换器 配置 Redis 序列化 实例

在 Redis 中,数据通常以字节(byte)的形式存储,因此当我们使用 Redis 客户端(如 Jedis、Lettuce 或 RedisTemplate 在 Spring Data Redis 中)时,我们需要配置序列化器(serializers)来将 Java 对象转换为字节,并在需要时从字节转换回 Java 对象。

在 Spring Data Redis 中,RedisTemplate 是与 Redis 进行交互的核心组件。为了配置消息转换器或序列化器,通常会设置 RedisTemplate 的 keySerializer、valueSerializer、hashKeySerializer 和 hashValueSerializer。

以下是一个配置 RedisTemplate 以使用 JSON 序列化的示例,这里我们使用 Jackson2JsonRedisSerializer 作为序列化器:

import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.data.redis.connection.RedisConnectionFactory;  
import org.springframework.data.redis.core.RedisTemplate;  
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;  
import org.springframework.data.redis.serializer.StringRedisSerializer;  import com.fasterxml.jackson.annotation.JsonAutoDetect;  
import com.fasterxml.jackson.annotation.PropertyAccessor;  
import com.fasterxml.jackson.databind.ObjectMapper;  @Configuration  
public class RedisConfig {  @Beanpublic RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<Object, Object> template = new RedisTemplate<>();// 配置连接工厂template.setConnectionFactory(factory);//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)Jackson2JsonRedisSerializer<Object> jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);ObjectMapper om = new ObjectMapper();// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和publicom.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常om.activateDefaultTyping( LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);// 空字段不序列化om.setDefaultPropertyInclusion(JsonInclude.Include.NON_NULL);// 解决jackson2无法反序列化LocalDateTime的问题om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);om.registerModule(new JavaTimeModule());jsonRedisSerializer.setObjectMapper(om);// 值采用json序列化template.setValueSerializer(jsonRedisSerializer);//使用StringRedisSerializer来序列化和反序列化redis的key值template.setKeySerializer(new StringRedisSerializer());//设置hash key 和value序列化模式template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(jsonRedisSerializer);template.afterPropertiesSet();return template;}
}

在这个配置中,我们为 key 使用了 StringRedisSerializer,因为它可以很好地处理字符串。对于 value 和 hash 的 key/value,我们使用了 Jackson2JsonRedisSerializer,它使用 Jackson 库将 Java 对象转换为 JSON 格式的字符串,并可以反向操作。

参考:
https://developer.aliyun.com/article/1233496

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/841999.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【前端Vue】——课堂笔记(一)

&#x1f4bb;博主现有专栏&#xff1a; C51单片机&#xff08;STC89C516&#xff09;&#xff0c;c语言&#xff0c;c&#xff0c;离散数学&#xff0c;算法设计与分析&#xff0c;数据结构&#xff0c;Python&#xff0c;Java基础&#xff0c;MySQL&#xff0c;linux&#xf…

Pip,whl,源码编译安装Python库

pip安装 pip 是 Python 包管理工具&#xff0c;用于安装和管理 Python 包。pip 是 Python 开发中不可或缺的工具&#xff0c;能够帮助开发者轻松地管理项目所需的各种库和依赖。无论是安装新包、升级现有包还是卸载不需要的包&#xff0c;pip 都提供了简单而强大的命令来完成这…

中国改革报是什么级别的报刊?在哪些领域具有较高的影响力?

中国改革报是什么级别的报刊&#xff1f;在哪些领域具有较高的影响力&#xff1f; 《中国改革报》是国家发展和改革委员会主管的全国性综合类报纸。它在经济领域和改革发展方面具有重要的影响力&#xff0c;是传递国家政策、反映改革动态的重要平台。该报对于推动中国的经济改…

Pulsar 社区周报 | No.2024-05-24

“ 各位热爱 Pulsar 的小伙伴们&#xff0c;Pulsar 社区周报更新啦&#xff01;这里将记录 Pulsar 社区每周的重要更新&#xff0c;每周发布。 ” Pulsar Weekly Merge Stars 感谢以下的小伙伴&#xff0c;感谢你们本周为 Apache Pulsar 做的精彩贡献&#xff08;排名不分先后&…

C++的数论相关算法

数论是数学的一个分支&#xff0c;主要研究整数的性质和关系。在计算机科学中&#xff0c;数论算法对于密码学、优化问题和算法分析等方面都具有重要作用。C作为一种高效的编程语言&#xff0c;非常适合用来实现这些算法。下面我们将介绍几个C中的数论相关算法&#xff0c;包括…

一篇文章教你入门Python

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

[Algorihm][简单多状态DP问题][买卖股票的最佳时机含冷冻期][买卖股票的最佳时机含手续费]详细讲解

目录 1.买卖股票的最佳时机含冷冻期1.题目链接买卖股票的最佳时机含冷冻期2.算法原理详解3.代码实现 2.买卖股票的最佳时机含手续费1.题目链接2.算法原理详解3.代码实现 1.买卖股票的最佳时机含冷冻期 1.题目链接 买卖股票的最佳时机含冷冻期 2.算法原理详解 思路&#xff…

基于jeecgboot-vue3的Flowable新建流程定义(三)

因为这个项目license问题无法开源&#xff0c;更多技术支持与服务请加入我的知识星球。 接上一节 8、同时可以进行流程的编辑 /** 编辑流程设计弹窗页面 */const handleLoadXml (row) > {console.log("handleLoadXml row",row)designerData.title "流程设…

SW手势定义

crtle:独立; T:测量;R隐藏;视图>用户界面>动态显示父子关系 crtld:相同零件; alte:草图显示; altw:基准面显示; ALTZ:上一视图;

MyBatis框架的使用:mybatis介绍+环境搭建+基础sql的使用+如何使用Map传入多个参数+返回多个实体用List或者Map接收+特殊sql的使用

MyBatis框架的使用&#xff1a;mybatis介绍环境搭建基础sql的使用如何使用Map传入多个参数返回多个实体用List或者Map接收特殊sql的使用 一、MyBatis介绍1.1 特性1.2 下载地址1.3 和其它持久层技术对比 二、搭建环境2.1配置maven2.2 创建mybatis配置文件2.3 搭建测试环境 三、基…

JAVA:Spring Boot整合MyBatis Plus持久层

1、简述 MyBatis Plus是MyBatis的增强工具包&#xff0c;它在MyBatis的基础上进行了扩展&#xff0c;提供了许多便捷的功能&#xff0c;例如通用CRUD操作、分页插件、代码生成器等。使用MyBatis Plus&#xff0c;开发者可以更加方便地进行持久层操作&#xff0c;并且减少了很多…

自动驾驶---Perception之IPM图和BEV图

1 前言 IPM&#xff08;Inverse Perspective Mapping&#xff0c;逆透视变换&#xff09;图的历史可以追溯到计算机视觉和图像处理领域的发展。逆透视变换是一种用于消除图像中透视效应的技术&#xff0c;使得原本由于透视产生的形变得以纠正&#xff0c;进而更准确地描述和理解…

【优选算法】位运算 {位运算符及其优先级;位运算的应用:判断位,打开位,关闭位,转置位,位图,get lowbit,close lowbit;相关编程题解析}

一、位运算符及其优先级 我们知道&#xff0c;计算机中的数在内存中都是以二进制形式进行存储的 &#xff0c;而位运算就是直接对整数在内存中的二进制位进行操作&#xff0c;因此其执行效率非常高&#xff0c;在程序中尽量使用位运算进行操作&#xff0c;这会大大提高程序的性…

04_前端三大件JS

文章目录 JavaScript1.JS的组成部分2.JS引入2.1 直接在head中通过一对script标签定义脚本代码2.2创建JS函数池文件&#xff0c;所有html文件共享调用 3.JS的数据类型和运算符4.分支结构5.循环结构6.JS函数的声明7.JS中自定义对象8.JS_JSON在客户端使用8.1JSON串格式8.2JSON在前…

Python项目开发实战:工厂库存管理系统(案例教程)

一、项目背景与意义 随着制造业的快速发展,工厂库存管理成为了企业运营中不可或缺的一部分。一个高效的库存管理系统能够确保物料供应的及时性、降低库存成本、提高生产效率。因此,我们决定使用Python开发一个工厂库存管理系统,以满足工厂日常库存管理的需求。 二、系统需求…

Flutter 中的 Badge 小部件:全面指南

Flutter 中的 Badge 小部件&#xff1a;全面指南 在移动应用设计中&#xff0c;徽章&#xff08;Badge&#xff09;是一种常见的UI元素&#xff0c;用于吸引用户注意并展示重要信息&#xff0c;如未读消息数量、新通知等。Flutter 通过各种第三方包提供了徽章小部件&#xff0…

弘君资本股市行情:股指预计保持震荡上扬格局 关注汽车、银行等板块

弘君资本指出&#xff0c;近期商场体现全体分化&#xff0c;指数层面上看&#xff0c;沪指一路震动上行&#xff0c;创出年内新高&#xff0c;创业板指和科创50指数体现相对较弱&#xff0c;依然是底部震动走势。从盘面体现上看&#xff0c;轮动依然是当时商场的主基调&#xf…

IBERT眼图扫描(高速收发器八)

前文讲解了GTX的时钟及收发数据通道的组成&#xff0c;之后讲解了眼图、加重、均衡等原理及原因&#xff0c;本文通过xilinx提供的IBERT IP完成实际工程的眼图扫描&#xff0c;确定加重和幅值调节的参数。 1、回环模式 在此之前&#xff0c;需要了解一下GTX的回环模式。如果板…

【字典树(前缀树) 字符串】2416. 字符串的前缀分数和

本文涉及知识点 字典树&#xff08;前缀树) 字符串 LeetCode 2416. 字符串的前缀分数和 给你一个长度为 n 的数组 words &#xff0c;该数组由 非空 字符串组成。 定义字符串 word 的 分数 等于以 word 作为 前缀 的 words[i] 的数目。 例如&#xff0c;如果 words [“a”,…

【list】list库介绍 + 简化模拟实现

本节博客先对list进行用法介绍&#xff0c;再在库的基础上简化其内容和形式&#xff0c;简单进行模拟实现&#xff0c;有需要借鉴即可。 目录 1.list介绍1.1 list概述1.2相关接口的介绍 2.简化模拟实现3.各部分的细节详述3.1结点3.2迭代器细节1&#xff1a;迭代器用原生指针还是…