最近在spring-data-redis用redis缓存对象时,如果保存是String的话,没有问题,但是如果保存对象时,发现就无法正常显示。利用redis-cli查看发现保存的均是二进制,无法正常的查看。
127.0.0.1:6379> keys *
1) "\xac\xed\x00\x05t\x00\x05test1"
2) "\xac\xed\x00\x05t\x00\atest122"
3) "\xac\xed\x00\x05t\x00\auser001"
4) "\xac\xed\x00\x05t\x00\ttest12245"
5) "\xac\xed\x00\x05t\x00\x1auser0000000000000000000001"
6) "\xac\xed\x00\x05t\x00\x10user000000000001"
查资料发现,spring-data-redis的RedisTemplate<K, V>模板类在操作redis时默认使用JdkSerializationRedisSerializer来进行序列,而spring-data-redis支持。
JacksonJsonRedisSerializer Jackson2JsonRedisSerializer OxmSerializer
现在我们实现Jackson2JsonRedisSerializer序列化,直接上代码,主要看objRedisTemplate方法
package com.xxfy.demo.config;
import java.lang.reflect.Method;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
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;
/**
* redis配置
* @author Administrator
*
*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport{
/**
* redis缓存管理
* @param redisTemplate
* @return
*/
@Bean
public CacheManager cacheManager(
@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
return new RedisCacheManager(redisTemplate);
}
@SuppressWarnings("unchecked")
@Bean
public RedisTemplate<String, String> redisTemplate(
RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
@SuppressWarnings("rawtypes")
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(String.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
/**
* 序列化方式
* @param redisConnectionFactory
* @return
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@Bean
public RedisTemplate<Object, Object> objRedisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
//key直接采用String的序列化
template.setKeySerializer(new StringRedisSerializer());
//key直接采用jackson2JsonRedisSerializer序列化
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
/**
* redis的key生成策略
* @return
*/
@Bean
KeyGenerator wiselyKeyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
}
写一个测试类进行测试:
package com.xxfy.demo.spring_boot_demo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import com.xxfy.demo.vo.UserVo;
import junit.framework.TestCase;
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisTest extends TestCase{
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private RedisTemplate<Object, Object> objRedisTemplate;
@Test
public void test() {
//保存字符串
stringRedisTemplate.opsForValue().set("aaa", "中文");
System.out.println(stringRedisTemplate.opsForValue().get("aaa"));
}
@Test
public void test2() {
UserVo vo = new UserVo();
vo.setUserId("001");
vo.setPassword("123456");
objRedisTemplate.opsForValue().set("user0001", vo);
System.out.println(((UserVo) objRedisTemplate.opsForValue().get("user0001")).getPassword());
}
}
从测试代码可以看到:如果redis的Key,value都是String的话,直接使用StringRedisTemplate即可,而如果不是的话,则使用了RedisConfig中我们定义的RedisTemplate<Object, Object>,利用它进行序列化,这样就不会显示乱码了。并且我们使用的是Object,所有今后使用POJO的话,不需要重新写RedisTemplate。
源码可参考:https://github.com/xiaojun90/spring-boot-demo.git