默认情况下,Spring 为我们提供了一个 RedisTemplate 来进行对 Redis 的操作,但是 RedisTemplate 默认配置的是使用Java本机序列化。
这种序列化方式,对于操作字符串或数字来说,用起来还行,但是如果要对对象操作,就不是那么的方便了。
所以我们需要配置合适的序列化方式。在 Spring 官方的文档中,官方也建议了我们使用其他的方式来进行序列化。比如JSON
下面就开始自动配置类的书写
我使用的是 Jackson2JsonRedisSerializer 来对对象进行序列化,所以首先需要一个方法,来配置 Jackson2JsonRedisSerializer 序列化策略
private Jackson2JsonRedisSerializer<Object> serializer() {
// 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
return jackson2JsonRedisSerializer;
}
这里要注意的是
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
这一句,这一句非常的重要,作用是序列化时将对象全类名一起保存下来
设置之后的序列化结果如下:
[
"com.buguagaoshu.redis.model.User",
{
"name": "1",
"age": "11",
"message": "牛逼"
}
]
不设置的话,序列化结果如下,将无法反序列化
{
"name": "1",
"age": "11",
"message": "牛逼"
}
网上大多数教程因为时间的原因,这一句用的是
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
但当把这段代码写入的时候,发现Idea提示,这是一个过时的方法,由于我当时并不知道这句话的意思,就把这段代码注释了,觉得可能没什么用,但注释后在向Redis里写数据的时候,数据会变成
导致数据无法反序列化。
最后我查看了这个方法的源码,找到了
通过注释,我得到了这段代码的最新写法。
也明白了这段代码的作用。
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
redisTemplate.setValueSerializer(serializer());
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// 使用StringRedisSerializer来序列化和反序列化redis的key值
redisTemplate.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
redisTemplate.setHashKeySerializer(stringRedisSerializer);
// hash的value序列化方式采用jackson
redisTemplate.setHashValueSerializer(serializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
这里就没有什么需要注意的了,按照自己的需求,来配置序列化的方式
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
// 配置序列化(解决乱码的问题)
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
// 缓存有效期
.entryTtl(timeToLive)
// 使用StringRedisSerializer来序列化和反序列化redis的key值
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
// 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer()))
// 禁用空值
.disableCachingNullValues();
return RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
}
@SpringBootTest
public class RedisApplicationTests {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Test
void contextLoads() throws Exception {
User user = new User();
user.setName("15");
user.setAge(20);
user.setMessage("牛逼");
redisTemplate.opsForValue().set(user.getName(), user);
User getUser = (User) redisTemplate.opsForValue().get(user.getName());
System.out.println(getUser);
System.out.println(getUser.getMessage());
}
}
再来查看Redis中的数据
数据正常,并且系统也能正常的反序列化了。
1 package com.buguagaoshu.redis.config;
2
3
4 import com.fasterxml.jackson.annotation.JsonAutoDetect;
5 import com.fasterxml.jackson.annotation.PropertyAccessor;
6 import com.fasterxml.jackson.databind.ObjectMapper;
7 import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
8 import org.springframework.beans.factory.annotation.Value;
9 import org.springframework.cache.CacheManager;
10 import org.springframework.cache.annotation.CachingConfigurerSupport;
11 import org.springframework.cache.annotation.EnableCaching;
12 import org.springframework.context.annotation.Bean;
13 import org.springframework.context.annotation.Configuration;
14 import org.springframework.data.redis.cache.RedisCacheConfiguration;
15 import org.springframework.data.redis.cache.RedisCacheManager;
16 import org.springframework.data.redis.connection.RedisConnectionFactory;
17 import org.springframework.data.redis.core.RedisTemplate;
18 import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
19 import org.springframework.data.redis.serializer.RedisSerializationContext;
20 import org.springframework.data.redis.serializer.RedisSerializer;
21 import org.springframework.data.redis.serializer.StringRedisSerializer;
22
23 import java.time.Duration;
24
25 /**
26 * @author Pu Zhiwei {@literal puzhiweipuzhiwei@foxmail.com}
27 * create 2020-03-17 21:08
28 * 继承 CachingConfigurerSupport,为了自定义生成 KEY 的策略。可以不继承。
29 */
30 @Configuration
31 @EnableCaching
32 public class RedisConfig extends CachingConfigurerSupport {
33 @Value("${spring.cache.redis.time-to-live}")
34 private Duration timeToLive = Duration.ZERO;
35
36 /**
37 * 配置Jackson2JsonRedisSerializer序列化策略
38 * */
39 private Jackson2JsonRedisSerializer<Object> serializer() {
40 // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
41 Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
42 ObjectMapper objectMapper = new ObjectMapper();
43
44 // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
45 objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
46
47 objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
48
49 // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
50 objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
51
52 jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
53 return jackson2JsonRedisSerializer;
54 }
55
56
57 @Bean
58 public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
59 RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
60 redisTemplate.setConnectionFactory(redisConnectionFactory);
61 // 用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
62 redisTemplate.setValueSerializer(serializer());
63
64 StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
65 // 使用StringRedisSerializer来序列化和反序列化redis的key值
66 redisTemplate.setKeySerializer(stringRedisSerializer);
67
68 // hash的key也采用String的序列化方式
69 redisTemplate.setHashKeySerializer(stringRedisSerializer);
70 // hash的value序列化方式采用jackson
71 redisTemplate.setHashValueSerializer(serializer());
72 redisTemplate.afterPropertiesSet();
73 return redisTemplate;
74 }
75
76
77
78
79 @Bean
80 public CacheManager cacheManager(RedisConnectionFactory factory) {
81 RedisSerializer<String> redisSerializer = new StringRedisSerializer();
82 // 配置序列化(解决乱码的问题)
83 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
84 // 缓存有效期
85 .entryTtl(timeToLive)
86 // 使用StringRedisSerializer来序列化和反序列化redis的key值
87 .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
88 // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
89 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer()))
90 // 禁用空值
91 .disableCachingNullValues();
92
93 return RedisCacheManager.builder(factory)
94 .cacheDefaults(config)
95 .build();
96 }
97 }
参考:https://www.cnblogs.com/puzhiwei/p/12519304.html