SpringBoot集成Redis及Redis使用方法

目录

应用背景

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中取数据,取到后返回。
  • 更新:先把数据存到数据库中,成功后,再让缓存失效。

更新问题

  1. 我们知道,在 springboot 1.5.x版本的默认的Redis客户端是 Jedis实现的,需要导入jedis依赖,而springboot 2.x版本中默认客户端是用 lettuce实现的,需要导入spring-boot-starter-data-redis依赖。这两种方式使用的都是 TCP协议。可以理解为:咱们通过程序是不能直接连接 Redis,得利用客户端工具才能进行连接。比较常用的有两种:JedisLettuce。既然 Lettuce 和 Jedis 的都是连接 Redis Server 的客户端,那么它们有什么区别呢?
  2. Jedis使用直连方式连接Redis Server,在多线程环境下存在线程安全问题, 因此需要增加连接池来解决线程安全的问题,同时可以限制redis客户端的数量, 但这种直连方式基于传统I/O模式,是阻塞式传输。
  3. 而 Lettuce 是 一种可伸缩,线程安全,完全非阻塞的Redis客户端,底层基于netty通信,我们知道netty是基于NIO的非阻塞通信, 天生支持高并发,因此在在多线程环境下不存在线程安全问题,一个连接实例就可以满足多线程环境下的并发访问, 当然实例不够的情况下也可以按需增加实例,保证伸缩性。
  4. 下面我们通过源码的方式解析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;}}

 调用结果:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/92296.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于安防监控EasyCVR视频汇聚融合技术的运输管理系统的分析

一、项目背景 近年来&#xff0c;随着物流行业迅速发展&#xff0c;物流运输费用高、运输过程不透明、货损货差率高、供应链协同能力差等问题不断涌现&#xff0c;严重影响了物流作业效率&#xff0c;市场对于运输管理数字化需求愈发迫切。当前运输行业存在的难题如下&#xf…

mysql-事务特性以及隔离机制

一.ACID 事务&#xff08;Transaction&#xff09;是访问和更新数据库的程序执行单元&#xff1b;事务中可能包含一个或多个sql语句&#xff0c;这些语句要么都执行&#xff0c;要么都不执行。 1.逻辑架构和存储引擎 如上图所示&#xff0c;MySQL服务器逻辑架构从上往下可以分…

【密码学】维京密码

维京密码 瑞典罗特布鲁纳巨石上的图案看起来毫无意义&#xff0c;但是它确实是一种维京密码。如果我们注意到每组图案中长笔画和短笔画的数量&#xff0c;将得到一组数字2、4、2、3、3、5、2、3、3、6、3、5。组合配对得到24、23、35、23、36、35。现在考虑如图1.4所示的内容&a…

六、Linux系统下,文件操作命令都有哪些?

总括&#xff1a; 创建文件/文件夹&#xff1a;touch&#xff1b; 查看&#xff1a;cat/more&#xff1b; 复制&#xff1a;copy&#xff1b; 移动文件/文件夹&#xff1a;mv&#xff1b; 删除&#xff1a;rm&#xff1b; 1、创建文件 &#xff08;1&#xff09;语法&#x…

java实现docx,pdf文件动态填充数据

一&#xff0c;引入pom 根据需求引入自己所需pom org.apache.poi poi 4.1.1 org.apache.poi poi-ooxml 4.1.1 org.jxls jxls 2.6.0 ch.qos.logback logback-core org.jxls jxls-poi 1.2.0 fr.opensagres.xdocreport fr.opensagres.xdocreport.core 2.0.2 fr.opensagres.xdocrep…

最小生成树 — Prim算法

同Kruskal算法一样&#xff0c;Prim算法也是最小生成树的算法&#xff0c;但与Kruskal算法有较大的差别。 Prim算法整体是通过“解锁” “选中”的方式&#xff0c;点 -> 边 -> 点 -> 边。 因为是最小生成树&#xff0c;所以针对的也是无向图&#xff0c;所以可以随意…

MySql011——检索数据:过滤数据(使用正则表达式)

前提&#xff1a;使用《MySql006——检索数据&#xff1a;基础select语句》中创建的products表 一、正则表达式介绍 关于正则表达式的介绍大家可以看我的这一篇博客《Java038——正则表达式》&#xff0c;这里就不再累赘。 二、使用MySQL正则表达式 2.1、基本字符匹配 检索…

Java版企业电子招投标采购系统源码之首页设计 tbms

​ 功能描述 1、门户管理&#xff1a;所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含&#xff1a;招标公告、非招标公告、系统通知、政策法规。 2、立项管理&#xff1a;企业用户可对需要采购的项目进行立项申请&#xff0c;并提交审批&#xff0c;查…

照耀国产的星火,再度上新!

国产之光&#xff0c;星火闪耀 ⭐ 新时代的星火⭐ 多模态能力⭐ 图像生成与虚拟人视频生成⭐ 音频生成与OCR笔记收藏⭐ 助手模式更新⭐ 插件能力⭐ 代码能力⭐ 写在最后 ⭐ 新时代的星火 在这个快速变革的时代&#xff0c;人工智能正迅猛地催生着前所未有的革命。从医疗到金融…

CEC2013(MATLAB):遗传算法(Genetic Algorithm,GA)求解CEC2013的28个函数

一、遗传算法GA 遗传算法&#xff08;Genetic Algorithm&#xff0c;GA&#xff09;起源于对生物系统所进行的计算机模拟研究&#xff0c;是一种随机全局搜索优化方法&#xff0c;它模拟了自然选择和遗传中发生的复制、交叉(crossover)和变异(mutation)等现象&#xff0c;从任…

easyx图形库基础4:贪吃蛇

贪吃蛇 一实现贪吃蛇&#xff1a;1.绘制网格&#xff1a;1.绘制蛇&#xff1a;3.控制蛇的默认移动向右&#xff1a;4.控制蛇的移动方向&#xff1a;5.生成食物6.判断蛇吃到食物并且长大。7.判断游戏结束&#xff1a;8.重置函数&#xff1a; 二整体代码&#xff1a; 一实现贪吃蛇…

【0基础学爬虫】爬虫基础之网络请求库的使用

大数据时代&#xff0c;各行各业对数据采集的需求日益增多&#xff0c;网络爬虫的运用也更为广泛&#xff0c;越来越多的人开始学习网络爬虫这项技术&#xff0c;K哥爬虫此前已经推出不少爬虫进阶、逆向相关文章&#xff0c;为实现从易到难全方位覆盖&#xff0c;特设【0基础学…

安卓13解决链接问题

作为Android用户&#xff0c;你可能已经注意到了一个问题——Android 13不再支持PPTP协议。但请别担心&#xff0c;作为一家专业的代理供应商&#xff0c;我们将与你分享解决方案&#xff0c;让你轻松解决L2TP问题&#xff0c;享受到高水平的连接体验。本文将为你提供实用的操作…

什么是浮动(float)?如何清除浮动?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 浮动&#xff08;Float&#xff09;和清除浮动⭐ 浮动的使用⭐ 清除浮动1. 空元素法&#xff08;Empty Element Method&#xff09;2. 使用 Clearfix Hack3. 使用 Overflow ⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发…

微服务与Nacos概述-5

引入OpenFeign 添加依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency><groupId>com.alibaba.cloud</groupId>…

山东布谷科技直播软件开发WebRTC技术:建立实时通信优质平台

在数字化的时代&#xff0c;实时通信成为了人们远程交流的主要方式&#xff0c;目前市场上也出现了很多带有实时通信交流的软件&#xff0c;实时通信符合人们现在的需求&#xff0c;所以在直播软件开发过程中&#xff0c;开发者也运用了实时通信技术为直播软件加入了实时通信的…

【芯片前端】auto_testbench的大版本升级——加入简单预期与自动比对

前言 前文提要&#xff1a; 【芯片前端】一键生成简易版本定向RTL验证环境的脚本——auto_verification_rtl脚本_尼德兰的喵的博客-CSDN博客 【芯片前端】可能是定向验证的巅峰之作——auto_testbench_autotestbench_尼德兰的喵的博客-CSDN博客 工具路径&#xff1a; auto…

Vue.js2+Cesium1.103.0 九、淹没分析效果

Vue.js2Cesium1.103.0 九、淹没分析效果 Demo <template><divid"cesium-container"style"width: 100%; height: 100%;"><spanid"button"style"position: absolute; right: 50px; top: 50px; z-index: 999; font-size: 24px…

Gitlab-第四天-CD到k8s集群的坑

一、.gitlab-ci.yml #CD到k8s集群的 stages: - deploy-test build-image-deploy-test: stage: deploy-test image: bitnami/kubectl:latest # 使用一个包含 kubectl 工具的镜像 tags: - k8s script: - ls -al - kubectl apply -f deployment.yaml # 根据实际情况替换…

SpringBoot请求响应

简单参数 1. 原始方式获取请求参数 Controller方法形参中声明httpServletRequest对象 调用对象的getParameter参数名 RestController public class RequestController {RequestMapping("/simpleParam")public String simpleParam(HttpServletRequest request){Strin…