Springboot?引入?Redis?并配置序列化并封裝RedisTemplate?
前言
為什么要配置序列化:如果不配置序列化的話,我們?cè)趓edis數(shù)據(jù)庫中存儲(chǔ)的數(shù)據(jù)可能以亂碼形式顯示出來,不方便我們判斷數(shù)據(jù)存儲(chǔ)的正確性,說白了就是序列化以后存進(jìn)去的是什么,查詢出來的就是什么,否則我們的鍵值都會(huì)變成一串看不懂的亂碼。
為什么要封裝RedisTemplate,因?yàn)槿绻贿M(jìn)行封裝的話,大家請(qǐng)看,是不是有黃色的警告信息,看著起來很不舒服,RedisTemplate后面的尖括號(hào)可以填泛型,填寫以后警告就消失了,但我們的類型很多,每次只能Autowired一個(gè)RedisTemplate,所以不能寫尖括號(hào)內(nèi)的類型,同時(shí)封裝也能按照自己的習(xí)慣自定義方法,更好用。
一、引入依賴
只需要引入這一個(gè)就可以了,現(xiàn)在的版本里面包含了 lettuce ,所以不需要再額外引入 common-pool2
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
二、配置yml
因?yàn)槲沂褂玫氖荢pringboot 3.0,所以配置層級(jí)是 spring-data-redis,如果你們的配置文件爆紅,說明你們是舊版,那么把data去掉就可以了,直接是 spring-redis
server: port: 8081 spring: data: redis: #數(shù)據(jù)庫索引 database: 0 #redis 服務(wù)器地址 host: 127.0.0.1 #redis 端口 port: 6379 #redis 密碼 默認(rèn)為空 password: # 鏈接超時(shí)時(shí)間 connect-timeout: 10s #lettuce連接池配置 lettuce: pool: # 鏈接池中最小的空閑鏈接 默認(rèn)為0 min-idle: 0 # 鏈接池中最大的空閑連接 默認(rèn)為 8 max-idle: 8 #連接池中最大數(shù)據(jù)庫鏈接數(shù) 默認(rèn)為8 max-active: 8 #連接池最大阻塞等待時(shí)間 負(fù)值表示沒有限制 max-wait: -1ms
三、封裝RedisTemplate
注意:我這里用的是 Java17 新增的 record 紀(jì)錄類,如果你們是低版本的 JDK ,把 record 更換成 class ,然后注入RedisTemplate
package com.xuyijie.redisdemo.utils; import org.springframework.data.redis.core.*; import org.springframework.stereotype.Component; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; /** * @Author: 徐一杰 * @date: 2022/4/3 * @Description: 對(duì)RedisTemplate進(jìn)行封裝 */ @Component public record RedisUtil<K, V>(RedisTemplate<K, V> redisTemplate) { /** * 消除黃色警告 * @param redisTemplate */ @SuppressWarnings("all") public RedisUtil { } /** * 默認(rèn)存活時(shí)間 2 天 */ private static final long DEFAULT_EXPIRE_TIME = 60 * 60 * 48; /** * 根據(jù)key 獲取過期時(shí)間 * @param key 鍵 不能為null * @return 時(shí)間(秒) 返回0代表為永久有效 */ public long getExpireTime(K key) { return redisTemplate.getExpire(key, TimeUnit.SECONDS); } /** * 指定緩存失效時(shí)間 * @param key 鍵 * @param expireTime 時(shí)間(秒) * @return */ public void setExpireTime(K key, long expireTime) { try { if (expireTime > 0) { redisTemplate.expire(key, expireTime, TimeUnit.SECONDS); } } catch (Exception e) { e.printStackTrace(); } } /** * 移除指定 key 的過期時(shí)間 * @param key * @return */ public void removeExpireTime(K key) { redisTemplate.boundValueOps(key).persist(); } /** * 獲取緩存中的鍵 * @param key * @return */ public Set<K> keys(K key) { return redisTemplate.keys(key); } /** * 判斷key是否存在 * @param key 鍵 * @return true 存在 false不存在 */ public boolean hasKey(K key) { try { return Boolean.TRUE.equals(redisTemplate.hasKey(key)); } catch (Exception e) { e.printStackTrace(); return false; } } /** * 根據(jù)key刪除緩 * @param keys */ public void delete(Collection<K> keys) { redisTemplate.delete(keys); } /** * 設(shè)置分布式鎖 * @param key * @param value * @param expire * @return */ @SuppressWarnings("unchecked") public Boolean setNx(String key, String value, long expire) { return (Boolean) redisTemplate.execute((RedisCallback) connection -> { Boolean acquire = connection.setNX(key.getBytes(), value.getBytes()); connection.expire(key.getBytes(), expire); return acquire; }); } /*********** String 類型操作 **************/ /** * 普通緩存放入 * @param key 鍵 * @param value 值 * @return true成功 false失敗 */ public void set(K key, V value) { try { redisTemplate.opsForValue().set(key, value); } catch (Exception e) { e.printStackTrace(); } } /** * 普通緩存放入并設(shè)置時(shí)間 * @param key 鍵 * @param value 值 * @param time 時(shí)間(秒) time要大于0 如果time小于等于0 將設(shè)置無限期 * @return true成功 false 失敗 */ public void set(K key, V value, long time) { try { if (time > 0) { redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); } else { redisTemplate.opsForValue().set(key, value); } } catch (Exception e) { e.printStackTrace(); } } /** * value增加值 * @param key * @param number * @return */ @SuppressWarnings("unchecked") public Long incrBy(String key, long number) { return (Long) redisTemplate.execute((RedisCallback) connection -> connection.incrBy(key.getBytes(), number)); } /** * value減少值 * @param key * @param number */ @SuppressWarnings("unchecked") public Long decrBy(String key, long number) { return (Long) redisTemplate.execute((RedisCallback) connection -> connection.decrBy(key.getBytes(), number)); } /** * 根據(jù)key獲取value * * @param key */ public Object get(K key) { BoundValueOperations<K, V> boundValueOperations = redisTemplate.boundValueOps(key); return boundValueOperations.get(); } /*********** list 類型操作 **************/ /** * 將list放入緩存 * @param key 鍵 * @param value 值 */ public void listRightPush(K key, V value) { ListOperations<K, V> listOperations = redisTemplate.opsForList(); //從隊(duì)列右插入 listOperations.rightPush(key, value); } /** * 將list放入緩存 * @param key 鍵 * @param value 值 * @return */ public void listLeftPush(K key, V value) { ListOperations<K, V> listOperations = redisTemplate.opsForList(); //從隊(duì)列右插入 listOperations.leftPush(key, value); } /** * 將list放入緩存 * @param key 鍵 * @param value 值 * @return */ public void listRightPushAll(K key, List<V> value) { try { redisTemplate.opsForList().rightPushAll(key, value); } catch (Exception e) { e.printStackTrace(); } } /** * 將list放入緩存 * @param key 鍵 * @param value 值 * @return */ public void listLeftPushAll(K key, List<V> value) { try { redisTemplate.opsForList().leftPushAll(key, value); } catch (Exception e) { e.printStackTrace(); } } /** * 通過索引 獲取list中的值 * @param key 鍵 * @param index 索引 index>=0時(shí), 0 表頭,1 第二個(gè)元素,依次類推;index<0時(shí),-1,表尾,-2倒數(shù)第二個(gè)元素,依次類推 * @return */ public Object listGetWithIndex(K key, long index) { try { return redisTemplate.opsForList().index(key, index); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 從隊(duì)列左邊彈出一條數(shù)據(jù) * @param key * @return */ public V listLeftPop(K key) { ListOperations<K, V> listOperations = redisTemplate.opsForList(); return listOperations.leftPop(key); } /** * 從隊(duì)列右邊彈出一條數(shù)據(jù) * @param key * @return */ public V listRightPop(K key) { ListOperations<K, V> listOperations = redisTemplate.opsForList(); return listOperations.rightPop(key); } /** * 獲取list緩存的內(nèi)容 * @param key 鍵 * @param start 開始 * @param end 結(jié)束 0 到 -1 代表所有值 * @return */ public List<V> listRange(K key, long start, long end) { try { ListOperations<K, V> listOperations = redisTemplate.opsForList(); return listOperations.range(key, start, end); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 獲取list緩存的長(zhǎng)度 * @param key 鍵 * @return */ public long listSize(K key) { try { return redisTemplate.opsForList().size(key); } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 根據(jù)索引修改list中的某條數(shù)據(jù) * @param key 鍵 * @param index 索引 * @param value 值 * @return */ public void listSet(K key, long index, V value) { try { redisTemplate.opsForList().set(key, index, value); } catch (Exception e) { e.printStackTrace(); } } /** * 移除N個(gè)值為value * * @param key 鍵 * @param count 移除多少個(gè) * @param value 值 * @return 移除的個(gè)數(shù) */ public long listRemove(K key, long count, V value) { try { return redisTemplate.opsForList().remove(key, count, value); } catch (Exception e) { e.printStackTrace(); return 0; } } /*********** hash 類型操作 **************/ /** * 根據(jù)key和鍵獲取value * * @param key 鍵 不能為null * @param item 項(xiàng) 不能為null * @return 值 */ public Object hashGet(K key, String item) { return redisTemplate.opsForHash().get(key, item); } /** * 獲取key對(duì)應(yīng)的所有鍵值 * * @param key 鍵 * @return 對(duì)應(yīng)的多個(gè)鍵值 */ public Map<Object, Object> hashMGet(K key) { return redisTemplate.opsForHash().entries(key); } /** * 添加map到hash中 * * @param key 鍵 * @param map 對(duì)應(yīng)多個(gè)鍵值 * @return true 成功 false 失敗 */ public void hashMSet(K key, Map<String, Object> map) { try { redisTemplate.opsForHash().putAll(key, map); } catch (Exception e) { e.printStackTrace(); } } /** * 添加map到hash中,并設(shè)置過期時(shí)間 * * @param key 鍵 * @param map 對(duì)應(yīng)多個(gè)鍵值 * @param expireTime 時(shí)間(秒) * @return true成功 false失敗 */ public void hashMSet(K key, Map<String, Object> map, long expireTime) { try { redisTemplate.opsForHash().putAll(key, map); if (expireTime > 0) { redisTemplate.expire(key, expireTime, TimeUnit.SECONDS); } } catch (Exception e) { e.printStackTrace(); } } /** * 向hash表中放入一個(gè)數(shù)據(jù) * * @param key 鍵 * @param hKey 項(xiàng) * @param value 值 * @return true 成功 false失敗 */ public <HK, HV> void hashPut(K key, HK hKey, HV value) { try { HashOperations<K, HK, HV> hashOperations = redisTemplate.opsForHash(); hashOperations.put(key, hKey, value); } catch (Exception e) { e.printStackTrace(); } } /** * 向hash表中放入一個(gè)數(shù)據(jù),并設(shè)置過期時(shí)間 * * @param key 鍵 * @param hKey 項(xiàng) * @param value 值 * @param expireTime 時(shí)間(秒) 注意:如果已存在的hash表有時(shí)間,這里將會(huì)替換原有的時(shí)間 * @return true 成功 false失敗 */ public <HK, HV> void hashPut(K key, HK hKey, HV value, long expireTime) { try { redisTemplate.opsForHash().put(key, hKey, value); if (expireTime > 0) { redisTemplate.expire(key, expireTime, TimeUnit.SECONDS); } } catch (Exception e) { e.printStackTrace(); } } /** * 判斷hash表中是否有該項(xiàng)的值 * * @param key 鍵 不能為null * @param hKey 項(xiàng) 不能為null * @return true 存在 false不存在 */ public <HK, HV> boolean hashHasKey(K key, HK hKey) { HashOperations<K, HK, HV> hashOperations = redisTemplate.opsForHash(); return hashOperations.hasKey(key, hKey); } /** * 取出所有 value * * @param key * @param <HK> * @param <HV> * @return */ public <HK, HV> List<HV> hashValues(K key) { HashOperations<K, HK, HV> hashOperations = redisTemplate.opsForHash(); return hashOperations.values(key); } /** * 取出所有 hKey * @param key */ public <HK, HV> Set<HK> hashHKeys(K key) { HashOperations<K, HK, HV> hashOperations = redisTemplate.opsForHash(); return hashOperations.keys(key); } /** * 刪除hash表中的鍵值,并返回刪除個(gè)數(shù) * @param key * @param hashKeys */ public <HK, HV> Long hashDelete(K key, Object... hashKeys) { HashOperations<K, HK, HV> hashOperations = redisTemplate.opsForHash(); return hashOperations.delete(key, hashKeys); } /*********** set 類型操作 **************/ /** * 將數(shù)據(jù)放入set緩存 * @param key 鍵 * @param values 值 可以是多個(gè) */ public void setAdd(K key, V... values) { redisTemplate.opsForSet().add(key, values); } /** * 將set數(shù)據(jù)放入緩存,并設(shè)置過期時(shí)間 * @param key 鍵 * @param expireTime 時(shí)間(秒) * @param values 值 可以是多個(gè) */ public void setAdd(K key, long expireTime, V... values) { redisTemplate.opsForSet().add(key, values); if (expireTime > 0) { redisTemplate.expire(key, expireTime, TimeUnit.SECONDS); } } /** * 獲取set緩存的長(zhǎng)度 * @param key 鍵 * @return 長(zhǎng)度 */ public long setSize(K key) { try { return redisTemplate.opsForSet().size(key); } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 根據(jù)key獲取Set中的所有值 * @param key * @return java.util.Set<V> */ public Set<V> setValues(K key) { SetOperations<K, V> setOperations = redisTemplate.opsForSet(); return setOperations.members(key); } /** * 根據(jù)value從一個(gè)set中查詢,是否存在 * @param key 鍵 * @param value 值 * @return true 存在 false不存在 */ public boolean setHasKey(K key, V value) { return Boolean.TRUE.equals(redisTemplate.opsForSet().isMember(key, value)); } /** * 根據(jù)value刪除,并返回刪除的個(gè)數(shù) * @param key * @param value * @return 刪除的個(gè)數(shù) */ public Long setDelete(K key, Object... value) { SetOperations<K, V> setOperations = redisTemplate.opsForSet(); return setOperations.remove(key, value); } /*********** zset 類型操作 **************/ /** * 在 zset中插入一條數(shù)據(jù) * @param key * @param value * @param score */ public void zSetAdd(K key, V value, long score) { ZSetOperations<K, V> zSetOperations = redisTemplate.opsForZSet(); zSetOperations.add(key, value, score); } /** * 得到分?jǐn)?shù)在 score1,score2 之間的值 * @param key * @param score1 * @param score2 * @return java.util.Set<V> */ public Set<V> zSetValuesRange(K key, long score1, long score2) { ZSetOperations<K, V> zSetOperations = redisTemplate.opsForZSet(); return zSetOperations.range(key, score1, score2); } /** * 根據(jù)value刪除,并返回刪除個(gè)數(shù) * @param key * @param value * @return 刪除個(gè)數(shù) */ public Long zSetDeleteByValue(K key, Object... value) { ZSetOperations<K, V> zSetOperations = redisTemplate.opsForZSet(); return zSetOperations.remove(key, value); } /** * 刪除多個(gè),并返回刪除個(gè)數(shù) * @param key * @param size1 * @param size2 * @return 刪除個(gè)數(shù) */ public Long zSetDeleteRange(K key, long size1, long size2) { ZSetOperations<K, V> zSetOperations = redisTemplate.opsForZSet(); return zSetOperations.removeRange(key, size1, size2); } /** * 刪除分?jǐn)?shù)區(qū)間內(nèi)元素,并返回刪除個(gè)數(shù) * @param key * @param score1 * @param score2 * @return 刪除個(gè)數(shù) */ public Long zSetDeleteByScore(K key, long score1, long score2) { ZSetOperations<K, V> zSetOperations = redisTemplate.opsForZSet(); return zSetOperations.removeRangeByScore(key, score1, score2); } }
當(dāng)然有些同學(xué)已經(jīng)發(fā)現(xiàn)了,我這樣封裝,也沒有解決RedisUtil后面的尖括號(hào)不輸入內(nèi)容出現(xiàn)警告的問題,因?yàn)槲沂菢I(yè)務(wù)需要,所以保留了尖括號(hào)指定類型
你們?nèi)绻遣幌胼斎爰饫ㄌ?hào)內(nèi)的類型,這樣改,把RedisUti和RedisTemplate的尖括號(hào)去掉,下面的方法中的 K 全部改為 String,V 全部改為 Object就可以了
@Component public record RedisUtil(RedisTemplate redisTemplate) { @SuppressWarnings("all") public RedisUtil { } /** * 默認(rèn)存活時(shí)間 2 天 */ private static final long DEFAULT_EXPIRE_TIME = 60 * 60 * 48; /** * 根據(jù)key 獲取過期時(shí)間 * @param key 鍵 不能為null * @return 時(shí)間(秒) 返回0代表為永久有效 */ public long getExpireTime(String key) { return redisTemplate.getExpire(key, TimeUnit.SECONDS); }
四、controller使用RedisUtil
package com.xuyijie.redisdemo.controller; import com.xuyijie.redisdemo.utils.RedisUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * @author 徐一杰 * @date 2022/9/20 10:30 * @description */ @RestController @RequestMapping("/test") public class TestController { @Autowired private RedisUtil<String, String> redisUtil; @GetMapping("/helloString/{key}") public String helloString(@PathVariable String key){ redisUtil.set("key", key); return (String) redisUtil.get("key"); } @GetMapping("/helloList") public List<String> helloList(){ //向key中push一個(gè)元素“0” redisUtil.listLeftPush("key2", "0"); //把一個(gè)列表push進(jìn)key List<String> list = new ArrayList<>(Arrays.asList("1", "2")); redisUtil.listLeftPushAll("key2", list); //讀取存儲(chǔ)的列表中的全部元素,0, -1代表從第一個(gè)元素到最后一個(gè)元素 return redisUtil.listRange("key2", 0, -1); } }
五、操作演示
我們先來演示一下第二個(gè)方法,直接瀏覽器請(qǐng)求,可以看到,存入并查詢出了我們存入的數(shù)據(jù)
redis控制臺(tái)也能查詢出來
為什么先演示第二個(gè)方法呢,因?yàn)橐玫谝粋€(gè)向你們展示一個(gè)“小錯(cuò)誤”,我們輸入中文來測(cè)試一下
很棒,成功存入并正確讀取出來了對(duì)不對(duì)
那我們?nèi)タ刂婆_(tái)看一看,注意看,我們的鍵還是“key”,沒有亂碼,value的前半部分中文亂碼,后面的String是正常顯示的,說明這不是序列化的問題
解決方案是,使用 redis-cli --raw 進(jìn)入控制臺(tái),flushall 先清空數(shù)據(jù),再次請(qǐng)求接口存儲(chǔ)數(shù)據(jù),查詢出來的中文就出來了,但是我們還是看不懂,這和代碼和redis沒有關(guān)系
原因是電腦的 cmd 字符默認(rèn)是 GBK,你們bing一下,看看怎么把cmd改為 UTF-8,好像要從注冊(cè)表里面改,改好就可以正確顯示了
其實(shí)代碼可以正確讀取出來就說明一切正常的了,我們控制臺(tái)看到亂碼不必理會(huì),這里只是提一下
到此這篇關(guān)于Springboot 引入 Redis 并配置序列化并封裝RedisTemplate 的文章就介紹到這了,更多相關(guān)Springboot 引入 Redis 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Spring Initializr方式如何快速構(gòu)建Spring Boot項(xiàng)目
Spring lnitializr是一個(gè)Web應(yīng)用,它提供了一個(gè)基本的項(xiàng)目結(jié)構(gòu),能夠幫助我們快速構(gòu)建一個(gè)基礎(chǔ)的Spring Boot項(xiàng)目,本文分步驟講解如何使用Spring Initializr方式構(gòu)建Spring Boot項(xiàng)目,感興趣的朋友跟隨小編一起看看吧2023-08-08SpringBoot前后端分離實(shí)現(xiàn)個(gè)人博客系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了使用springboot+mybatis+前端vue,使用前后端分離架構(gòu)實(shí)現(xiàn)的個(gè)人博客系統(tǒng),感興趣的小伙伴可以動(dòng)手嘗試一下2022-06-06解決mysql字符串類型的數(shù)字排序出錯(cuò):cast(year as signed)
這篇文章主要介紹了解決mysql字符串類型的數(shù)字排序出錯(cuò)問題 :cast(year as signed),如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08Java中的自動(dòng)裝箱與自動(dòng)拆箱的實(shí)現(xiàn)
自動(dòng)裝箱和自動(dòng)拆箱使得我們?cè)谑褂没緮?shù)據(jù)類型時(shí)更加方便,同時(shí)也提高了代碼的可讀性和健壯性,本文將詳細(xì)介紹Java中的自動(dòng)裝箱和自動(dòng)拆箱機(jī)制,感興趣的可以了解一下2023-08-08Springboot 中使用 Aop代碼實(shí)戰(zhàn)教程
AOP的編程思想是把對(duì)類對(duì)象的橫切問題點(diǎn),從業(yè)務(wù)邏輯中分離出來,從而達(dá)到解耦的目的,增加代碼的復(fù)用性,提高開發(fā)效率,這篇文章主要介紹了Springboot中使用Aop代碼實(shí)戰(zhàn)教程,需要的朋友可以參考下2023-07-07java利用phantomjs進(jìn)行截圖實(shí)例教程
PlantomJs是一個(gè)基于javascript的webkit內(nèi)核無頭瀏覽器 也就是沒有顯示界面的瀏覽器,你可以在基于 webkit 瀏覽器做的事情,它都能做到。下面這篇文章主要給大家介紹了關(guān)于java利用phantomjs進(jìn)行截圖的相關(guān)資料,需要的朋友可以參考下2018-10-10