SpringMVC使用 redis 实现缓存

news2024/11/14 19:26:48

简介

SpringMVC 中也可以将缓存标签和 redis 结合起来使用,其实此时缓存没有起作用,只是通过缓存的那几个注解来操作 redis 而已;SpringMVC 中整合 redis 比较麻烦的是注意版本冲突的问题,如下是官网有关于版本的要求

https://docs.spring.io/spring-data/data-redis/docs/current/reference/html/#requirements

实现步骤

  1. 在 pom.xml 中添加如下依赖,尤其要注意各个依赖的版本,基本上都是 maven 官网上的最新版
<properties>
    <!-- java 版本 -->
    <java.version>1.8</java.version>
    <!-- spring 版本 -->
    <spring.version>5.1.2.RELEASE</spring.version>
    <!-- jstl 版本 -->
    <jstl.version>1.2</jstl.version>
    <!-- standard 版本 -->
    <standard.version>1.2.5</standard.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-servlets</artifactId>
        <version>9.1.0.M0</version>
    </dependency>
    <!-- begin SpringMVC -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-instrument</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jms</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-messaging</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-oxm</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-websocket</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc-portlet</artifactId>
        <version>4.3.20.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-instrument-tomcat</artifactId>
        <version>4.3.20.RELEASE</version>
    </dependency>
    <!-- end SpringMVC -->
    <!-- begin jstl -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>${jstl.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.taglibs</groupId>
        <artifactId>taglibs-standard-impl</artifactId>
        <version>${standard.version}</version>
    </dependency>
    <!-- end jstl -->
    <!-- config redis data and client jar-->
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-redis</artifactId>
        <version>2.1.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.9.0</version>
    </dependency>
    <!-- 用于处理将对象转化为json格式的字符串 -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.7</version>
    </dependency>
</dependencies>
  1. 新建 CacheConfig.class,实现 Cache 接口,添加如下属性和方法
@Component
public class CacheConfig implements Cache {
    private StringRedisTemplate redisTemplate;
    private String name;

    public CacheConfig() {}

    public CacheConfig(StringRedisTemplate redisTemplate, String name) {
        this.redisTemplate = redisTemplate;
        this.name = name;
    }

    public StringRedisTemplate getStringRedisTemplate() {
        return redisTemplate;
    }

    public void setStringRedisTemplate(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public void clear() {
        redisTemplate.execute(new RedisCallback < String > () {
            public String doInRedis(RedisConnection connection) throws DataAccessException {
                connection.flushDb();
                return "ok";
            }
        });
    }

    public void evict(Object object) {
        final String key = (String) object;
        redisTemplate.execute(new RedisCallback < Long > () {
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.del(key.getBytes());
            }
        });
    }

    public ValueWrapper get(Object obj) {
        final String key = (String) obj;
        Object object = null;
        object = redisTemplate.execute(new RedisCallback < Object > () {
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                byte[] keys = key.getBytes();
                byte[] value = connection.get(keys);
                if (value == null) {
                    return null;
                }
                return toObject(value);
            }
        });
        return (object != null ? new SimpleValueWrapper(object) : null);
    }

    public Object getNativeCache() {
        return this.redisTemplate;
    }

    public void put(Object key, Object value) {
        final String keyf = (String) key;
        final Object valuef = value;
        final long liveTime = 86400;

        redisTemplate.execute(new RedisCallback < Long > () {
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                byte[] keyb = keyf.getBytes();
                byte[] valueb = toByteArray(valuef);
                connection.set(keyb, valueb);
                if (liveTime > 0) {
                    connection.expire(keyb, liveTime);
                }
                return 1 L;
            }
        });
    }

    public ValueWrapper putIfAbsent(Object key, Object value) {
        return null;
    }

    public < T > T get(Object object, Class < T > clz) {
        return null;
    }

    public < T > T get(Object object, Callable < T > callable) {
        return null;
    }

    private Object toObject(byte[] bytes) {
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        Object obj = null;
        try {
            bis = new ByteArrayInputStream(bytes);
            ois = new ObjectInputStream(bis);
            obj = ois.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            closeIO(ois, bis);
        }
        return obj;
    }

    private byte[] toByteArray(Object obj) {
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        byte[] bytes = null;
        try {
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(obj);
            oos.flush();
            bytes = bos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            closeIO(oos, bos);
        }
        return bytes;
    }

    public void closeIO(Closeable...ios) {
        try {
            for (Closeable io: ios) {
                if (null != io) {
                    io.close();
                }@Configuration
@EnableWebMvc
@EnableCaching
@ComponentScan(basePackages = "com.ibm.redis")
public class SpringConfig extends WebMvcConfigurationSupport {@
    Resource
    private AppSetting appSetting;

    @Bean
    public CacheManager cacheManager(StringRedisTemplate redisTemplate) {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        cacheManager
        // 注意此处设置的 cache name 后面将会用到
            .setCaches(Arrays.asList(new ConcurrentMapCache("myCache"), new CacheConfig(redisTemplate, "redis")));
        return cacheManager;
    }

    @Bean
    public KeyGenerator keyGenerator() {
        return new MyKeyGenerator();
    }
    // Jedis 连接池配置(对于缓存+redis配置来说, 该 bean 不是必需的, 只有单独使用 jedis 才用到)
    @Bean
    public GenericObjectPoolConfig poolConfig() {
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        poolConfig.setMaxWaitMillis(appSetting.getMaxWaitMillis());
        poolConfig.setMaxTotal(appSetting.getMaxActive());
        poolConfig.setMaxIdle(appSetting.getMaxIdle());
        poolConfig.setMinIdle(appSetting.getMinIdle());
        return poolConfig;
    }

    // 创建 Jedis 连接池(对于缓存+redis配置来说, 该 bean 不是必需的, 只有单独使用 jedis 才用到)
    @Bean
    public JedisPool jedisPool(GenericObjectPoolConfig poolConfig) {
        JedisPool jedisPool = new JedisPool(poolConfig, appSetting.getHost(), appSetting.getPort(), 60, appSetting.getPass());
        return jedisPool;
    }

    // 创建 JedisConnectionFactory
    @Bean
    public JedisConnectionFactory redisConnectionFactory() {
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(appSetting.getHost());
        redisStandaloneConfiguration.setPassword(RedisPassword.of(appSetting.getPass()));
        redisStandaloneConfiguration.setPort(appSetting.getPort());
        return new JedisConnectionFactory(redisStandaloneConfiguration);
    }

    // 创建 StringRedisTemplate
    @Bean
    public StringRedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate redisTemplate = new StringRedisTemplate(redisConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        return redisTemplate;
    }
}
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  1. 新建 SpringConfig.class 为 spring 的配置类,添加如下配置
在这里插入代码片

注意:上面的主键生成器 Bean 的实现如下

// 缓存键的生成策略
public class MyKeyGenerator implements KeyGenerator {
    public Object generate(Object target, Method method, Object ... params) {
        return target.getClass().getName() + method.getName();
    }
}
  1. Appsetting.class 类主要用于从 redis.properties 中绑定数据

Appsetting.class

@PropertySource(value="classpath:redis.properties")
@Component
public class AppSetting {
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.password}")
    private String pass;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.timeout}")
    private int timeout;
    @Value("${spring.redis.pool.max-active}")
    private int maxActive;
    @Value("${spring.redis.pool.max-idle}")
    private int maxIdle;
    @Value("${spring.redis.pool.min-idle}")
    private int minIdle;
    @Value("${spring.redis.pool.max-wait}")
    private long maxWaitMillis;
    ... ... 省略 getter 和 setter 方法
}

redis.properties

# REDIS
#redis jedis配置
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址 (默认为127.0.0.1)
spring.redis.host=127.0.0.1
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=dufu9137
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=200
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=0
#spring-session 使用
spring.session.store-type=none
  1. 在 RedisService.class 中使用
@Service
// 此处的 cache name 和第 3 步中声明 CacheManager 时添加的 name 要对应上
@CacheConfig(cacheNames = "redis", keyGenerator = "keyGenerator")
public class RedisService {
    @Resource
    private CacheManager cacheManager;

    @Cacheable
    public String get1() {
        System.out.println(new Date() + "--> No value from cache");
        return "Ramos";
    }

    @Cacheable
    public User get2() {
        System.out.println(new Date() + "--> No value from cache");
        return new User(1, "dufu");
    }
}

运行效果

  1. 操作字符串
    在这里插入图片描述

查看 redis 客户端,发现已经有数据存入到库中
在这里插入图片描述
2. 操作对象
在这里插入图片描述
查看 redis 客户端,发现已经有数据存入到库中
在这里插入图片描述
此时,如果我们反复刷新页面,RedisService.class 中的 get1() 和 get2() 方法也只会打印出一次:No value from cache,说明缓存(redis)已经生效

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

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

相关文章

【人脸识别】DDL:数据分布知识蒸馏思想,提升困难样本(遮挡、低分辨率等)识别效果

论文题目&#xff1a;《Improving Face Recognition from Hard Samples via Distribution Distillation Loss》 论文地址&#xff1a;https://arxiv.org/pdf/2002.03662v3.pdf 代码地址&#xff1a;https://github.com/HuangYG123/DDL 1.前言及相关工作 Large facial variatio…

秒懂算法 | 基于图神经网络的推荐算法

图神经网络(Graph Neural Networks,GNN)是近几年兴起的学科,用来作推荐算法自然效果也相当好,但是要学会基于图神经网络的推荐算法之前,需要对图神经网络自身有个了解。 图卷积网络(Graph Convolutional Networks,GCN)提出于2017年。GCN 的出现标志着图神经网络的出现。深度学习…

大家一起来找茬,新手第一次layout到底能挑出多少毛病?

有一个新手工程师在论坛上发了一篇帖子&#xff0c;把自己的处女PCB布线图贴出来。 如果不看其他网友的评论&#xff0c;你能看出多少问题呢&#xff1f;可以在留言区和我们互动哦~ 帖子里他还提出了自己的小见解&#xff1a;问一下&#xff0c;我觉得自动布线挺好用的啊&#…

汽车标定知识整理(一):标定简介与CCP报文协议简介

目录 一、什么是标定 二、XCP与CCP 三、CCP报文协议简介 1、CCP报文协议简介 &#xff08;1&#xff09;CRO&#xff1a;Command Receive Object &#xff0c;命令接收对象&#xff08;由Master -> Slave&#xff09; &#xff08;2&#xff09;DTO&#xff1a;Data T…

Kotlin 39. Dependency Injection依赖注入以及Hilt在Kotlin中的使用,系列2:手动依赖注入

一起来学Kotlin&#xff1a;概念&#xff1a;26. Dependency Injection依赖注入以及Hilt在Kotlin中的使用&#xff0c;系列2&#xff1a;手动依赖注入 此系列博客中&#xff0c;我们将主要介绍&#xff1a; Dependency Injection&#xff08;依赖注入&#xff09; 概念介绍。…

当IDEA加载一个MAVEN新项目时,加载不成功,无法加载依赖的解决方法

当IDEA加载一个MAVEN新项目时&#xff0c;加载不成功&#xff0c;无法加载依赖的解决方法 此文为练习项目时的错误记录 当使用IDEA引入一个MAVEN新项目时&#xff0c;点击Reload maven按钮加载不成功&#xff0c;显示如下图界面&#xff1a; 在项目中的代码显示报红&#xff0c…

urllib之ProxyHandler代理以及CookieJar的cookie内存传递和本地保存与读取的使用详解

处理更高级操作时(Cookies处理&#xff0c;代理设置)&#xff0c;需要一个强大的工具Handler&#xff0c;可以理解成各种处理器&#xff0c;有处理登录认证的、有处理Cookies的、有处理代理设置的。利用这些几乎可以做到HTTP请求中所有事情。当中urllib.request模块里的 BaseHa…

机器学习:基于朴素贝叶斯对花瓣花萼的宽度和长度分类预测

机器学习&#xff1a;基于朴素贝叶斯对花瓣花萼的宽度和长度分类预测 作者&#xff1a;AOAIYI 作者简介&#xff1a;Python领域新星作者、多项比赛获奖者&#xff1a;AOAIYI首页 &#x1f60a;&#x1f60a;&#x1f60a;如果觉得文章不错或能帮助到你学习&#xff0c;可以点赞…

MySQL实战解析底层---基础架构:一条SQL查询语句是如何执行的?

目录 前言 连接器 查询缓存 分析器 优化器 执行器 前言 平时使用数据库&#xff0c;看到的通常都是一个整体比如&#xff0c;有个最简单的表&#xff0c;表里只有一个 ID 字段&#xff0c;在执行下面这个查询语句时&#xff1a; 看到的只是输入一条语句&#xff0c;返回…

微电影广告的内容突破方案

微电影作为新媒体时代背景的产物&#xff0c;深受大众的欢迎&#xff0c;同时&#xff0c;微电影广告在微电影模式环境下应运而生&#xff0c;以自己独特的传播优势&#xff0c;俘获了大量企业主的青睐&#xff0c;也获得了广大青年群体的喜爱。微电影广告欲确保可持续发展&…

Android App异常崩溃处理详解

异常崩溃是Android项目中一个棘手的问题&#xff0c;即使你做了很多的try - catch处理&#xff0c;也不能保证不崩溃&#xff0c;一旦崩溃就会出现下图的弹窗&#xff0c;xx应用就会停止运行这种体验对于用户来说是很差的&#xff0c;所以很明显我们做的app已经崩溃了。 像现在…

社科院与杜兰大学金融管理硕士项目——在这里共同改变,一起前行

人这一生&#xff0c;要走很长的路&#xff0c;才能确定前行的方向&#xff0c;在路上遇到很多的人&#xff0c;才知道与谁同行。在人生旅程中&#xff0c;保持怎样的姿态前行&#xff0c;往往与身边的人有很大关系。身边的人都很努力&#xff0c;你也会跟着努力上进。怀揣着在…

Synchronized,我要一层一层剥开你的心

三种应用方式 修饰实例方法&#xff0c;作用于当前实例加锁&#xff0c;进入同步代码前要获得当前实例的锁。修饰静态方法&#xff0c;作用于当前类对象加锁&#xff0c;进入同步代码前要获得当前类对象的锁。修饰代码块&#xff0c;指定加锁对象&#xff0c;对给定对象加锁&a…

TypeScript 使用 ES6 解构骚操作

TypeScript 使用 ES6 解构骚操作 文章目录TypeScript 使用 ES6 解构骚操作一、TypeScript 对象解构二、TypeScript 函数参数解构四、参考资料&#x1f498;五、推荐博文&#x1f357;一、TypeScript 对象解构 我们都知道 ES6 的数据解构功能很强大&#xff0c;一行命令就能够声…

HTMLCSS常见问题解决

文章目录一、解决img图片底部空白问题1、出现问题的效果2、原理3、解决方式3.1、将图片变为盒子3.2、处理基线3.3、把上级元素的字体大小改成0像素二、解决给子元素设置margin-top父子盒子都向下移动问题1、出现问题的效果2、原理3、解决方式3.1、给父元素设置边框3.2、给父元素…

程序员多赚20k的接私活必备网站

为什么都是程序员&#xff0c;就有人能多赚20k&#xff1f;那是因为副业搞得那么溜啊&#xff01; 今天分享一些程序员搞钱必备的接私活网站&#xff0c;让更多程序员们在工作之余能有另外一份收入。 1.程序员客栈&#xff1a;http://proginn.com 专为程序员服务的软件外包对…

跨境电商代购系统演示说明

首先来看什么是淘宝代购淘宝代购是近年兴起的一种购物模式&#xff0c;是帮国外客户购买中国商品。主要是通过万邦 科技的外贸代购系统&#xff0c;把淘宝、天猫等电商平台的全站商品通过API 接入到你的网站 上&#xff0c;瞬间就可以架设一个有数亿产品的大型网上商城&#xf…

FATE联邦学习centos成功部署

官方文档&#xff1a;https://fate.readthedocs.io/en/latest/deploy/standalone-deploy/#1-description。 我用的文档中的Standalone的第二种安装方式&#xff0c;没用docker。 安装过程 文档上写着确定版本 export version1.7.0但是你别真的用1.7.0啊&#xff01; &#…

ATS认证教学

我用的版本是ATS7.11、系统版本是用最新的ios13.2.1 定义 ATS旨在分析通过UART、USB和蓝牙传输传输的iAP流量、通过USB和无线&#xff08;蓝牙和Wi-Fi&#xff09;传输的CarPlay流量、通过Wi-Fi传输的AirPlay 2流量以及闪电音频流量。 ATS是Apple’s Accessory Test System的…

Cookie、Session、JWT 那些事

文章目录前言一、概念1、Cookie&#xff1a;2、Session&#xff1a;3、JWT二、应用1. 基本使用2. 实现 “退出” 功能总结前言 目前 C/S 模式盛行&#xff0c;HTTP 是其中最常见的通信协议&#xff0c;我们知道 HTTP 协议是无状态的&#xff0c;但是这场景完全不够用。 比如&…