SpringBoot集成Redis后,如果使用redis存储Object,redis默认的序列化器在写入key或value时会以二进制的形式存储,并不方便我们日常观察他的key和value,如下图。因此我们需要自定义序列化器配置来方便我们更好的观察它的key和value,目前比较流行有两种配置方式。
第一种、使用spring-data-redis的jar里的org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer.
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
//指定Jackson2JsonRedisSerializer为Object的序列化器,替代redis默认的序列化器JdkSerializationRedisSerializer
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
ObjectMapper objectMapper = new ObjectMapper();
//反序列化时智能识别变量名(识别没有按驼峰格式命名的变量名)
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//反序列化识别对象类型
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
//反序列化如果有多的属性,不抛出异常
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//反序列化如果碰到不识别的枚举值,是否作为空值解释,true:不会抛不识别的异常, 会赋空值,false:会抛不识别的异常
objectMapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
1.1、反序列化时智能识别变量名(识别没有按驼峰格式命名的变量名)。配置代码如下:
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
反例演示如下:
redis的value值,key没有按驼峰格式命名, 反序列化时出现不识别导致赋值providerOrderNo的值为null。
1.2、序列化和反序列化识别对象类型。配置代码如下:
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
添加这个配置后,存储到redis的对象的字符串我们会出现“@type”字样的标识,并标示时哪一种对象,反序列化时也根据这个标识识别对象的类型。
1.3、反序列化如果有多的属性,不抛出异常。代码配置如下:
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
没配置时,从redis缓存中获取字符串值进行反序列化对象时报“org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Unrecognized field "appId"”的错误。
反例演示:
redis的value新增一个属性appId。
反序列化成对象时报不识别的属性appId, 如下:
1.4、反序列化如果碰到不识别的枚举值,是否作为空值解释,true:不会抛不识别的异常, 会赋空值,false:会抛不识别的异常。代码配置如下:
objectMapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);
反例演示:
修改redis的value的枚举属性值:
反序列化时,报不识别的枚举值。
第二种:直接使用Fastjson的序列化器(1.2.68以上的版本漏洞已修复)
注明:fastJson版本<=1.2.68,存在远程代码执行的漏洞。我们项目中如果使用小于或等于1.2.68版本的fastjson,需要及时升级修复漏洞。
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory, RedisSerializer fastJson2JsonRedisSerializer) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
//key采用String序列化方式
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
//value采用fast-json序列化方式。
redisTemplate.setValueSerializer(fastJson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(fastJson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public RedisSerializer fastJson2JsonRedisSerializer() {
return new FastJson2JsonRedisSerializer<>(Object.class);
}
public static class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
private Class<T> clazz;
public FastJson2JsonRedisSerializer(Class<T> clazz) {
super();
this.clazz = clazz;
}
@Override
public byte[] serialize(T t) throws SerializationException {
if (t == null) {
return new byte[0];
}
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
}
@Override
public T deserialize(byte[] bytes) throws SerializationException {
if (bytes == null || bytes.length <= 0) {
return null;
}
String str = new String(bytes, DEFAULT_CHARSET);
return JSON.parseObject(str, clazz, Feature.SupportAutoType);
}
}