做網(wǎng)站的公司中國(guó)聯(lián)通業(yè)績(jī)
目錄
應(yīng)用背景
Redis簡(jiǎn)介
更新問題
一:環(huán)境配置
1.1: 在pom.xml文件中添加依賴
1.2:配置SpringBoot核心配置文件application.properties
二:在Config文件夾中創(chuàng)建RedisConfig配置文件類
2.1:RedisTemplate中的幾個(gè)角色:
2.2:為什么要自定義序列化:
2.2.1:Spring 中提供了以下幾個(gè)序列化器:
四:封裝Redis Utils工具包
4.1:RedisUtils.java
4.2:RedisKeys.java
4.3:UserRedis.java
五:流程實(shí)現(xiàn)
1.RedisTestController
?2.RedisTestService
3.RedisTestServiceImpl
4.AttributeData
?調(diào)用結(jié)果:
應(yīng)用背景
將一些經(jīng)常展現(xiàn)和不會(huì)頻繁變更的數(shù)據(jù),存放在存取速率更快的地方。 緩存就是一個(gè)存儲(chǔ)器,在技術(shù)選型中,常用 Redis 作為緩存數(shù)據(jù)庫(kù),可以幫我們分散掉數(shù)據(jù)庫(kù)的壓力,有了它能更好的支持并發(fā)性能,主要是在獲取資源方便性能優(yōu)化的關(guān)鍵方面??梢赃@樣理解redis位于數(shù)據(jù)庫(kù)和springboot框架之間,起到數(shù)據(jù)緩存的作用。
Redis簡(jiǎn)介
- Redis介紹:Redis是現(xiàn)在最受歡迎的NoSQL數(shù)據(jù)庫(kù)之一,Redis是一個(gè)使用ANSI C編寫的開源、包含多種數(shù)據(jù)結(jié)構(gòu)、支持網(wǎng)絡(luò)、基于內(nèi)存、可選持久性的鍵值對(duì)存儲(chǔ)數(shù)據(jù)庫(kù)。
- Redis使用場(chǎng)景:緩存系統(tǒng)(“熱點(diǎn)”數(shù)據(jù):高頻讀、低頻寫)、計(jì)數(shù)器、消息隊(duì)列系統(tǒng)、排行榜、社交網(wǎng)絡(luò)和實(shí)時(shí)系統(tǒng)
- Redis數(shù)據(jù)類型:Redis提供的數(shù)據(jù)類型主要分為5種自有類型和一種自定義類型,這5種自有類型包括:String類型、哈希類型、列表類型、集合類型和順序集合類型。
更新緩存模式 Cache aside
這是最常用最常用的pattern了。其具體邏輯如下:
- 失效:應(yīng)用程序先從cache取數(shù)據(jù),沒有得到,則從數(shù)據(jù)庫(kù)中取數(shù)據(jù),成功后,放到緩存中。
- 命中:應(yīng)用程序從cache中取數(shù)據(jù),取到后返回。
- 更新:先把數(shù)據(jù)存到數(shù)據(jù)庫(kù)中,成功后,再讓緩存失效。
更新問題
- 我們知道,在 springboot 1.5.x版本的默認(rèn)的Redis客戶端是 Jedis實(shí)現(xiàn)的,需要導(dǎo)入jedis依賴,而springboot 2.x版本中默認(rèn)客戶端是用 lettuce實(shí)現(xiàn)的,需要導(dǎo)入spring-boot-starter-data-redis依賴。這兩種方式使用的都是 TCP協(xié)議。可以理解為:咱們通過程序是不能直接連接 Redis,得利用客戶端工具才能進(jìn)行連接。比較常用的有兩種:
Jedis
、Lettuce
。既然?Lettuce
?和?Jedis
?的都是連接 Redis Server 的客戶端,那么它們有什么區(qū)別呢? - Jedis使用直連方式連接Redis Server,在多線程環(huán)境下存在線程安全問題, 因此需要增加連接池來解決線程安全的問題,同時(shí)可以限制redis客戶端的數(shù)量, 但這種直連方式基于傳統(tǒng)I/O模式,是阻塞式傳輸。
- 而 Lettuce 是 一種可伸縮,線程安全,完全非阻塞的Redis客戶端,底層基于netty通信,我們知道netty是基于NIO的非阻塞通信, 天生支持高并發(fā),因此在在多線程環(huán)境下不存在線程安全問題,一個(gè)連接實(shí)例就可以滿足多線程環(huán)境下的并發(fā)訪問, 當(dāng)然實(shí)例不夠的情況下也可以按需增加實(shí)例,保證伸縮性。
- 下面我們通過源碼的方式解析springboot是如何通過lettuce方式連接redis server的,以及springboot操作redis的底層原理。????????
?
一:環(huán)境配置
1.1: 在pom.xml文件中添加依賴
這里說說為什么要添加 org.apache.commons 依賴,如果不加,它會(huì)報(bào)錯(cuò):Caused by: java.lang.ClassNotFoundException: org.apache.commons.pool2.impl.GenericObjectPoolConfig
<dependencies><!-- SpringBoot集成Redis的起步依賴 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><version>1.4.7.RELEASE</version>
</dependency>
<!--lettuce 依賴commons-pool-->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.8.0</version>
</dependency></dependencies>
1.2:配置SpringBoot核心配置文件application.properties
- yml文件格式
spring: redis:open: true # 是否開啟redis緩存 true開啟 false關(guān)閉database: 0host: 127.0.0.1port: 3304password: 123456 # 密碼(默認(rèn)為空)timeout: 6000ms # 連接超時(shí)時(shí)長(zhǎng)(毫秒)expire: 3600 #7天不過期lettuce:pool:max-active: 100 # 連接池最大連接數(shù)(使用負(fù)值表示沒有限制)max-wait: -1ms # 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒有限制)max-idle: 20 # 連接池中的最大空閑連接min-idle: 5 # 連接池中的最小空閑連接
- properties文件格式
#Redis
##Redis數(shù)據(jù)庫(kù)索引
spring.redis.database=0
##Redis服務(wù)器地址
spring.redis.host=127.0.0.1
## Redis服務(wù)器連接端口
spring.redis.port=3304
## 連接超時(shí)時(shí)間(毫秒)
spring.redis.timeout=3
## Redis服務(wù)器連接密碼(默認(rèn)為空)
spring.redis.password=135246
## 連接池中的最大連接數(shù) (使用復(fù)數(shù)則標(biāo)識(shí)沒有限制) 默認(rèn) 8
spring.redis.pool.max.active=100
## 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒有限制)默認(rèn) -1
spring.redis.pool.max.wait=-1
## 連接池中的最大空閑連接 默認(rèn) 8
spring.redis.pool.max.idle=20
## 連接池中的最小空閑連接 默認(rèn) 0
spring.redis.pool.max.idle=0
二:在Config文件夾中創(chuàng)建RedisConfig配置文件類
RedisTemplate 是 Spring 操作 Redis 的重點(diǎn)內(nèi)容。 RedisTemplate是一個(gè)強(qiáng)大的類,首先它會(huì)自動(dòng)從 RedisConnectionFactory 工廠中獲取連接,然后執(zhí)行對(duì)應(yīng)的 Redis命令,提供了redis各種操作、異常處理及序列化,支持發(fā)布訂閱,并對(duì)spring 3.1 cache進(jìn)行了實(shí)現(xiàn),在最后還會(huì)關(guān)閉 Redis 的連接。
2.1:RedisTemplate中的幾個(gè)角色:
- RedisSerializer:由于與Redis服務(wù)器的通信一定是使用字節(jié)數(shù)組完成的,所以RedisSerializer是將Java對(duì)象編碼解碼的組件
- RedisOperations:封裝了一些Redis操作
- XXXOperations:封裝了指定類型或功能的數(shù)據(jù)的操作,如ZSetOperations
2.2:為什么要自定義序列化:
RedisTemplate操作時(shí),默認(rèn)會(huì)采用jdkSerializable序列化機(jī)制,使得插入的值在redis客戶端看來會(huì)有亂碼 類似于: "\xac\ced\x00\x05t\x00\x03key" ,所以解決這個(gè)問題就需要修改默認(rèn)的序列化規(guī)則。
2.2.1:Spring 中提供了以下幾個(gè)序列化器:
- Jackson2JsonRedisSerializer
- JdkSerializationRedisSerializer
- OxmSerializer
- StringRedisSerializer
- GenericToStringRedisSerializer
- GenericJackson2JsonRedisSerializer
本章使用的是StringRedisSerializer, String序列化方式。
RedisConfig 所在結(jié)構(gòu)地址:
?
?
package com.lizexin.springbootdemo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/*** 項(xiàng)目名稱:springboot-demo* 類名稱:RedisConfig* 類描述:Redis配置* 創(chuàng)建時(shí)間:2023/08/04* @author lzx* @version v1.0*/
@Configuration
public class RedisConfig {@Autowiredprivate RedisConnectionFactory factory;@Beanpublic RedisTemplate<String, Object> redisTemplate() {// 將template 泛型設(shè)置為 <String, Object>RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();// 使用 String 序列化方式,序列化 KEY。redisTemplate.setKeySerializer(new StringRedisSerializer());// 使用 String 序列化方式,序列化 VALUE。redisTemplate.setValueSerializer(new StringRedisSerializer());// 使用 String 序列化方式,序列化 HashKEY。redisTemplate.setHashKeySerializer(new StringRedisSerializer());// 使用 String 序列化方式,序列化 ValueKEY。redisTemplate.setHashValueSerializer(new StringRedisSerializer());// 配置連接工廠redisTemplate.setConnectionFactory(factory);return redisTemplate;}/*** HashOperations* 操作 Hash 類型數(shù)據(jù)**/@Beanpublic HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {return redisTemplate.opsForHash();}/*** HashOperations* 操作 String 類型數(shù)據(jù)**/@Beanpublic ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {return redisTemplate.opsForValue();}/*** HashOperations* 操作 List 類型數(shù)據(jù)**/@Beanpublic ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {return redisTemplate.opsForList();}/*** HashOperations* 操作 Set 類型數(shù)據(jù)**/@Beanpublic SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {return redisTemplate.opsForSet();}/*** HashOperations* 操作 SortedSet 類型數(shù)據(jù)**/@Beanpublic ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {return redisTemplate.opsForZSet();}
}
四:封裝Redis Utils工具包
Redis工具包分為三個(gè)類
1:RedisUtils.java? ? ?Redis方法類主要記錄對(duì)redis的一些操作,增刪改查等。
2:RedisKeys.java?? ?Redis自定義Key類,自定義配置,對(duì)redis操作時(shí)好分辨哪個(gè)key的數(shù)據(jù)
3:UserRedis.java? ? 封裝類,將RedisUtils和RedisKey進(jìn)行封裝,用戶直接操作此類
redis 工具包?所在結(jié)構(gòu)地址:
?
4.1:RedisUtils.java
package com.lizexin.springbootdemo.utils.redis;import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;/*** 項(xiàng)目名稱:springboot-demo* 類名稱:RedisUtils* 類描述:Redis工具類* 創(chuàng)建時(shí)間:2023/08/04* @author lzx* @version v1.0*/
@Component
public class RedisUtils {/**日志*/private static final Logger logger = LoggerFactory.getLogger(RedisUtils.class);@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Autowiredprivate ValueOperations<String, String> valueOperations;@Autowiredprivate HashOperations<String, String, Object> hashOperations;@Autowiredprivate ListOperations<String, Object> listOperations;@Autowiredprivate SetOperations<String, Object> setOperations;@Autowiredprivate ZSetOperations<String, Object> zSetOperations;/**默認(rèn)過期時(shí)長(zhǎng),單位: 秒*/public final static long DEFAULT_EXPIRE = 60 * 10;/**從配置文件獲取 默認(rèn)過期時(shí)長(zhǎng)*/@Value("${spring.redis.expire}")public long expire;/**不設(shè)置過期時(shí)長(zhǎng) */public final static long NOT_EXPIRE = -1;/**它可以幫助我們快速的進(jìn)行各個(gè)類型和Json類型的相互轉(zhuǎn)換*/private static final ObjectMapper MAPPER = new ObjectMapper();/**給指定key設(shè)置固定時(shí)間的有效期*/public void expireAt(String key,Date date){redisTemplate.expireAt(key,date);}/**根據(jù)指定的key,獲取過期時(shí)間*/public long getExpire(String key) { return redisTemplate.getExpire(key, TimeUnit.SECONDS);}/**判斷key是否存在*/public boolean hasKey(String key) {try {return redisTemplate.hasKey(key);} catch (Exception e) {e.printStackTrace();return false;}}/*** 刪除緩存, @param key可以傳一個(gè)值 或多個(gè)* 該注解屏蔽某些編譯時(shí)的警告信息* */@SuppressWarnings("unchecked")public void delete(String... key) {if (key != null && key.length > 0) {if (key.length == 1) {redisTemplate.delete(key[0]);} else {redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));}}}/**將Object值放如緩存并設(shè)置默認(rèn)時(shí)間,調(diào)用下一個(gè)方法將值轉(zhuǎn)為JSON字符串*/public void set(String key, Object value){set(key, value, DEFAULT_EXPIRE);}/**將Object值轉(zhuǎn)為JSON字符串放入緩存,并設(shè)置過期時(shí)長(zhǎng)*/public void set(String key, Object value, long expire){valueOperations.set(key, objectToJson(value));if(expire != NOT_EXPIRE){redisTemplate.expire(key, expire, TimeUnit.SECONDS);}}/**根據(jù)key和泛型獲取值, 調(diào)用下一個(gè)get方法*/public <T> T get(String key, Class<T> clazz) {return get(key, clazz, NOT_EXPIRE);}/**根據(jù)key鍵獲取值并轉(zhuǎn)為對(duì)象 并重新設(shè)置過期時(shí)間*/public <T> T get(String key, Class<T> clazz, long expire) {String value = valueOperations.get(key);if(expire != NOT_EXPIRE){redisTemplate.expire(key, expire, TimeUnit.SECONDS);}//將Json字符串轉(zhuǎn)換為bean對(duì)象return value == null ? null : fromJson(value, clazz);}/**根據(jù)key鍵獲取值返回為String*/public String get(String key, long expire) {String value = valueOperations.get(key);if(expire != NOT_EXPIRE){redisTemplate.expire(key, expire, TimeUnit.SECONDS);}return value;}/*根據(jù)key獲取值*/public String get(String key) {return get(key, NOT_EXPIRE);}/**Object轉(zhuǎn)換為JSON字符串,在存reid的時(shí)候調(diào)用此方法*/private String objectToJson(Object object){if(object instanceof Integer || object instanceof Long || object instanceof Float ||object instanceof Double || object instanceof Boolean || object instanceof String){return String.valueOf(object);}return JSONUtil.toJsonStr(object);}/**JSON字符串, 轉(zhuǎn)成javaBean對(duì)象*/private <T> T fromJson(String json, Class<T> clazz){return JSONUtil.toBean(json, clazz);//return JSON.parseObject(json,clazz);}/**將JsonObject轉(zhuǎn)為實(shí)體類對(duì)象,轉(zhuǎn)換異常將被拋出*/public static <T> T fromJsonToBean(JSONObject json, Class<T> beanClass) {return null == json ? null : json.toBean(beanClass);}/**將元素添加到指定set集合中*/public void addToSet(String key,String member){redisTemplate.opsForSet().add(key,member);}/**批量添加到指定set集合中*/public void addBatchToSet(String key,List<String> memberList) {Object[] members = memberList.toArray();redisTemplate.opsForSet().add(key,members);}/**統(tǒng)計(jì)指定set的長(zhǎng)度,當(dāng)指定key的set不存在時(shí),返回null*/public Long countForSet(String key){return redisTemplate.opsForSet().size(key);}/**只有當(dāng)key不存在時(shí)才設(shè)置key的值,并返回true;當(dāng)key存在時(shí)不修改key的值,并返回false。*/public Boolean isMember(String value){return setOperations.isMember(RedisKeys.AutoKey,value);}/**向集合添加值并設(shè)置過期時(shí)間*/public Long addSetDataExpire(String value,String name,long expire){Long addSet = setOperations.add(name,value);if(expire != NOT_EXPIRE){redisTemplate.expire(name, expire, TimeUnit.SECONDS);}return addSet;}/**向右邊批量添加元素*/public boolean addrightPushAll(String key, List<Object> value) {boolean var4;try {this.redisTemplate.opsForList().rightPushAll(key, value);boolean var3 = true;return var3;} catch (Exception var8) {logger.error("", var8);var4 = false;} finally {this.close();}return var4;}/** * 獲取泛型的Collection Type* @param collectionClass 泛型的Collection* @param elementClasses 元素類* @return JavaType Java類型* @since 1.0*/public static JavaType getCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {return MAPPER.getTypeFactory().constructParametricType(collectionClass, elementClasses);}private void close() {RedisConnectionUtils.unbindConnection(this.redisTemplate.getConnectionFactory());}
}
4.2:RedisKeys.java
package com.zhangtao.moguding.province.utils.redis;/*** 項(xiàng)目名稱:user-center-service* 類名稱:RedisKeys* 類描述:redis所有的key* 創(chuàng)建時(shí)間:2023/7/27** @author lzx* @version v1.0*/
public class RedisKeys {//最大蘑菇號(hào)的keypublic final static String MAX_MOGUNO_KEY = "moguding:user:max_mogu_no";//短信驗(yàn)證碼的keypublic static String getSmsCodeKey(String key,Integer type){return "moguding:user:smsCode:" + key+":"+type;}//權(quán)限列表public final static String PERMISSIONS_USERAUTH_KEY = "moguding:permissions:permissions_userauth_list:";//參數(shù)配置public static String getUserConfigKey(String... key){return "moguding:user:config:" + key;}//用戶Tokenpublic final static String AUTH_TOKEN_KEY = "moguding:user:authToken:";//authtoken的key web端public static String getAuthToken(String type,String userid){if("web".equals(type)){return AUTH_TOKEN_KEY+type+":" + userid;}else {return getAuthToken(userid);}}//authtoken的key app端public static String getAuthToken(String userid){return AUTH_TOKEN_KEY+ userid;}//緩存活躍蘑菇號(hào)key的public final static String ACTIVE_MOGU_NO= "moguding:user:active:";//緩存今日學(xué)校簽到排行榜public final static String SCHOOL_SIGN_RANK= "moguding:school:sign:rank";//學(xué)校統(tǒng)計(jì)(實(shí)時(shí)發(fā)送【考勤,上崗,周報(bào)】)public final static String SCHOOL_COUNT= "moguding.school.count";//自動(dòng)報(bào)告keypublic final static String AutoKey = "autoReport_set";//30天最后一次考勤public final static String LastSign = "moguding.last.sign";//省平臺(tái)基礎(chǔ)數(shù)據(jù)public static String getProvinceConfigKey(String key){return "moguding:province:config:" + key;}
}
4.3:UserRedis.java
package com.zhangtao.moguding.province.utils.redis;
import com.zhangtao.moguding.province.entity.UserConfigEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.List;/*** 項(xiàng)目名稱:user-center-service* 類名稱:UserRedis* 類描述:UserRedis* 創(chuàng)建時(shí)間:2019/5/27* @author lzx* @version v1.0*/
/**將RedisUtils的set方法和RedisKeys的key 封裝到一起* */
@Component
public class UserRedis {@Autowiredprivate RedisUtils redisUtils;public void set(String key,String value) {if(key == null){return ;}String redisKey = RedisKeys.getUserConfigKey(key);redisUtils.set(redisKey, value,redisUtils.expire);}public void delete(String key) {if(key == null){return ;}String redisKey = RedisKeys.getUserConfigKey(key);redisUtils.delete(redisKey);}public String get(String key){if(key == null){return null;}String redisKey = RedisKeys.getUserConfigKey(key);return redisUtils.get(redisKey);}public UserConfigEntity getObject(String key){if(key == null){return null;}String redisKey = RedisKeys.getUserConfigKey(key);return redisUtils.get(redisKey, UserConfigEntity.class);}//向Redis添加值,設(shè)置默認(rèn)過期時(shí)長(zhǎng) 7天, set方法將value進(jìn)行序列化(轉(zhuǎn)為JSON字符串)
/* public void set(String key,Object value) {if(key == null){return ;}String redisKey = RedisKeys.getRedisTestKey(key);redisUtils.set(redisKey, value,redisUtils.expire);}public <T> T get(String key, Class<T> clazz){if(key == null){return null;}String redisKey = RedisKeys.getRedisTestKey(key);return redisUtils.get(redisKey,clazz);}//判斷Redis測(cè)試key是否存在public boolean hasKey(String key){if(key == null){return false;}String redisKey = RedisKeys.getRedisTestKey(key);return redisUtils.hasKey(redisKey);};*///將今日活躍用戶的蘑菇號(hào)批量存進(jìn)redis指定Set集合中public void addUserMoguNosToSet(List<String> moguNos){redisUtils.addBatchToSet(RedisKeys.ACTIVE_MOGU_NO,moguNos);}//將今日活躍用戶的蘑菇號(hào)緩存Set集合清空public void deleteForCacheUserMoguNo(){redisUtils.delete(RedisKeys.ACTIVE_MOGU_NO);}//判斷Redis測(cè)試key是否存在public boolean hasKey(String key){if(key == null){return false;}String redisKey = RedisKeys.getProvinceConfigKey(key);return redisUtils.hasKey(redisKey);};//從redis中統(tǒng)計(jì)活躍用戶數(shù)量public int countActiveUser(){Long Lnum = redisUtils.countForSet(RedisKeys.ACTIVE_MOGU_NO);if(Lnum==null){return 0;}else {return Lnum.intValue();}}//省級(jí)平臺(tái)獲取redisKeypublic String getProvinceKey(String key){if(key == null){return null;}String redisKey = RedisKeys.getProvinceConfigKey(key);return redisUtils.get(redisKey);}//省級(jí)平臺(tái)向redis插入數(shù)據(jù)public void setProvinceDataToRedis(String key,String list){String keys = RedisKeys.getProvinceConfigKey(key);//配置文件默認(rèn)保留時(shí)長(zhǎng)redisUtils.setRedis(keys,list,redisUtils.expire);}
}
五:流程實(shí)現(xiàn)
模擬SpringBoot項(xiàng)目結(jié)構(gòu)調(diào)用
1.RedisTestController
package com.lizexin.springbootdemo.Controller;
import com.lizexin.springbootdemo.entity.Item;
import com.lizexin.springbootdemo.service.RedisTestService;
import com.zhangtao.common.dto.response.BaseResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @program: springboot-demo* @author: lzx* @Time: 2023/8/9 16:35* @description: Redis測(cè)試接口* @version: v1.0*/@RestController
@Api(tags = {"Redis測(cè)試接口"},produces = "RedisTest_controller")
@RequestMapping("/redis")
public class RedisTestController {@AutowiredRedisTestService redisTestService;private Logger logger = LoggerFactory.getLogger(RedisTestController.class);@ApiOperation(value = "Redis測(cè)試,將對(duì)象插入緩存",notes = "")@RequestMapping("/v1/test")public BaseResponse redisInsertBeanController(@RequestBody Item item){return redisTestService.redisInsertBeanService(item);}@ApiOperation(value = "Redis測(cè)試,將List插入緩存",notes = "")@RequestMapping("/v2/test")public BaseResponse redisInsertListController(@RequestBody Item item){return redisTestService.redisInsertListService(item);}@ApiOperation(value = "Redis測(cè)試,將Map<String,Set<String>>插入緩存,取出來轉(zhuǎn)Map<String,JsonArry>",notes = "")@RequestMapping("/v3/test")public BaseResponse redisInsertMapController(@RequestBody Item item){return redisTestService.redisInsertMapService(item);}
}
?2.RedisTestService
package com.lizexin.springbootdemo.service;import com.lizexin.springbootdemo.entity.Item;
import com.zhangtao.common.dto.response.BaseResponse;/*** @program: springboot-demo* @author: lzx* @Time: 2023/8/9 22:55* @description: Redis測(cè)試接口Service* @version: v1.0*/
public interface RedisTestService {BaseResponse redisInsertBeanService( Item item);BaseResponse redisInsertListService( Item item);BaseResponse redisInsertMapService( Item item);
}
3.RedisTestServiceImpl
package com.lizexin.springbootdemo.service.impl;import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONArray;
import com.lizexin.springbootdemo.entity.Item;
import com.lizexin.springbootdemo.service.RedisTestService;
import com.lizexin.springbootdemo.utils.*;
import com.lizexin.springbootdemo.utils.redis.UserRedis;
import com.zhangtao.common.dto.response.BaseResponse;
import com.zhangtao.common.dto.response.ObjectResponse;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.*;
import java.util.stream.Collectors;/*** @program: springboot-demo* @author: lzx* @Time: 2023/08/9 22:58* @description: test* @version: v1.0*/
@Service
public class RedisTestServiceImpl implements RedisTestService {@AutowiredUserRedis userRedis;private static final Logger logger = LoggerFactory.getLogger(RedisTestServiceImpl.class);@Override@ApiOperation("通過key得到值并重新設(shè)置過期時(shí)間,若值不存在則重新插入緩存。"+"set方法封裝了 JSONUtil.toJsonStr"+ "get帶泛型的方法封裝了JSONUtil.toBean ")public BaseResponse redisInsertBeanService(Item item) {String redisKey= "redisInsertBeanService";System.out.println(redisKey);//判斷key值是否存在,如果存在則優(yōu)先取緩存if (userRedis.hasKey(redisKey)){Item jsonString= userRedis.get(redisKey,Item.class);logger.info("存在值");logger.info(jsonString.toString());return ObjectResponse.resObj(jsonString);}else{//不存在則緩存Item item1= AttributeData.list9();logger.info("不存在值 插入");userRedis.set(redisKey,item1);return ObjectResponse.ok();}}@Override@ApiOperation("get方法不帶泛型默認(rèn)返回Json字符串,需要自行反序列化")public BaseResponse redisInsertListService(Item item) {//通過key得到值,String redisKey = "redisInsertListService";System.out.println(redisKey);//判斷key值是否存在,如果存在則優(yōu)先取緩存if (userRedis.hasKey(redisKey)){List<Item> list = JSONArray.parseArray(userRedis.get(redisKey),Item.class);logger.info("存在值");logger.info(list.toString());return ObjectResponse.resObj(list);}else{//不存在則緩存List<Item> list= AttributeData.list8();logger.info("不存在值 插入");userRedis.set(redisKey,list);return ObjectResponse.ok();}}@Override@ApiOperation("")public BaseResponse redisInsertMapService(Item item) {//通過key得到值,String redisKey= "redisInsertMapService";System.out.println(redisKey);//判斷key值是否存在,如果存在則優(yōu)先取緩存if (userRedis.hasKey(redisKey)){String jsonString= userRedis.get(redisKey);//可以通過JSonString轉(zhuǎn)對(duì)象方法把Vlue值從Set轉(zhuǎn)為JsonArrayMap<String,JSONArray> arrayMap= JSONUtil.toBean(jsonString,Map.class);logger.info("存在值");logger.info(arrayMap.toString());return ObjectResponse.resObj(arrayMap);}else{//不存在則緩存List<Item> list= AttributeData.list10();//根據(jù)key轉(zhuǎn)map,之后將Value換成set集合//將集合添加至Map 指定參數(shù)作為keyMap<String,List<Item>> map = new HashMap();Map<String,Set<String>>setMap =new HashMap<>();map = list.stream().collect(Collectors.groupingBy(Item::getName,Collectors.toList()));for (Map.Entry<String,List<Item>> key:map.entrySet()){Set<String> set = new HashSet<>();key.getValue().forEach(c->{set.add(c.getValue());});setMap.put(key.getKey(), set);}logger.info("不存在值 插入");userRedis.set(redisKey,setMap);return ObjectResponse.ok();}}}
4.AttributeData
package com.lizexin.springbootdemo.utils;
import com.lizexin.springbootdemo.dto.CommonInterfaceDto;
import com.lizexin.springbootdemo.dto.InformationDatasDto;
import com.lizexin.springbootdemo.dto.export.ExportGxySchoolFlowDto;
import com.lizexin.springbootdemo.entity.Item;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @program: springboot-demo* @author: lzx* @Time: 2023/8/9 22:55* @description: 常用數(shù)據(jù)集* @version: v1.0*/
public class AttributeData {public static List<Map<String,Object>> list1 (){//構(gòu)建List集合1List<Map<String,Object>> list1 = new ArrayList<>();Map<String,Object> data=new HashMap<>();data.put("userId","100001");data.put("userName","唐僧");list1.add(data);data=new HashMap<>();data.put("userId","100002");data.put("userName","八戒");list1.add(data);data=new HashMap<>();data.put("userId","100003");data.put("userName","悟空");list1.add(data);data=new HashMap<>();data.put("userId","100004");data.put("userName","沙僧");list1.add(data);return list1;}public static List<Map<String,Object>> list2(){Map<String,Object> data=new HashMap<>();List<Map<String,Object>> list2 = new ArrayList<>();data=new HashMap<>();data.put("userId","100001");data.put("gender","男");data.put("age",20);list2.add(data);data=new HashMap<>();data.put("userId","100002");data.put("gender","雄");data.put("age",1000);list2.add(data);data=new HashMap<>();data.put("userId","100003");data.put("gender","雄");data.put("age",600);list2.add(data);data=new HashMap<>();data.put("userId","100004");data.put("gender","男");data.put("age",800);list2.add(data);return list2;}public static List<InformationDatasDto> list3(){List<InformationDatasDto> list = new ArrayList<>();InformationDatasDto info = new InformationDatasDto();info.setStudentId("10000");info.setStudent_name("張三");list.add(info);info = new InformationDatasDto();info.setStudentId("10001");info.setStudent_name("里李四");list.add(info);info = new InformationDatasDto();info.setStudentId("10002");info.setStudent_name("王五");list.add(info);info = new InformationDatasDto();info.setStudentId("10003");info.setStudent_name("趙六");list.add(info);info = new InformationDatasDto();info.setStudentId("10004");info.setStudent_name("馬七");list.add(info);return list;}public static List<InformationDatasDto> list4(){List<InformationDatasDto> list = new ArrayList<>();InformationDatasDto info = new InformationDatasDto();info.setStudentId("北京");info.setStudent_name("張三");list.add(info);info = new InformationDatasDto();info.setStudentId("北京省");info.setStudent_name("里李四");list.add(info);info = new InformationDatasDto();info.setStudentId("湖北省");info.setStudent_name("王五");list.add(info);info = new InformationDatasDto();info.setStudentId("湖北");info.setStudent_name("趙六");list.add(info);info = new InformationDatasDto();info.setStudentId("海南");info.setStudent_name("馬七");list.add(info);return list;}public static List<ExportGxySchoolFlowDto> list5(){List<ExportGxySchoolFlowDto> list = new ArrayList<>();ExportGxySchoolFlowDto info = new ExportGxySchoolFlowDto();info.setSchoolName("齊齊哈爾大學(xué)");info.setDatas("黑龍江省");info.setValue(10);list.add(info);info = new ExportGxySchoolFlowDto();info.setSchoolName("齊齊哈爾大學(xué)");info.setDatas("黑龍江");info.setValue(20);list.add(info);info = new ExportGxySchoolFlowDto();info.setSchoolName("齊齊哈爾大學(xué)");info.setDatas("黑龍江省哈爾濱市");info.setValue(20);list.add(info);info = new ExportGxySchoolFlowDto();info.setSchoolName("齊齊哈爾大學(xué)");info.setDatas("甘肅省");info.setValue(20);list.add(info);info = new ExportGxySchoolFlowDto();info.setSchoolName("哈爾濱大學(xué)");info.setDatas("黑龍江");info.setValue(20);list.add(info);info = new ExportGxySchoolFlowDto();info.setSchoolName("武漢職業(yè)大學(xué)");info.setDatas("北京市");info.setValue(10);list.add(info);info = new ExportGxySchoolFlowDto();info.setSchoolName("黑河市大學(xué)");info.setDatas("北京");info.setValue(10);list.add(info);return list;}public static List<CommonInterfaceDto.ItemBatchDataDto> list6(){List<CommonInterfaceDto.ItemBatchDataDto> list =new ArrayList<>();CommonInterfaceDto.ItemBatchDataDto item1 =new CommonInterfaceDto.ItemBatchDataDto();item1.setSchoolName("雙高校");item1.setData(10);item1.setBatchName("19年");list.add(item1);CommonInterfaceDto.ItemBatchDataDto item2 =new CommonInterfaceDto.ItemBatchDataDto();item2.setSchoolName("雙高校");item2.setData(20);item2.setBatchName("20年");list.add(item2);CommonInterfaceDto.ItemBatchDataDto item3 =new CommonInterfaceDto.ItemBatchDataDto();item3.setSchoolName("雙高校");item3.setData(30);item3.setBatchName("21年");list.add(item3);CommonInterfaceDto.ItemBatchDataDto item4 =new CommonInterfaceDto.ItemBatchDataDto();item4.setSchoolName("雙高校");item4.setData(40);item4.setBatchName("22年");list.add(item4);return list;}public static List<CommonInterfaceDto.ItemBatchDataDto> list7(){List<CommonInterfaceDto.ItemBatchDataDto> list =new ArrayList<>();CommonInterfaceDto.ItemBatchDataDto item1 =new CommonInterfaceDto.ItemBatchDataDto();item1.setSchoolName("鄭州經(jīng)貿(mào)學(xué)院");item1.setData(60);item1.setBatchName("19年");list.add(item1);CommonInterfaceDto.ItemBatchDataDto item2 =new CommonInterfaceDto.ItemBatchDataDto();item2.setSchoolName("鄭州經(jīng)貿(mào)學(xué)院");item2.setData(10);item2.setBatchName("22年");list.add(item2);return list;}public static List<Item> list8(){List<Item> list =new ArrayList<>();Item item1 =new Item();item1.setName("計(jì)算機(jī)");item1.setValue(10);list.add(item1);Item item2 =new Item();item2.setName("會(huì)計(jì)");item2.setValue(20);list.add(item2);Item item3 =new Item();item3.setName("銷售");item3.setValue(30);list.add(item3);Item item4 =new Item();item4.setName("老師");item4.setValue(40);list.add(item4);Item item5 =new Item();item5.setName("醫(yī)學(xué)");item5.setValue(40);list.add(item5);Item item6 =new Item();item6.setName("農(nóng)業(yè)");item6.setValue(94);list.add(item6);Item item7 =new Item();item7.setName("工程");item7.setValue(100);list.add(item7);return list;}public static Item list9(){Item item7 =new Item();item7.setName("工程");item7.setValue(100);return item7;}public static List<Item> list10(){List<Item> list =new ArrayList<>();Item item1 =new Item();item1.setName("河南省");item1.setValue("鄭州市");list.add(item1);Item item2 =new Item();item2.setName("河南省");item2.setValue("洛陽市");list.add(item2);Item item3 =new Item();item3.setName("河南省");item3.setValue("開封市");list.add(item3);Item item4 =new Item();item4.setName("湖北省");item4.setValue("武漢市");list.add(item4);Item item5 =new Item();item5.setName("湖北省");item5.setValue("襄陽市");list.add(item5);Item item6 =new Item();item6.setName("湖北省");item6.setValue("潛江市");list.add(item6);Item item7 =new Item();item7.setName("湖北省");item7.setValue("荊州市");list.add(item7);Item item8 =new Item();item8.setName("北京");item8.setValue("北京市");list.add(item8);return list;}}
?調(diào)用結(jié)果:
?