Springboot整合RedisTemplate以及业务工具类示例

docker安装Redis参考我另一篇博客Docker安装Redis及持久化

一、Get-Started

依赖

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!--Apache对象池技术,包括RedisConnecttionFactory等,引入这个依赖就不需要自己配置了-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

yml配置

springboot2.0.0过后默认使用lettuce.pool而不使用jedis.pool

spring:
  redis:
    host: 192.168.150.101
    password: 123321
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 1
        max-wait: 300

测试

package com.gzdemo.redisdemo;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

@SpringBootTest
public class RedisTemplateTest {
    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void testAdd() {
        // String
        redisTemplate.opsForValue().set("name","zhangsan");
        // set
        redisTemplate.opsForSet().add("myset","1");
        // zset
        redisTemplate.opsForZSet().add("myzset","stu1",10);
        //hash
        redisTemplate.opsForHash().put("myhash","stu1","1");
        //list
        redisTemplate.opsForList().leftPush("mylist","1");
    }
}

运行单元测试,发现redis保存的这5个键值对出现乱码,原因是RedisTemplate默认使用的是Jdk序列化器。
在这里插入图片描述
在这里插入图片描述

二、StringRedisTemplate

RedisTemplate常用方法:https://blog.csdn.net/zzvar/article/details/118388897

先运行单元测试把新增的5个数据删掉

    @Test
    void testRemove() {
        // String
        redisTemplate.delete("name");
        // set
        redisTemplate.opsForSet().remove("myset","1");
        // zset
        redisTemplate.opsForZSet().remove("myzset","stu1");
        //hash
        redisTemplate.opsForHash().delete("myhash","stu1");
        //list
        redisTemplate.opsForList().rightPop("mylist");
    }

将RedisTemplate换成StringRedisTemplate(使用了String序列化器)或者RedisTemplate<String,String>,不能是RedisTemplate<String,Object>,除非自己配置一个RedisTemplate<String,Object>

在这里插入图片描述

重新测试TestAdd
在这里插入图片描述

三、配置RedisTemplate<String,Object>(可选)

给RedisTemplate<String,Object>配置序列化器后,不会乱码。
可以直接用RedisTemplate<String,Object>传输一个对象(必须implements Serializable
但通常不用这种方式,而是直接把对象转成json字符串保存在redis中
Redis配置

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
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.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;

@Configuration
public class RedisConfig {

    /**
     * RedisTemplate配置
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        // 创建RedisTemplate<String, Object>对象
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();

        // 设置RedisTemplate的连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        // 自定义序列化器
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);//序列化的类型为Object
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); //序列化所有属性
        // om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); //设置这个过后,redis中的数据会携带该对象的类型,不方便读取
        jackson2JsonRedisSerializer.setObjectMapper(om);

        // key和hashKey的序列化器采用String
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setHashKeySerializer(RedisSerializer.string());

        // value和hashValue的序列化器采用jackson2JsonRedisSerializer
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        return redisTemplate;
    }
}

单元测试

    //使用RedisTemplate<String,Object>需要配置一个RedisTemplate<String,Object>
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Test
    public void Test1_Add(){
        User u = User.builder()
                .id(1000)
                .name("zhangsan")
                .phone("15730000001")
                .build();

        redisTemplate.opsForValue().set("user1", u);
    }

    @Test
    public void Test1_Get(){
        Object obj = redisTemplate.opsForValue().get("user1");
        // 这里不能把Object强转为User类 否则会java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.gzdemo.redisdemo.domain.User
        User user = JSONUtil.toBean(JSONUtil.toJsonStr(obj), User.class);
        System.out.println(user);
    }

四、StringRedisTemplate-以json字符串保存对象

通常用这种方式将某个对象保存在redis中,这种方式不需要类implements Serializable

	@Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Test
    public void Test2_Add(){
        User u = User.builder()
                .id(1000)
                .name("zhangsan")
                .phone("15730000001")
                .build();

        stringRedisTemplate.opsForValue().set("user2", JSONUtil.toJsonStr(u));
    }

    @Test
    public void Test2_Get(){
        String s = stringRedisTemplate.opsForValue().get("user2");
        User user = JSONUtil.toBean(s, User.class);
        System.out.println(user);
    }

五、实际开发

实际开发中,在使用到缓存的地方,定义一个业务工具类。这里举个例子,基于LearningRecord实体类,比如

import cn.hutool.json.JSONUtil;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.time.LocalDateTime;
...

@Component
@Slf4j
@RequiredArgsConstructor
public class LearningRecordCacheHandler {
    private final StringRedisTemplate redisTemplate;
    private final ILearningLessonService lessonService;
    private final LearningRecordMapper recordMapper;
    // 缓存前缀
    private static final String LEARNING_RECORD_CACHE_PREFIX="learning:record:";

    //1) 写入缓存
    public void writeRecordCache(LearningRecord record){
        log.info("缓存放入了消息:");
        // 1.转成只有三个属性的对象
        RecordCacheData cacheData = new RecordCacheData(record);
        // 2. 转成json 字符串
        String jsonData = JSONUtil.toJsonStr(cacheData);
        // 3 拼接key  learning:record:6688
        String key =LEARNING_RECORD_CACHE_PREFIX+record.getLessonId();
        // 4 存储缓存(覆盖)
        redisTemplate.opsForHash().put(key,record.getSectionId().toString(),jsonData);
        // 5 设置超时时间
        redisTemplate.expire(key, Duration.ofSeconds(60));

    }
    //2) 读取缓存
    public LearningRecord readRecordCache(Long lessonId,Long sectionId){
        //1 拼接key  learning:record:6688
        String key =LEARNING_RECORD_CACHE_PREFIX+lessonId;
        // 真正的是String
        Object o = redisTemplate.opsForHash().get(key, sectionId.toString());
        if(o==null){
            return null;
        }
        // {id:1,moment:30,finshsend:false}
        // 转成对象
        LearningRecord record = JSONUtil.toBean(o.toString(), LearningRecord.class);
        record.setLessonId(lessonId);
        record.setSectionId(sectionId);
        return record;
    }
    //3) 删除缓存
    public void removeRecordCache(Long lessonId,Long sectionId){
        //1 拼接key  learning:record:6688
        String key =LEARNING_RECORD_CACHE_PREFIX+lessonId;
        redisTemplate.opsForHash().delete(key,sectionId.toString());
    }
    // 存储缓存的对象
    @Data
    @NoArgsConstructor
    public class RecordCacheData{
        private Long id;
        private Boolean finished;
        private Integer moment;

        public RecordCacheData(LearningRecord record) {
            this.id = record.getId();
            this.finished = record.getFinished();
            this.moment = record.getMoment();
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java_多线程:线程池

1、线程池优点&#xff1a; 降低资源消耗&#xff1a;通过重复利用已创建的线程降低线程创建和销毁造成的消耗。提高响应速度&#xff1a;当任务到达时&#xff0c;任务可以不需要等到线程创建就能立即执行。提高线程的可管理性&#xff1a;线程是稀缺资源&#xff0c;如果无限…

Django 多对多关系

多对多关系作用 Django 中&#xff0c;多对多关系模型的作用主要是为了表示两个模型之间的多对多关系。具体来说&#xff0c;多对多关系允许一个模型的实例与另一个模型的多个实例相关联&#xff0c;反之亦然。这在很多实际应用场景中非常有用&#xff0c;比如&#xff1a; 博…

因版本冲突导致logback的debug日志不打印

因框架调整&#xff0c;降级了logback的版本号&#xff0c;由1.3.12降级为1.2.11&#xff08;因框架限制&#xff0c;只能采用1.2版本&#xff09;&#xff0c;降级后发现debug日志无法打印出来&#xff0c;logback.xml配置文件不生效。后排查发现是与slf4j的版本兼容问题 依赖…

搜维尔科技:数据手套为什么要选择SenseGlove

了解 SenseGlove SenseGlove 是一支由电子工程师、触觉研究人员和计算机视觉专家、XR 开发人员、UX 设计师和产品创新者组成的科幻爱好者团队&#xff0c;他们拥有丰富人类能力和赋予 Metaverse 意义的技能和热情。 推进触觉技术是我们实现这一目标的方式。 公司及产品背景 S…

基于Hadoop平台的电信客服数据的处理与分析③项目开发:搭建Kafka大数据运算环境---任务12:安装Kafka

任务描述 任务内容为安装和配置Kafka集群。 任务指导 Kafka是大数据生态圈中常用的消息队列框架 具体安装步骤如下&#xff1a; 1. 解压缩Kafka的压缩包 2. 配置Kafka的环境变量 3. 修改Kafka的配置文件&#xff0c;Kafka的配置文件存放在Kafka安装目录下的config中 4. 验证…

【融合ChatGPT等AI模型】Python-GEE遥感云大数据分析、管理与可视化及多领域案例应用

随着航空、航天、近地空间遥感平台的持续发展&#xff0c;遥感技术近年来取得显著进步。遥感数据的空间、时间、光谱分辨率及数据量均大幅提升&#xff0c;呈现出大数据特征。这为相关研究带来了新机遇&#xff0c;但同时也带来巨大挑战。传统的工作站和服务器已无法满足大区域…

JDK动态代理-AOP编程

AOPTest.java&#xff0c;相当于main函数&#xff0c;经过代理工厂出来的Hello类对象就不一样了&#xff0c;这是Proxy.newProxyInstance返回的对象&#xff0c;会hello.addUser会替换为invoke函数&#xff0c;比如这里的hello.addUser("sun", "13434");会…

【驱动篇】龙芯LS2K0300之红外驱动

实验目标 编写HX1838红外接收器驱动&#xff0c;根据接收的波形脉冲解码红外按键键值 模块连接 模块连接&#xff1a;VCC接Pin 2&#xff0c;GND接Pin1&#xff0c;DATA接Pin16 驱动代码 HX1838 GPIO初始化&#xff0c;申请中断&#xff0c;注意&#xff1a;GPIO48默认是给…

vscode语言模式

1.背景 写vue3ts项目的时候&#xff0c;用到了volar插件&#xff0c;在单文件使用的时候&#xff0c;鼠标悬浮在代码上面会有智能提示&#xff1b; 但是最近volar插件提示被弃用了&#xff0c;然后我按照它的官方提示&#xff0c;安装了Vue-official扩展插件&#xff0c;但是…

Vue3 特点以及优势-源码解剖

Vue3 特点以及优势-Vue3.4源码解剖 Vue3 特点以及优势 1.声明式框架 命令式和声明式区别 早在 JQ 的时代编写的代码都是命令式的&#xff0c;命令式框架重要特点就是关注过程声明式框架更加关注结果。命令式的代码封装到了 Vuejs 中&#xff0c;过程靠 vuejs 来实现 声明式代…

剑神诀_单机架设_无需虚拟机_小白专用

前言 今天给大家带来一款单机游戏的架设&#xff1a;剑神诀&#xff0c;一键端 无需虚拟机 如今市面上的资源参差不齐&#xff0c;大部分的都不能运行&#xff0c;本人亲自测试&#xff0c;运行视频如下&#xff1a; 剑神诀 搭建教程 此游戏架设不需要安装虚拟机&#xff0c;…

爬虫cookie是什么意思

“爬虫 cookie”指的是网络爬虫在访问网站时所使用的cookie&#xff0c;网络爬虫是一种自动化程序&#xff0c;用于在互联网上收集信息并进行索引&#xff0c;这些信息可以用于搜索引擎、数据分析或其他目的。 本教程操作系统&#xff1a;Windows10系统、Dell G3电脑。 “爬虫…

SpringBoot 项目整合 MyBatisPlus 框架,附带测试示例

文章目录 一、创建 SpringBoot 项目二、添加 MyBatisPlus 依赖三、项目结构和数据库表结构四、项目代码1、application.yml2、TestController3、TbUser4、TbUserMapper5、TestServiceImpl6、TestService7、TestApplication8、TbUserMapper.xml9、MyBatisPlusTest 五、浏览器测试…

新鲜出炉!恭喜这 5 位同学中选 NebulaGraph 社区 2024 开源之夏项目!

开源之夏是中国科学院软件研究所发起的“开源软件供应链点亮计划”系列暑期活动&#xff0c;旨在鼓励高校学生积极参与开源软件的开发维护&#xff0c;促进优秀开源软件社区的蓬勃发展。活动联合各大开源社区&#xff0c;针对重要开源软件的开发与维护提供项目开发任务&#xf…

stm32学习笔记---USART串口外设(理论部分)

目录 USART简介 USART的框图 串口的引脚 USART的基本结构 数据帧 起始位侦测 数据采样 波特率发生器 USD转串口模块的原理图 声明&#xff1a;本专栏是本人跟着B站江科大的视频的学习过程中记录下来的笔记&#xff0c;我之所以记录下来是为了方便自己日后复习。如果你…

个人微信二次开发

​ 由于自身在机器人方面滚爬多年&#xff0c;现在收藏几个宝藏机器人 推荐一下自己常用的机器人&#xff1a; 适合有技术开发的公司&#xff0c;可以自主开发所需要的功能&#xff01;十分齐全 测试问文档&#xff1a;https://www.wkteam.cn/ 有需要的兄弟可以看一下&#…

手写一个基于SpringBoot的MVC架构,默认实现CRUD和导入导出功能

文章目录 前言正文一、项目结构二、技术点三、部分核心代码3.1 core-tool 中的核心代码3.1.1 所有实体的通用父类 SuperEntity3.1.2 所有枚举的父接口 BaseEnum3.1.3 所有业务异常的父接口 BaseException 3.2 mvc-tool 中的核心代码3.2.1 CrudController 接口定义3.2.2 默认的C…

手写一个类似@RequestParam的注解(用来接收请求体的参数)

一、本文解决的痛点 按照大众认为的开发规范&#xff0c;一般post类型的请求参数应该传在请求body里面。但是我们有些post接口只需要传入一个字段&#xff0c;我们接受这种参数就得像下面这样单独创建一个类&#xff0c;类中再添加要传入的基本类型字段&#xff0c;配合Reques…

清爽一夏,羊大师伴你健康运动,引领活力生活!

在这个绚烂多彩的夏日&#xff0c;让我们携手踏上一段清爽与健康并行的旅程。阳光炽热&#xff0c;万物生长&#xff0c;正是释放活力、追求健康的最佳时节。“清爽一夏&#xff0c;健康运动引领活力生活&#xff01;”这不仅是一句口号&#xff0c;更是我们向美好生活发出的诚…

模电-运放的供电

模电-运放的供电 Fang XS.1452512966qq.com如果有错误&#xff0c;希望被指出&#xff0c;学习技术的路难免会磕磕绊绊量的积累引起质的变化注&#xff1a;本文章为唐老师讲电赛视频的个人笔记 运放的供电 所有的运放都可以单电源和双电源供电&#xff1b;采用双电源供电的运…