目录
应用背景
Redis简介
更新问题
一:环境配置
1.1: 在pom.xml文件中添加依赖
1.2:配置SpringBoot核心配置文件application.properties
二:在Config文件夹中创建RedisConfig配置文件类
2.1:RedisTemplate中的几个角色:
2.2:为什么要自定义序列化:
2.2.1:Spring 中提供了以下几个序列化器:
四:封装Redis Utils工具包
4.1:RedisUtils.java
4.2:RedisKeys.java
4.3:UserRedis.java
五:流程实现
1.RedisTestController
2.RedisTestService
3.RedisTestServiceImpl
4.AttributeData
调用结果:
应用背景
将一些经常展现和不会频繁变更的数据,存放在存取速率更快的地方。 缓存就是一个存储器,在技术选型中,常用 Redis 作为缓存数据库,可以帮我们分散掉数据库的压力,有了它能更好的支持并发性能,主要是在获取资源方便性能优化的关键方面。可以这样理解redis位于数据库和springboot框架之间,起到数据缓存的作用。
Redis简介
- Redis介绍:Redis是现在最受欢迎的NoSQL数据库之一,Redis是一个使用ANSI C编写的开源、包含多种数据结构、支持网络、基于内存、可选持久性的键值对存储数据库。
- Redis使用场景:缓存系统(“热点”数据:高频读、低频写)、计数器、消息队列系统、排行榜、社交网络和实时系统
- Redis数据类型:Redis提供的数据类型主要分为5种自有类型和一种自定义类型,这5种自有类型包括:String类型、哈希类型、列表类型、集合类型和顺序集合类型。
更新缓存模式 Cache aside
这是最常用最常用的pattern了。其具体逻辑如下:
- 失效:应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放到缓存中。
- 命中:应用程序从cache中取数据,取到后返回。
- 更新:先把数据存到数据库中,成功后,再让缓存失效。
更新问题
- 我们知道,在 springboot 1.5.x版本的默认的Redis客户端是 Jedis实现的,需要导入jedis依赖,而springboot 2.x版本中默认客户端是用 lettuce实现的,需要导入spring-boot-starter-data-redis依赖。这两种方式使用的都是 TCP协议。可以理解为:咱们通过程序是不能直接连接 Redis,得利用客户端工具才能进行连接。比较常用的有两种:
Jedis
、Lettuce
。既然Lettuce
和Jedis
的都是连接 Redis Server 的客户端,那么它们有什么区别呢? - Jedis使用直连方式连接Redis Server,在多线程环境下存在线程安全问题, 因此需要增加连接池来解决线程安全的问题,同时可以限制redis客户端的数量, 但这种直连方式基于传统I/O模式,是阻塞式传输。
- 而 Lettuce 是 一种可伸缩,线程安全,完全非阻塞的Redis客户端,底层基于netty通信,我们知道netty是基于NIO的非阻塞通信, 天生支持高并发,因此在在多线程环境下不存在线程安全问题,一个连接实例就可以满足多线程环境下的并发访问, 当然实例不够的情况下也可以按需增加实例,保证伸缩性。
- 下面我们通过源码的方式解析springboot是如何通过lettuce方式连接redis server的,以及springboot操作redis的底层原理。
一:环境配置
1.1: 在pom.xml文件中添加依赖
这里说说为什么要添加 org.apache.commons 依赖,如果不加,它会报错: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关闭database: 0host: 127.0.0.1port: 3304password: 123456 # 密码(默认为空)timeout: 6000ms # 连接超时时长(毫秒)expire: 3600 #7天不过期lettuce:pool:max-active: 100 # 连接池最大连接数(使用负值表示没有限制)max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)max-idle: 20 # 连接池中的最大空闲连接min-idle: 5 # 连接池中的最小空闲连接
- properties文件格式
#Redis
##Redis数据库索引
spring.redis.database=0
##Redis服务器地址
spring.redis.host=127.0.0.1
## Redis服务器连接端口
spring.redis.port=3304
## 连接超时时间(毫秒)
spring.redis.timeout=3
## Redis服务器连接密码(默认为空)
spring.redis.password=135246
## 连接池中的最大连接数 (使用复数则标识没有限制) 默认 8
spring.redis.pool.max.active=100
## 连接池最大阻塞等待时间(使用负值表示没有限制)默认 -1
spring.redis.pool.max.wait=-1
## 连接池中的最大空闲连接 默认 8
spring.redis.pool.max.idle=20
## 连接池中的最小空闲连接 默认 0
spring.redis.pool.max.idle=0
二:在Config文件夹中创建RedisConfig配置文件类
RedisTemplate 是 Spring 操作 Redis 的重点内容。 RedisTemplate是一个强大的类,首先它会自动从 RedisConnectionFactory 工厂中获取连接,然后执行对应的 Redis命令,提供了redis各种操作、异常处理及序列化,支持发布订阅,并对spring 3.1 cache进行了实现,在最后还会关闭 Redis 的连接。
2.1:RedisTemplate中的几个角色:
- RedisSerializer:由于与Redis服务器的通信一定是使用字节数组完成的,所以RedisSerializer是将Java对象编码解码的组件
- RedisOperations:封装了一些Redis操作
- XXXOperations:封装了指定类型或功能的数据的操作,如ZSetOperations
2.2:为什么要自定义序列化:
RedisTemplate操作时,默认会采用jdkSerializable序列化机制,使得插入的值在redis客户端看来会有乱码 类似于: "\xac\ced\x00\x05t\x00\x03key" ,所以解决这个问题就需要修改默认的序列化规则。
2.2.1:Spring 中提供了以下几个序列化器:
- Jackson2JsonRedisSerializer
- JdkSerializationRedisSerializer
- OxmSerializer
- StringRedisSerializer
- GenericToStringRedisSerializer
- GenericJackson2JsonRedisSerializer
本章使用的是StringRedisSerializer, String序列化方式。
RedisConfig 所在结构地址:
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;
/*** 项目名称:springboot-demo* 类名称:RedisConfig* 类描述:Redis配置* 创建时间:2023/08/04* @author lzx* @version v1.0*/
@Configuration
public class RedisConfig {@Autowiredprivate RedisConnectionFactory factory;@Beanpublic RedisTemplate<String, Object> redisTemplate() {// 将template 泛型设置为 <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 类型数据**/@Beanpublic HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {return redisTemplate.opsForHash();}/*** HashOperations* 操作 String 类型数据**/@Beanpublic ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {return redisTemplate.opsForValue();}/*** HashOperations* 操作 List 类型数据**/@Beanpublic ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {return redisTemplate.opsForList();}/*** HashOperations* 操作 Set 类型数据**/@Beanpublic SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {return redisTemplate.opsForSet();}/*** HashOperations* 操作 SortedSet 类型数据**/@Beanpublic ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {return redisTemplate.opsForZSet();}
}
四:封装Redis Utils工具包
Redis工具包分为三个类
1:RedisUtils.java Redis方法类主要记录对redis的一些操作,增删改查等。
2:RedisKeys.java Redis自定义Key类,自定义配置,对redis操作时好分辨哪个key的数据
3:UserRedis.java 封装类,将RedisUtils和RedisKey进行封装,用户直接操作此类
redis 工具包 所在结构地址:
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;/*** 项目名称:springboot-demo* 类名称:RedisUtils* 类描述:Redis工具类* 创建时间: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;/**默认过期时长,单位: 秒*/public final static long DEFAULT_EXPIRE = 60 * 10;/**从配置文件获取 默认过期时长*/@Value("${spring.redis.expire}")public long expire;/**不设置过期时长 */public final static long NOT_EXPIRE = -1;/**它可以帮助我们快速的进行各个类型和Json类型的相互转换*/private static final ObjectMapper MAPPER = new ObjectMapper();/**给指定key设置固定时间的有效期*/public void expireAt(String key,Date date){redisTemplate.expireAt(key,date);}/**根据指定的key,获取过期时间*/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可以传一个值 或多个* 该注解屏蔽某些编译时的警告信息* */@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值放如缓存并设置默认时间,调用下一个方法将值转为JSON字符串*/public void set(String key, Object value){set(key, value, DEFAULT_EXPIRE);}/**将Object值转为JSON字符串放入缓存,并设置过期时长*/public void set(String key, Object value, long expire){valueOperations.set(key, objectToJson(value));if(expire != NOT_EXPIRE){redisTemplate.expire(key, expire, TimeUnit.SECONDS);}}/**根据key和泛型获取值, 调用下一个get方法*/public <T> T get(String key, Class<T> clazz) {return get(key, clazz, NOT_EXPIRE);}/**根据key键获取值并转为对象 并重新设置过期时间*/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字符串转换为bean对象return value == null ? null : fromJson(value, clazz);}/**根据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;}/*根据key获取值*/public String get(String key) {return get(key, NOT_EXPIRE);}/**Object转换为JSON字符串,在存reid的时候调用此方法*/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字符串, 转成javaBean对象*/private <T> T fromJson(String json, Class<T> clazz){return JSONUtil.toBean(json, clazz);//return JSON.parseObject(json,clazz);}/**将JsonObject转为实体类对象,转换异常将被抛出*/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);}/**统计指定set的长度,当指定key的set不存在时,返回null*/public Long countForSet(String key){return redisTemplate.opsForSet().size(key);}/**只有当key不存在时才设置key的值,并返回true;当key存在时不修改key的值,并返回false。*/public Boolean isMember(String value){return setOperations.isMember(RedisKeys.AutoKey,value);}/**向集合添加值并设置过期时间*/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;/*** 项目名称:user-center-service* 类名称:RedisKeys* 类描述:redis所有的key* 创建时间:2023/7/27** @author lzx* @version v1.0*/
public class RedisKeys {//最大蘑菇号的keypublic final static String MAX_MOGUNO_KEY = "moguding:user:max_mogu_no";//短信验证码的keypublic static String getSmsCodeKey(String key,Integer type){return "moguding:user:smsCode:" + key+":"+type;}//权限列表public final static String PERMISSIONS_USERAUTH_KEY = "moguding:permissions:permissions_userauth_list:";//参数配置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;}//缓存活跃蘑菇号key的public final static String ACTIVE_MOGU_NO= "moguding:user:active:";//缓存今日学校签到排行榜public final static String SCHOOL_SIGN_RANK= "moguding:school:sign:rank";//学校统计(实时发送【考勤,上岗,周报】)public final static String SCHOOL_COUNT= "moguding.school.count";//自动报告keypublic final static String AutoKey = "autoReport_set";//30天最后一次考勤public final static String LastSign = "moguding.last.sign";//省平台基础数据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;/*** 项目名称:user-center-service* 类名称:UserRedis* 类描述:UserRedis* 创建时间: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添加值,设置默认过期时长 7天, set方法将value进行序列化(转为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测试key是否存在public boolean hasKey(String key){if(key == null){return false;}String redisKey = RedisKeys.getRedisTestKey(key);return redisUtils.hasKey(redisKey);};*///将今日活跃用户的蘑菇号批量存进redis指定Set集合中public void addUserMoguNosToSet(List<String> moguNos){redisUtils.addBatchToSet(RedisKeys.ACTIVE_MOGU_NO,moguNos);}//将今日活跃用户的蘑菇号缓存Set集合清空public void deleteForCacheUserMoguNo(){redisUtils.delete(RedisKeys.ACTIVE_MOGU_NO);}//判断Redis测试key是否存在public boolean hasKey(String key){if(key == null){return false;}String redisKey = RedisKeys.getProvinceConfigKey(key);return redisUtils.hasKey(redisKey);};//从redis中统计活跃用户数量public int countActiveUser(){Long Lnum = redisUtils.countForSet(RedisKeys.ACTIVE_MOGU_NO);if(Lnum==null){return 0;}else {return Lnum.intValue();}}//省级平台获取redisKeypublic String getProvinceKey(String key){if(key == null){return null;}String redisKey = RedisKeys.getProvinceConfigKey(key);return redisUtils.get(redisKey);}//省级平台向redis插入数据public void setProvinceDataToRedis(String key,String list){String keys = RedisKeys.getProvinceConfigKey(key);//配置文件默认保留时长redisUtils.setRedis(keys,list,redisUtils.expire);}
}
五:流程实现
模拟SpringBoot项目结构调用
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测试接口* @version: v1.0*/@RestController
@Api(tags = {"Redis测试接口"},produces = "RedisTest_controller")
@RequestMapping("/redis")
public class RedisTestController {@AutowiredRedisTestService redisTestService;private Logger logger = LoggerFactory.getLogger(RedisTestController.class);@ApiOperation(value = "Redis测试,将对象插入缓存",notes = "")@RequestMapping("/v1/test")public BaseResponse redisInsertBeanController(@RequestBody Item item){return redisTestService.redisInsertBeanService(item);}@ApiOperation(value = "Redis测试,将List插入缓存",notes = "")@RequestMapping("/v2/test")public BaseResponse redisInsertListController(@RequestBody Item item){return redisTestService.redisInsertListService(item);}@ApiOperation(value = "Redis测试,将Map<String,Set<String>>插入缓存,取出来转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测试接口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得到值并重新设置过期时间,若值不存在则重新插入缓存。"+"set方法封装了 JSONUtil.toJsonStr"+ "get带泛型的方法封装了JSONUtil.toBean ")public BaseResponse redisInsertBeanService(Item item) {String redisKey= "redisInsertBeanService";System.out.println(redisKey);//判断key值是否存在,如果存在则优先取缓存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方法不带泛型默认返回Json字符串,需要自行反序列化")public BaseResponse redisInsertListService(Item item) {//通过key得到值,String redisKey = "redisInsertListService";System.out.println(redisKey);//判断key值是否存在,如果存在则优先取缓存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值是否存在,如果存在则优先取缓存if (userRedis.hasKey(redisKey)){String jsonString= userRedis.get(redisKey);//可以通过JSonString转对象方法把Vlue值从Set转为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();//根据key转map,之后将Value换成set集合//将集合添加至Map 指定参数作为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: 常用数据集* @version: v1.0*/
public class AttributeData {public static List<Map<String,Object>> list1 (){//构建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("齐齐哈尔大学");info.setDatas("黑龙江省");info.setValue(10);list.add(info);info = new ExportGxySchoolFlowDto();info.setSchoolName("齐齐哈尔大学");info.setDatas("黑龙江");info.setValue(20);list.add(info);info = new ExportGxySchoolFlowDto();info.setSchoolName("齐齐哈尔大学");info.setDatas("黑龙江省哈尔滨市");info.setValue(20);list.add(info);info = new ExportGxySchoolFlowDto();info.setSchoolName("齐齐哈尔大学");info.setDatas("甘肃省");info.setValue(20);list.add(info);info = new ExportGxySchoolFlowDto();info.setSchoolName("哈尔滨大学");info.setDatas("黑龙江");info.setValue(20);list.add(info);info = new ExportGxySchoolFlowDto();info.setSchoolName("武汉职业大学");info.setDatas("北京市");info.setValue(10);list.add(info);info = new ExportGxySchoolFlowDto();info.setSchoolName("黑河市大学");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("郑州经贸学院");item1.setData(60);item1.setBatchName("19年");list.add(item1);CommonInterfaceDto.ItemBatchDataDto item2 =new CommonInterfaceDto.ItemBatchDataDto();item2.setSchoolName("郑州经贸学院");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("计算机");item1.setValue(10);list.add(item1);Item item2 =new Item();item2.setName("会计");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("医学");item5.setValue(40);list.add(item5);Item item6 =new Item();item6.setName("农业");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;}}
调用结果: