SpringBoot集成Redis及Redis使用方法

news2024/12/23 18:13:17

目录

应用背景

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: 0
    host: 127.0.0.1
    port: 3304
    password: 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 {
    @Autowired
    private RedisConnectionFactory factory;

    @Bean
    public 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 类型数据
     **/
    @Bean
    public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForHash();
    }

    /**
     *  HashOperations
     * 操作 String 类型数据
     **/
    @Bean
    public ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {
        return redisTemplate.opsForValue();
    }

    /**
     *  HashOperations
     * 操作 List 类型数据
     **/
    @Bean
    public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForList();
    }

    /**
     *  HashOperations
     * 操作 Set 类型数据
     **/
    @Bean
    public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForSet();
    }

    /**
     *  HashOperations
     * 操作 SortedSet 类型数据
     **/
    @Bean
    public 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);
    @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;
    /**默认过期时长,单位: 秒*/
    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 {
    //最大蘑菇号的key
    public final static String MAX_MOGUNO_KEY = "moguding:user:max_mogu_no";
    //短信验证码的key
    public 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;
    }
    //用户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;
    }
    //缓存活跃蘑菇号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";

    //自动报告key
    public 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 {
    @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添加值,设置默认过期时长 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();
        }
    }

    //省级平台获取redisKey
    public 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 {
    @Autowired
    RedisTestService 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 {
    @Autowired
    UserRedis 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转为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();
            //根据key转map,之后将Value换成set集合
            //将集合添加至Map 指定参数作为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: 常用数据集
 * @version: v1.0
 */
public class AttributeData {
        public static  List<Map<String,Object>> list1 (){
            //构建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("齐齐哈尔大学");
        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.coloradmin.cn/o/861714.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023最新版本Activiti7系列-多实例详解

工作流多实例 1.多实例介绍 多实例活动是为业务流程中的某个步骤定义重复的一种方式。在编程概念中&#xff0c;多实例与 for each 结构相匹配&#xff1a;它允许对给定集合中的每个项目按顺序或并行地执行某个步骤或甚至一个完整的子流程。 多实例是一个有额外属性&#xff0…

【Java并发】如何进行死锁诊断?

文章目录 1.什么是死锁2.死锁怎么产生的3.如何进行死锁诊断&#xff1f;3.1 通过命令查看3.2 jconsole可视化工具3.2 VisualVM&#xff1a;故障处理工具 1.什么是死锁 死锁&#xff08;Deadlock&#xff09;是指两个或多个进程&#xff08;线程&#xff09;在执行过程中&#…

spss什么是描述性分析,以及如何去处理。

描述性分析是数据分析的第一步&#xff0c;是了解和认识数据基本特征和结构的方法&#xff0c;只有在完成了描述性统计分析&#xff0c;充分的了解和认识数据特征后&#xff0c;才能更好地开展后续更复杂的数据分析。因此&#xff0c;描述性分析是开展数据分析过程中最基础且必…

怎么在python里面安装库,如何在python中安装库

大家好&#xff0c;给大家分享一下python外部库安装后放在哪里&#xff0c;很多人还不知道这一点。下面详细解释一下。现在让我们来看看&#xff01; Python成为最流行的语言之一&#xff0c;除了它的简单易学和语法简单外&#xff0c;还有一个重要的原因是Python有非常强大的第…

PMP认证考试有何变化?该如何备考

截至2023年1月31日&#xff0c;全球有超130万PMP有效持证人士&#xff0c;其中中国有效持证人数已超过了43万人。持有PMP也已成为企业衡量项目经理人专业度的重要指标之一。 PMP考证人数的快速发展&#xff0c;与其考试大纲和知识体系的科学性和实战性密不可分。PMP考纲和教材…

【雕爷学编程】Arduino动手做(201)---行空板硬件控制之LED与按键

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

数组slice、splice字符串substr、split

一、定义 这篇文章主要对数组操作的两种方法进行介绍和使用&#xff0c;包括&#xff1a;slice、splice。对字符串操作的两种方法进行介绍和使用&#xff0c;包括&#xff1a;substr、split (一)、数组 slice:可以操作的数据类型有&#xff1a;数组字符串 splice:数组 操作数组…

Spring依赖注入、对象装配

文章目录 依赖注入与对象装配依赖注入的常见方式属性注入&#xff08;Property Injection&#xff09;属性注入的优缺点 Setter 注入&#xff08;Setter Injection&#xff09;Setter注入优缺点 构造函数注入&#xff08;Constructor Injection&#xff09;构造函数注入优缺点 …

Unity游戏源码分享-多角色fps射击游戏

Unity游戏源码分享-多角色fps射击游戏 项目地址&#xff1a;https://download.csdn.net/download/Highning0007/88204023

Flutter BottomSheet 三段式拖拽

BottomSheetBehavior 追踪 BottomSheet系统默认实现效果准备要实现的功能点&#xff1a;定义三段式状态&#xff1a;BottomSheetBehavoir阀值定义1. 未达到滚动阀值&#xff0c;恢复状态2. 达到滚动阀值&#xff0c;更新状态 前面倒是有讲过Android原生的BottomSheetBehavior&a…

Camunda 7.x 系列【2】开源工作流引擎框架

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Spring Boot 版本 2.7.9 本系列Camunda 版本 7.19.0 源码地址&#xff1a;https://gitee.com/pearl-organization/camunda-study-demo 文章目录 1. 前言2. 开源工作流引擎框架2.1 jBPM2.2 Activ…

综合技巧练习 - Packet Tracer 简介

1.7.1&#xff1a;综合技巧练习 - Packet Tracer 简介 拓扑图&#xff1a; 以基本完成的逻辑拓扑为起点。 设备 接口 IP 地址 子网掩码 默认网关 R1-ISP Fa0/0 192.168.254.253 255.255.255.0 不适用 S0/0/0 10.10.10.6 255.255.255.252 R2-Central Fa0/0 17…

DTC服务(0x14 0x19 0x85)

DTC相关的服务有ReadDTCInformation (19) service&#xff0c;ControlDTCSetting (85) service和ReadDTCInformation (19) service ReadDTCInformation (19) service 该服务允许客户端从车辆内任意一台服务器或一组服务器中读取驻留在服务器中的诊断故障代码( DTC )信息的状态…

并发——ThreadPoolExecutor 类简单介绍

文章目录 1 ThreadPoolExecutor 类分析2 推荐使用 ThreadPoolExecutor 构造函数创建线程池 线程池实现类 ThreadPoolExecutor 是 Executor 框架最核心的类。 1 ThreadPoolExecutor 类分析 ThreadPoolExecutor 类中提供的四个构造方法。我们来看最长的那个&#xff0c;其余三个…

P15 电路定理——巧妙-灵性-智慧

1、戴维南定理 2、戴维南定理的证明 对于线性含源的一个结构&#xff0c; 右边接一个支路N&#xff0c;再用电流源替代N 情况一&#xff1a;A没有独立源&#xff0c;那么A可以等价于一个电阻 情况二&#xff1a;A有独立源&#xff0c;例证法&#xff1a; 使用叠加法&#xf…

获取 Android 的 SHA1 值

1、调试版&#xff0c;可以直接在 Android studio 中的 gradle 中查看。也可以用下面方法进行 前提要先确定签名文件所在的路径&#xff1a;调试版默认使用的签名文件是debug.keystore&#xff0c;文件处于 C 盘用户目录下的.android文件夹下。打开命令行工具&#xff0c; 1、…

分析为何科研转化率低

最近这两天&#xff0c;[广西审计:高校1.31亿科研经费成果转化率为0] 话题引发热议。据报道&#xff0c;广西壮族自治区审计厅近日公布的《关于2022年度自治区本级预算执行和其他财政收支的审计工作报告》披露了广西在科教振兴资金审计方面 9 所高校开展科研的相关情况。报告发…

Flutter:文件上传与下载(下载后预览)

Dio dio是一个强大的Dart Http请求库&#xff0c;提供了丰富的功能和易于使用的API&#xff0c;支持文件上传和下载。 这个就不介绍了&#xff0c;网上有很多的封装案例。 background_downloader 简介 适用于iOS&#xff0c;Android&#xff0c;MacOS&#xff0c;Windows和L…

使用 prometheus client SDK 暴露指标

目录 1. 使用 prometheus client SDK 暴露指标1.1. How Go exposition works1.2. Adding your own metrics1.3. Other Go client features 2. Golang Application monitoring using Prometheus2.1. Metrics and Labels2.2. Metrics Types2.2.1. Counters:2.2.2. Gauges:2.2.3. …

【ECharts】树图

将3级改成4级 demo上是3层&#xff0c;如何实现4层。 initialTreeDepth: 4