序列化和反序列化需要确保算法一致
spring-data-redis-客户端,配置,序列化,Pipeline管道_spring data redis 配置-CSDN博客
通过 RedisTemplate 读取 Key 为 stringRedisTemplate 的 Value,
使用 StringRedisTemplate 读取 Key 为 redisTemplate 的 Value:
结果是,两次都无法读取到 Value:
@SpringBootTest
public class SerialDemo {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private ObjectMapper objectMapper;
@PostConstruct
public void init() throws JsonProcessingException {
redisTemplate.opsForValue().set("redisTemplate", new UserBean("zhuye", "dd", 23));
stringRedisTemplate.opsForValue().set("stringRedisTemplate",
objectMapper.writeValueAsString(new UserBean("zhuye", "dd", 23)));
Object stringRedisTemplate1 = redisTemplate.opsForValue().get("stringRedisTemplate");
String redisTemplate1 = stringRedisTemplate.opsForValue().get("redisTemplate");
}
}
- RedisTemplate 默认情况下 RedisTemplate 针对 Key 和 Value 使用JDK 序列化
- StringRedisTemplate 对于 Key 和 Value,使用的是 String 序列化方式,Key 和 Value 只能是 String:
/**
* 启用 activateDefaultTyping 方法把类型信息作为属性写入序列化后的数据中
* <code>
* ObjectMapper objectMapper = new ObjectMapper();
* objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
* objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(),ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT);
* Jackson2JsonRedisSerializer<Object> objectJackson2JsonRedisSerializer =
* *new Jackson2JsonRedisSerializer<>(objectMapper,Object .class);
* </code>
* 直接 使用 RedisSerializer.json() 更简单
*/
@Configuration
public class RedisTemplateConfiguration {
@Bean("redisTemplate")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 设置key和value的序列化规则
redisTemplate.setValueSerializer(RedisSerializer.json());
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setHashKeySerializer(RedisSerializer.string());
redisTemplate.setHashValueSerializer(RedisSerializer.json());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
注意 Jackson JSON 反序列化对额外字段的处理
修改特性
不要自定义 ObjectMapper,而是直接在配置文件设置相关参数,来修改Spring 默认的 ObjectMapper 的功能。比如,直接在配置文件启用把枚举序列化为索引号
spring.jackson.serialization.write_enums_using_index=true
或者可以直接定义 Jackson2ObjectMapperBuilderCustomizer Bean 来启用新特性:
@Configuration
public class JacksonConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return builder -> {
// 启用序列化特性
builder.featuresToEnable(
SerializationFeature.INDENT_OUTPUT, // 使输出的 JSON 格式化
SerializationFeature.WRITE_DATES_AS_TIMESTAMPS // 将日期对象序列化为时间戳
);
// 禁用序列化特性
builder.featuresToDisable(
SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS // 不将日期键序列化为时间戳
);
// 启用反序列化特性
builder.featuresToEnable(
DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, // 如果 JSON 数组只有一个值,则接受单个值
DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE // 如果 JSON 中包含未知的枚举值,则使用默认值
);
// 禁用反序列化特性
builder.featuresToDisable(
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES // 如果 JSON 中包含未知属性,则不反序列化失败
);
// 启用映射器特性
builder.featuresToEnable(
MapperFeature.AUTO_DETECT_GETTERS_SETTERS, // 自动检测 getter 和 setter 方法
MapperFeature.AUTO_DETECT_FIELDS // 自动检测字段
);
// 禁用映射器特性
builder.featuresToDisable(
MapperFeature.SORT_PROPERTIES_ALPHABETICALLY // 不按字母顺序排序属性
);
};
}
}
简单使用
Jackson 官方文档来了解这些特性,详见SerializationFeatureDeserializationFeature和 MapperFeature。
SerializationFeature 用于控制 JSON 序列化的行为。以下是一些常见的 SerializationFeature:
- INDENT_OUTPUT: 使输出的 JSON 格式化,便于阅读。
- WRITE_DATES_AS_TIMESTAMPS: 将日期对象序列化为时间戳。
- WRITE_DATE_KEYS_AS_TIMESTAMPS: 将日期键序列化为时间戳。
- WRITE_ENUMS_USING_TO_STRING: 使用枚举的 toString 方法而不是名称进行序列化。
- WRITE_EMPTY_JSON_ARRAYS_FOR_NULL_COLLECTIONS: 将空集合序列化为空数组而不是 null。
DeserializationFeature
DeserializationFeature 用于控制 JSON 反序列化的行为。以下是一些常见的 DeserializationFeature:
- FAIL_ON_UNKNOWN_PROPERTIES: 如果 JSON 中包含未知属性,则反序列化失败。
- ACCEPT_SINGLE_VALUE_AS_ARRAY: 如果 JSON 数组只有一个值,则接受单个值。
- READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE: 如果 JSON 中包含未知的枚举值,则使用默认值。
MapperFeature
MapperFeature 用于控制 ObjectMapper 的行为。以下是一些常见的 MapperFeature:
- AUTO_DETECT_GETTERS_SETTERS: 自动检测 getter 和 setter 方法。
- AUTO_DETECT_FIELDS: 自动检测字段。
- AUTO_DETECT_CREATORS: 自动检测构造函数。
- SORT_PROPERTIES_ALPHABETICALLY: 按字母顺序排序属性。
- USE_GETTERS_AS_SETTERS: 使用 getter 方法作为 setter 方法。
反序列化时要小心类的构造方法
默认情况下,在反序列化的时候,Jackson 框架只会调用无参构造方法创建对象。如果走自定义的构造方法创建对象,需要通过 @JsonCreator 来指定构造方法,并通过@JsonProperty 设置构造方法中参数对应的 JSON 属性名:
@Data
public class APIResultRight {
...
@JsonCreator
public APIResultRight(@JsonProperty("code") int code) {
this.code = code;
if (code == 2000) success = true;
else success = false;
}
}
枚举作为 API 接口参数或返回值的两个大坑
客户端和服务端的枚举定义不一致时,会出异常
要解决这个问题,可以开启 Jackson 的 read_unknown_enum_values_using_default_value 反序列化特性,也就是在枚举值未知的时候使用默认值:并为枚举添加一个默认值,使用 @JsonEnumDefaultValue 注解注释:
@JsonEnumDefaultValue
UNKNOWN(-1, "未知");
RestTemplate 生效这个反序列化特性,还 需要配置 RestTemplate,来使用 Spring Boot 的 MappingJackson2HttpMessageConverter 才行:
@Bean
public RestTemplate restTemplate(MappingJackson2HttpMessageConverter mappingJac
return new RestTemplateBuilder()
.additionalMessageConverters(mappingJackson2HttpMessageConverter)
.build();
}