SpringBoot集成Redis及Redis使用方法
應(yīng)用背景
將一些經(jīng)常展現(xiàn)和不會(huì)頻繁變更的數(shù)據(jù),存放在存取速率更快的地方。 緩存就是一個(gè)存儲(chǔ)器,在技術(shù)選型中,常用 Redis 作為緩存數(shù)據(jù)庫,可以幫我們分散掉數(shù)據(jù)庫的壓力,有了它能更好的支持并發(fā)性能,主要是在獲取資源方便性能優(yōu)化的關(guān)鍵方面??梢赃@樣理解redis位于數(shù)據(jù)庫和springboot框架之間,起到數(shù)據(jù)緩存的作用。
Redis簡介
- Redis介紹:Redis是現(xiàn)在最受歡迎的NoSQL數(shù)據(jù)庫之一,Redis是一個(gè)使用ANSI C編寫的開源、包含多種數(shù)據(jù)結(jié)構(gòu)、支持網(wǎng)絡(luò)、基于內(nèi)存、可選持久性的鍵值對(duì)存儲(chǔ)數(shù)據(jù)庫。
- Redis使用場景:緩存系統(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ù)庫中取數(shù)據(jù),成功后,放到緩存中。
- 命中:應(yīng)用程序從cache中取數(shù)據(jù),取到后返回。
- 更新:先把數(shù)據(jù)存到數(shù)據(jù)庫中,成功后,再讓緩存失效。
更新問題
- 我們知道,在 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: 0
host: 127.0.0.1
port: 3304
password: 123456 # 密碼(默認(rèn)為空)
timeout: 6000ms # 連接超時(shí)時(shí)長(毫秒)
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ù)庫索引 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 {
@Autowired
private RedisConnectionFactory factory;
@Bean
public 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ù)
**/
@Bean
public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForHash();
}
/**
* HashOperations
* 操作 String 類型數(shù)據(jù)
**/
@Bean
public ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {
return redisTemplate.opsForValue();
}
/**
* HashOperations
* 操作 List 類型數(shù)據(jù)
**/
@Bean
public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForList();
}
/**
* HashOperations
* 操作 Set 類型數(shù)據(jù)
**/
@Bean
public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForSet();
}
/**
* HashOperations
* 操作 SortedSet 類型數(shù)據(jù)
**/
@Bean
public 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);
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private ValueOperations<String, String> valueOperations;
@Autowired
private HashOperations<String, String, Object> hashOperations;
@Autowired
private ListOperations<String, Object> listOperations;
@Autowired
private SetOperations<String, Object> setOperations;
@Autowired
private ZSetOperations<String, Object> zSetOperations;
/**默認(rèn)過期時(shí)長,單位: 秒*/
public final static long DEFAULT_EXPIRE = 60 * 10;
/**從配置文件獲取 默認(rèn)過期時(shí)長*/
@Value("${spring.redis.expire}")
public long expire;
/**不設(shè)置過期時(shí)長 */
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í)長*/
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的長度,當(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)的key
public final static String MAX_MOGUNO_KEY = "moguding:user:max_mogu_no";
//短信驗(yàn)證碼的key
public 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;
}
//用戶Token
public 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)告key
public 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 {
@Autowired
private 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í)長 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)獲取redisKey
public 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í)長
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 {
@Autowired
RedisTestService 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 {
@Autowired
UserRedis 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)為JsonArray
Map<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ù)作為key
Map<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集合1
List<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é)果:


- 使用SpringBoot集成redis的方法
- SpringBoot利用redis集成消息隊(duì)列的方法
- SpringBoot集成Redis的實(shí)現(xiàn)示例
- SpringBoot集成Redis實(shí)現(xiàn)消息隊(duì)列的方法
- springboot集成redis啟動(dòng)報(bào)錯(cuò)問題的解決方式
- springboot集成redis實(shí)現(xiàn)簡單秒殺系統(tǒng)
- 一起來看看springboot集成redis的使用注解
- SpringBoot3集成Redis的方法詳解
- SpringBoot集成Redis6.0的實(shí)現(xiàn)示例
相關(guān)文章
java實(shí)現(xiàn)數(shù)字轉(zhuǎn)大寫的方法
這篇文章主要介紹了 java實(shí)現(xiàn)數(shù)字轉(zhuǎn)大寫的方法的相關(guān)資料,希望通過本文能幫助到大家,讓大家實(shí)現(xiàn)這樣的功能,需要的朋友可以參考下2017-10-10
java如何發(fā)送get請(qǐng)求獲取數(shù)據(jù)(附代碼)
這篇文章主要給大家介紹了關(guān)于java如何發(fā)送get請(qǐng)求獲取數(shù)據(jù)的相關(guān)資料,Java中的GET請(qǐng)求方法是HTTP協(xié)議中的一種請(qǐng)求方式,用于向服務(wù)器請(qǐng)求獲取資源,需要的朋友可以參考下2023-10-10
使用MappingJackson2XmlView實(shí)現(xiàn)JSON到XML的視圖轉(zhuǎn)換
MappingJackson2XmlView來實(shí)現(xiàn)從JSON到XML格式的響應(yīng)轉(zhuǎn)換,本文將通過案例,將展示如何將JSON格式的數(shù)據(jù)轉(zhuǎn)換為XML格式,以滿足不同客戶端的數(shù)據(jù)交換需求,需要的朋友可以參考下2024-07-07
IDEA代碼規(guī)范&質(zhì)量檢查的實(shí)現(xiàn)
這篇文章主要介紹了IDEA代碼規(guī)范&質(zhì)量檢查的實(shí)現(xiàn),文中通過圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
Java調(diào)用bat執(zhí)行python腳本方式
文章介紹了如何在Windows環(huán)境下通過Java調(diào)用bat文件來執(zhí)行Python腳本,并解決了執(zhí)行過程中出現(xiàn)的中文亂碼問題,具體方法是修改bat文件的編碼格式為ANSI,這樣可以確保中文路徑不會(huì)因編碼問題而導(dǎo)致路徑錯(cuò)誤2025-10-10
spring?boot?3使用?elasticsearch?提供搜索建議的實(shí)例詳解
這篇文章主要介紹了spring?boot3使用elasticsearch提供搜索建議,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08
解決JSONObject.toJSONString()輸出null的問題
這篇文章主要介紹了解決JSONObject.toJSONString()輸出null的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02

