1 簡介 之前講過如何通過 安裝 ,也講了 以`Repository Redis`,建議閱讀後再看本文效果更佳: (1) "Docker安裝Redis並介紹漂亮的可視化客戶端進行操作" (2) "實例講解Springboot以Repository方式整合Redis" 本文將通過實例講解 以`Temp ...
1 簡介
之前講過如何通過Docker
安裝Redis
,也講了Springboot
以Repository
方式整合Redis
,建議閱讀後再看本文效果更佳:
(1) Docker安裝Redis並介紹漂亮的可視化客戶端進行操作
(2) 實例講解Springboot以Repository方式整合Redis
本文將通過實例講解Springboot
以Template
方式整合Redis
,並遇到一些序列化的問題。代碼結構如下:
2 整合過程
與文章《實例講解Springboot以Repository方式整合Redis》相同的代碼不再列出來,文末將提供代碼下載方式。
2.1 自動配置類
把相關依賴引入到項目中後,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
可以操作任何類型。
2.2 實現數據訪問層
本文通過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
提供了豐富的方法,具體可以參考官方文檔,本次用到的及類似的方法有:
- opsForHash(): 返回對於Hash的操作類;
- opsForList(): 返回對於列表List的操作類;
- opsForSet(): 返回對於Set的操作類;
- opsForValue(): 返回對於字元串String的操作類;
- opsForZSet(): 返回對於ZSet的操作類。
2.3 實現Controller
我們需要把功能通過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;
}
}
只提供兩個介面,分別是設值和取值。
2.4 通過Postman測試
(1)存入對象
(2)讀取對象
能寫能讀,功能實現,完美!Perfect!收工!
3 序列化問題
程式功能正常運行一段時間後,運維殺來了:“這是什麼東西?我怎麼看得懂?我要怎麼查看數據?”
3.1 定位問題
不得不重新打開項目代碼,Debug
一下看看哪出了問題。既然用Postman
測試能正常顯示,而資料庫顯示不對,說明是寫入資料庫時做了轉換。查看RedisTemplate
就行了,畢竟活是他乾的(先瘋狂甩鍋)。
看它的序列化類用的是預設的JdkSerializationRedisSerializer
,所以序列化後的數據我們看不懂。
3.2 問題修複
甩鍋完後,還是要修複問題的,畢竟代碼是自己寫的。關鍵就是替換掉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();
}
重新提交代碼、重新測試、重新發佈,結果可以了:
4 總結
本文詳細代碼可在南瓜慢說公眾號回覆<SpringbootRedisTemplate>獲取。
歡迎訪問南瓜慢說 www.pkslow.com獲取更多精彩文章!
歡迎關註微信公眾號<南瓜慢說>,將持續為你更新...
多讀書,多分享;多寫作,多整理。