欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SpringBoot整合Redis及Redis工具类撰写实例

程序员文章站 2022-03-24 08:06:03
目录一、maven依赖二、application.properties中加入redis相关配置三、写一个redis配置类四、写一个redis工具类五、小结springboot整合redis的博客很多,...

springboot整合redis的博客很多,但是很多都不是我想要的结果。因为我只需要整合完成后,可以操作redis就可以了,并不需要配合缓存相关的注解使用(如@cacheable)。看了很多博客后,我成功的整合了,并写了个redis操作工具类。特意在此记录一下,方便后续查阅。

一、maven依赖

(1)本文所采用的springboot的版本如下

   <parent>
        <groupid>org.springframework.boot</groupid>
        <artifactid>spring-boot-starter-parent</artifactid>
        <version>2.0.2.release</version>
        <relativepath/> <!-- lookup parent from repository -->
    </parent>

(2)加入redis相关依赖

        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-data-redis</artifactid>
        </dependency> 

二、application.properties中加入redis相关配置

# redis数据库索引(默认为0)  
spring.redis.database=0  
# redis服务器地址  
spring.redis.host=192.168.0.24  
# redis服务器连接端口  
spring.redis.port=6379  
# redis服务器连接密码(默认为空)  
spring.redis.password=  
# 连接池最大连接数(使用负值表示没有限制)  
spring.redis.pool.max-active=200  
# 连接池最大阻塞等待时间(使用负值表示没有限制)  
spring.redis.pool.max-wait=-1  
# 连接池中的最大空闲连接  
spring.redis.pool.max-idle=10 
# 连接池中的最小空闲连接  
spring.redis.pool.min-idle=0  
# 连接超时时间(毫秒)  
spring.redis.timeout=1000 

三、写一个redis配置类

(1)聊聊redistemplate的自动配置

其实现在就可以在代码中注入redistemplate,为啥可以直接注入呢?先看下源码吧。下图为 redisautoconfiguration类中的截图,为了防止图片失效,代码也贴上 。

SpringBoot整合Redis及Redis工具类撰写实例

代码:

@configuration
@conditionalonclass(redisoperations.class)
@enableconfigurationproperties(redisproperties.class)
@import({ lettuceconnectionconfiguration.class, jedisconnectionconfiguration.class })
public class redisautoconfiguration {
    @bean
    @conditionalonmissingbean(name = "redistemplate")
    public redistemplate<object, object> redistemplate(
            redisconnectionfactory redisconnectionfactory) throws unknownhostexception {
        redistemplate<object, object> template = new redistemplate<>();
        template.setconnectionfactory(redisconnectionfactory);
        return template;
    }
    @bean
    @conditionalonmissingbean
    public stringredistemplate stringredistemplate(
            redisconnectionfactory redisconnectionfactory) throws unknownhostexception {
        stringredistemplate template = new stringredistemplate();
        template.setconnectionfactory(redisconnectionfactory);
        return template;
    }
}     

通过源码可以看出,springboot自动帮我们在容器中生成了一个redistemplate和一个stringredistemplate。但是,这个redistemplate的泛型是<object,object>,写代码不方便,需要写好多类型转换的代码;我们需要一个泛型为<string,object>形式的redistemplate。并且,这个redistemplate没有设置数据存在redis时,key及value的序列化方式。       

看到这个@conditionalonmissingbean注解后,就知道如果spring容器中有了redistemplate对象了,这个自动配置的redistemplate不会实例化。因此我们可以直接自己写个配置类,配置redistemplate。

(2)既然自动配置不好用,就重新配置一个redistemplate

代码如下:

package com.zxy.demo.redis;
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.stringredisserializer;
import com.fasterxml.jackson.annotation.jsonautodetect;
import com.fasterxml.jackson.annotation.propertyaccessor;
import com.fasterxml.jackson.databind.objectmapper;
/**
 * redis配置类
 * @author zeng.xiao.yan
 * @date   2018年6月6日
 * 
 */
@configuration
public class redisconfig {
    
	@bean
	@suppresswarnings("all")
    public redistemplate<string, object> redistemplate(redisconnectionfactory factory) {
    	redistemplate<string, object> template = new redistemplate<string, object>();
    	template.setconnectionfactory(factory);
		jackson2jsonredisserializer jackson2jsonredisserializer = new jackson2jsonredisserializer(object.class);
        objectmapper om = new objectmapper();
        om.setvisibility(propertyaccessor.all, jsonautodetect.visibility.any);
        om.enabledefaulttyping(objectmapper.defaulttyping.non_final);
        jackson2jsonredisserializer.setobjectmapper(om);
        stringredisserializer stringredisserializer = new stringredisserializer();
        // key采用string的序列化方式
        template.setkeyserializer(stringredisserializer);
        // hash的key也采用string的序列化方式
        template.sethashkeyserializer(stringredisserializer);
        // value序列化方式采用jackson
        template.setvalueserializer(jackson2jsonredisserializer);
        // hash的value序列化方式采用jackson
        template.sethashvalueserializer(jackson2jsonredisserializer);
        template.afterpropertiesset();
        return template;
    }
}

四、写一个redis工具类

直接用redistemplate操作redis,需要很多行代码,因此直接封装好一个redisutils,这样写代码更方便点。这个redisutils交给spring容器实例化,使用时直接注解注入。

工具类代码如下:

package com.zxy.demo.redis;
import java.util.list;
import java.util.map;
import java.util.set;
import java.util.concurrent.timeunit;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.data.redis.core.redistemplate;
import org.springframework.stereotype.component;
import org.springframework.util.collectionutils;
/**
 * redis工具类
 * @author zeng.xiao.yan
 * @date   2018年6月7日
 */
@component
public final class redisutil {
	
	@autowired
	private redistemplate<string, object> redistemplate;
	// =============================common============================
	/**
	 * 指定缓存失效时间
	 * @param key 键
	 * @param time 时间(秒)
	 * @return
	 */
	public boolean expire(string key, long time) {
		try {
			if (time > 0) {
				redistemplate.expire(key, time, timeunit.seconds);
			}
			return true;
		} catch (exception e) {
			e.printstacktrace();
			return false;
		}
	}
	/**
	 * 根据key 获取过期时间
	 * @param key 键 不能为null
	 * @return 时间(秒) 返回0代表为永久有效
	 */
	public long getexpire(string key) {
		return redistemplate.getexpire(key, timeunit.seconds);
	}
	/**
	 * 判断key是否存在
	 * @param key 键
	 * @return true 存在 false不存在
	 */
	public boolean haskey(string key) {
		try {
			return redistemplate.haskey(key);
		} catch (exception e) {
			e.printstacktrace();
			return false;
		}
	}
	/**
	 * 删除缓存
	 * @param key 可以传一个值 或多个
	 */
	@suppresswarnings("unchecked")
	public void del(string... key) {
		if (key != null && key.length > 0) {
			if (key.length == 1) {
				redistemplate.delete(key[0]);
			} else {
				redistemplate.delete(collectionutils.arraytolist(key));
			}
		}
	}
	// ============================string=============================
	/**
	 * 普通缓存获取
	 * @param key 键
	 * @return 值
	 */
	public object get(string key) {
		return key == null ? null : redistemplate.opsforvalue().get(key);
	}
	/**
	 * 普通缓存放入
	 * @param key 键
	 * @param value 值
	 * @return true成功 false失败
	 */
	public boolean set(string key, object value) {
		try {
			redistemplate.opsforvalue().set(key, value);
			return true;
		} catch (exception e) {
			e.printstacktrace();
			return false;
		}
	}
	/**
	 * 普通缓存放入并设置时间
	 * @param key 键
	 * @param value 值
	 * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
	 * @return true成功 false 失败
	 */
	public boolean set(string key, object value, long time) {
		try {
			if (time > 0) {
				redistemplate.opsforvalue().set(key, value, time, timeunit.seconds);
			} else {
				set(key, value);
			}
			return true;
		} catch (exception e) {
			e.printstacktrace();
			return false;
		}
	}
	/**
	 * 递增
	 * @param key 键
	 * @param delta 要增加几(大于0)
	 * @return
	 */
	public long incr(string key, long delta) {
		if (delta < 0) {
			throw new runtimeexception("递增因子必须大于0");
		}
		return redistemplate.opsforvalue().increment(key, delta);
	}
	/**
	 * 递减
	 * @param key 键
	 * @param delta 要减少几(小于0)
	 * @return
	 */
	public long decr(string key, long delta) {
		if (delta < 0) {
			throw new runtimeexception("递减因子必须大于0");
		}
		return redistemplate.opsforvalue().increment(key, -delta);
	}
	// ================================map=================================
	/**
	 * hashget
	 * @param key 键 不能为null
	 * @param item 项 不能为null
	 * @return 值
	 */
	public object hget(string key, string item) {
		return redistemplate.opsforhash().get(key, item);
	}
	/**
	 * 获取hashkey对应的所有键值
	 * @param key 键
	 * @return 对应的多个键值
	 */
	public map<object, object> hmget(string key) {
		return redistemplate.opsforhash().entries(key);
	}
	/**
	 * hashset
	 * @param key 键
	 * @param map 对应多个键值
	 * @return true 成功 false 失败
	 */
	public boolean hmset(string key, map<string, object> map) {
		try {
			redistemplate.opsforhash().putall(key, map);
			return true;
		} catch (exception e) {
			e.printstacktrace();
			return false;
		}
	}
	/**
	 * hashset 并设置时间
	 * @param key 键
	 * @param map 对应多个键值
	 * @param time 时间(秒)
	 * @return true成功 false失败
	 */
	public boolean hmset(string key, map<string, object> map, long time) {
		try {
			redistemplate.opsforhash().putall(key, map);
			if (time > 0) {
				expire(key, time);
			}
			return true;
		} catch (exception e) {
			e.printstacktrace();
			return false;
		}
	}
	/**
	 * 向一张hash表中放入数据,如果不存在将创建
	 * @param key 键
	 * @param item 项
	 * @param value 值
	 * @return true 成功 false失败
	 */
	public boolean hset(string key, string item, object value) {
		try {
			redistemplate.opsforhash().put(key, item, value);
			return true;
		} catch (exception e) {
			e.printstacktrace();
			return false;
		}
	}
	/**
	 * 向一张hash表中放入数据,如果不存在将创建
	 * @param key 键
	 * @param item 项
	 * @param value 值
	 * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
	 * @return true 成功 false失败
	 */
	public boolean hset(string key, string item, object value, long time) {
		try {
			redistemplate.opsforhash().put(key, item, value);
			if (time > 0) {
				expire(key, time);
			}
			return true;
		} catch (exception e) {
			e.printstacktrace();
			return false;
		}
	}
	/**
	 * 删除hash表中的值
	 * @param key 键 不能为null
	 * @param item 项 可以使多个 不能为null
	 */
	public void hdel(string key, object... item) {
		redistemplate.opsforhash().delete(key, item);
	}
	/**
	 * 判断hash表中是否有该项的值
	 * @param key 键 不能为null
	 * @param item 项 不能为null
	 * @return true 存在 false不存在
	 */
	public boolean hhaskey(string key, string item) {
		return redistemplate.opsforhash().haskey(key, item);
	}
	/**
	 * hash递增 如果不存在,就会创建一个 并把新增后的值返回
	 * @param key 键
	 * @param item 项
	 * @param by 要增加几(大于0)
	 * @return
	 */
	public double hincr(string key, string item, double by) {
		return redistemplate.opsforhash().increment(key, item, by);
	}
	/**
	 * hash递减
	 * @param key 键
	 * @param item 项
	 * @param by 要减少记(小于0)
	 * @return
	 */
	public double hdecr(string key, string item, double by) {
		return redistemplate.opsforhash().increment(key, item, -by);
	}
	// ============================set=============================
	/**
	 * 根据key获取set中的所有值
	 * @param key 键
	 * @return
	 */
	public set<object> sget(string key) {
		try {
			return redistemplate.opsforset().members(key);
		} catch (exception e) {
			e.printstacktrace();
			return null;
		}
	}
	/**
	 * 根据value从一个set中查询,是否存在
	 * @param key 键
	 * @param value 值
	 * @return true 存在 false不存在
	 */
	public boolean shaskey(string key, object value) {
		try {
			return redistemplate.opsforset().ismember(key, value);
		} catch (exception e) {
			e.printstacktrace();
			return false;
		}
	}
	/**
	 * 将数据放入set缓存
	 * @param key 键
	 * @param values 值 可以是多个
	 * @return 成功个数
	 */
	public long sset(string key, object... values) {
		try {
			return redistemplate.opsforset().add(key, values);
		} catch (exception e) {
			e.printstacktrace();
			return 0;
		}
	}
	/**
	 * 将set数据放入缓存
	 * @param key 键
	 * @param time 时间(秒)
	 * @param values 值 可以是多个
	 * @return 成功个数
	 */
	public long ssetandtime(string key, long time, object... values) {
		try {
			long count = redistemplate.opsforset().add(key, values);
			if (time > 0)
				expire(key, time);
			return count;
		} catch (exception e) {
			e.printstacktrace();
			return 0;
		}
	}
	/**
	 * 获取set缓存的长度
	 * @param key 键
	 * @return
	 */
	public long sgetsetsize(string key) {
		try {
			return redistemplate.opsforset().size(key);
		} catch (exception e) {
			e.printstacktrace();
			return 0;
		}
	}
	/**
	 * 移除值为value的
	 * @param key 键
	 * @param values 值 可以是多个
	 * @return 移除的个数
	 */
	public long setremove(string key, object... values) {
		try {
			long count = redistemplate.opsforset().remove(key, values);
			return count;
		} catch (exception e) {
			e.printstacktrace();
			return 0;
		}
	}
	// ===============================list=================================
	/**
	 * 获取list缓存的内容
	 * @param key 键
	 * @param start 开始
	 * @param end 结束 0 到 -1代表所有值
	 * @return
	 */
	public list<object> lget(string key, long start, long end) {
		try {
			return redistemplate.opsforlist().range(key, start, end);
		} catch (exception e) {
			e.printstacktrace();
			return null;
		}
	}
	/**
	 * 获取list缓存的长度
	 * @param key 键
	 * @return
	 */
	public long lgetlistsize(string key) {
		try {
			return redistemplate.opsforlist().size(key);
		} catch (exception e) {
			e.printstacktrace();
			return 0;
		}
	}
	/**
	 * 通过索引 获取list中的值
	 * @param key 键
	 * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
	 * @return
	 */
	public object lgetindex(string key, long index) {
		try {
			return redistemplate.opsforlist().index(key, index);
		} catch (exception e) {
			e.printstacktrace();
			return null;
		}
	}
	/**
	 * 将list放入缓存
	 * @param key 键
	 * @param value 值
	 * @param time 时间(秒)
	 * @return
	 */
	public boolean lset(string key, object value) {
		try {
			redistemplate.opsforlist().rightpush(key, value);
			return true;
		} catch (exception e) {
			e.printstacktrace();
			return false;
		}
	}
	/**
	 * 将list放入缓存
	 * @param key 键
	 * @param value 值
	 * @param time 时间(秒)
	 * @return
	 */
	public boolean lset(string key, object value, long time) {
		try {
			redistemplate.opsforlist().rightpush(key, value);
			if (time > 0)
				expire(key, time);
			return true;
		} catch (exception e) {
			e.printstacktrace();
			return false;
		}
	}
	/**
	 * 将list放入缓存
	 * @param key 键
	 * @param value 值
	 * @param time 时间(秒)
	 * @return
	 */
	public boolean lset(string key, list<object> value) {
		try {
			redistemplate.opsforlist().rightpushall(key, value);
			return true;
		} catch (exception e) {
			e.printstacktrace();
			return false;
		}
	}
	/**
	 * 将list放入缓存
	 * 
	 * @param key 键
	 * @param value 值
	 * @param time 时间(秒)
	 * @return
	 */
	public boolean lset(string key, list<object> value, long time) {
		try {
			redistemplate.opsforlist().rightpushall(key, value);
			if (time > 0)
				expire(key, time);
			return true;
		} catch (exception e) {
			e.printstacktrace();
			return false;
		}
	}
	/**
	 * 根据索引修改list中的某条数据
	 * @param key 键
	 * @param index 索引
	 * @param value 值
	 * @return
	 */
	public boolean lupdateindex(string key, long index, object value) {
		try {
			redistemplate.opsforlist().set(key, index, value);
			return true;
		} catch (exception e) {
			e.printstacktrace();
			return false;
		}
	}
	/**
	 * 移除n个值为value
	 * @param key 键
	 * @param count 移除多少个
	 * @param value 值
	 * @return 移除的个数
	 */
	public long lremove(string key, long count, object value) {
		try {
			long remove = redistemplate.opsforlist().remove(key, count, value);
			return remove;
		} catch (exception e) {
			e.printstacktrace();
			return 0;
		}
	}
}

五、小结

整合其实不麻烦,网上好多博文都有。注意设置下key和value的序列化方式,不然存到redis的中数据看起来像乱码一下。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。