之前讲过如何通过 Docker 安装 Redis ,也讲了 Springboot 以 Repository 方式整合 Redis ,建议阅读后再看本文效果更佳:
(1) Docker安装Redis并介绍漂亮的可视化客户端进行操作
(2) 实例讲解Springboot以Repository方式整合Redis
本文将通过实例讲解 Springboot 以 Template 方式整合 Redis ,并遇到一些序列化的问题。代码结构如下:
与文章《 实例讲解Springboot以Repository方式整合Redis 》相同的代码不再列出来,文末将提供代码下载方式。
把相关依赖引入到项目中后, Springboot 就自动帮我们生成了 Template 类,分别是 RedisTemplate 和 StringRedisTemplate 。看一下自动配置类能看出这两个类都已经创建到Spring容器里了。
public class RedisAutoConfiguration {
public RedisAutoConfiguration() {
}
@Bean
@ConditionalOnMissingBean( name = {"redisTemplate"} )
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
实际上 StringRedisTemplate 是 RedisTemplate 的子类,对于 String 类型,更推荐使用前者,它的类型只能是 String 的,会有类型检查上的安全;而 RedisTemplate 可以操作任何类型。
本文通过 RedisTemplate 对 Redis 进行操作,所以我们需要将它注入进来。代码如下:
package com.pkslow.springbootredistemplate.dal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class UserDAL {
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
public void setValue(Object key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
public Object getValue(Object key) {
return redisTemplate.opsForValue().get(key);
}
}
RedisTemplate 提供了丰富的方法,具体可以参考官方文档,本次用到的及类似的方法有:
我们需要把功能通过 Web 的方式暴露出去,实现以下 Contrller :
package com.pkslow.springbootredistemplate.controller;
import com.pkslow.springbootredistemplate.dal.UserDAL;
import com.pkslow.springbootredistemplate.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/userTemplate")
public class UserTemplateController {
@Autowired
private final UserDAL userDAL;
public UserTemplateController(UserDAL userDAL) {
this.userDAL = userDAL;
}
@GetMapping("/{userId}")
public User getByUserId(@PathVariable String userId) {
return (User)userDAL.getValue(userId);
}
@PostMapping("/{userId}")
public User addNewUser(@PathVariable String userId,
@RequestBody User user) {
user.setUserId(userId);
userDAL.setValue(userId, user);
return user;
}
}
只提供两个接口,分别是设值和取值。
(1)存入对象
(2)读取对象
能写能读,功能实现,完美!Perfect!收工!
程序功能正常运行一段时间后,运维杀来了: “这是什么东西?我怎么看得懂?我要怎么查看数据?”
不得不重新打开项目代码, Debug 一下看看哪出了问题。既然用 Postman 测试能正常显示,而数据库显示不对,说明是写入数据库时做了转换。查看 RedisTemplate 就行了,毕竟活是他干的(先疯狂甩锅)。
看它的序列化类用的是默认的 JdkSerializationRedisSerializer ,所以序列化后的数据我们看不懂。
甩锅完后,还是要修复问题的,毕竟代码是自己写的。关键就是替换掉 RedisTemplate 所使用的序列化类就行了,这有两个方案可选:
(1)自定义一个新的 RedisTemplate 以覆盖旧的,在定义的时候指定序列化类。大致代码如下:
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(jackson2JsonRedisSerializer);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
甚至还可以自定义 RedisConnectionFactory ,如下:
@Bean
JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory jedisConFactory = new JedisConnectionFactory();
jedisConFactory.setHostName("localhost");
jedisConFactory.setPort(6379);
return jedisConFactory;
}
(2)使用原有的 RedisTemplate ,在使用前替换掉序列化类
引用的类的代码如下, init 方法作为初始化方法:
public class UserDAL {
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
public void init() {
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
}
public void setValue(Object key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
public Object getValue(Object key) {
return redisTemplate.opsForValue().get(key);
}
}
然后在创建 UserDAL 时,代码如下:
@Bean(initMethod = "init")
public UserDAL userDAL() {
return new UserDAL();
}
重新提交代码、重新测试、重新发布,结果可以了:
本文详细代码可在 南瓜慢说 公众号回复< SpringbootRedisTemplate >获取。
欢迎访问 南瓜慢说 www.pkslow.com 获取更多精彩文章!
欢迎关注微信公众号< 南瓜慢说 >,将持续为你更新...