背景:由于自研框架,好多公司都自己封装自己的Redis,所以需要单独讲redis封装起来,作为公举模块给业务系统用。自动装配原理就不介绍了,网上一搜一大堆,说的都不错。废话不多数,上代码
目录
4.redis模块pom配置 lilock-redis-spring-boot-starter
4.4 springboot装配文件 spring.factories
项目结构:
lilock-framework lilock-commons lilock-common-spring-boot-starter lilock-redis-spring-boot-starter lilock-modules lilock-service-user
1.springboot 版本号选择
我自己选定的版本号是 2.3.12.RELEASE,可以根据自己公司对springboot的版本号情况自己选定
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.12.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent>
2.项目根pom配置 lilock-framework
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<modules>
<module>lilock-commons</module>
<module>lilock-modules</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
</parent>
<groupId>lilock.cn</groupId>
<artifactId>lilock-framework</artifactId>
<version>1.0-SNAPSHOT</version>
<name>lilock-framework</name>
<packaging>pom</packaging>
<properties>
<java.version>8</java.version>
<spring.boot.version>2.3.12.RELEASE</spring.boot.version>
<lombok.version>1.18.26</lombok.version>
<jackson.version>2.14.2</jackson.version>
<jedis.version>3.8.0</jedis.version>
<swagger.version>2.9.2</swagger.version>
<fastjson.version>1.2.70</fastjson.version>
<nacos.version>2.1.0.RELEASE</nacos.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
</dependency>
<!-- jedis配置-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!-- Jackson序列化配置-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.公共模块pom配置 lilock-commons
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>lilock-framework</artifactId>
<groupId>lilock.cn</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lilock-commons</artifactId>
<packaging>pom</packaging>
<modules>
<module>lilock-redis-spring-boot-starter</module>
</modules>
</project>
4.redis模块pom配置 lilock-redis-spring-boot-starter
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>lilock-commons</artifactId>
<groupId>lilock.cn</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath/>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lilock-common-spring-redis-starter</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<!-- 以防止repackage目标将依赖项添加到 jar 中 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
上述配置Redis自动装配模块的所有配置,开始进入主题
4.1 自定义redis参数配置类
package lilock.cn.common.redis.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Data
@ConfigurationProperties(prefix = "lilock.redis")
public class RedisDataSourceProperties {
//链接地址
private String host;
//端口号
private Integer port;
//默认database
private Integer database;
//密码
private String password;
//超时时间
private Integer timeout;
//最大空闲数
private Integer maxIdle;
//连接池最大连接数
private Integer maxTotal;
//最大等待时间
private Integer maxWaitMillis;
//逐出链接最小空闲时间
private Integer minEvictableIdleTimeMillis;
//每次最大逐出数量
private Integer numTestsPerEvictionRun;
//逐出扫描时间的间隔
private Long timeBetweenEvictionRunsMillis;
///是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
private boolean testOnBorrow;
//空闲时检查有效性
private boolean testWhileIdle;
}
4.2 自定义redis工具类 RedisService
package lilock.cn.common.redis.template;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.connection.RedisClusterNode;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisServerCommands;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.CollectionUtils;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* Redis Repository
* redis 基本操作 可扩展,基本够用了
*
*/
@Slf4j
public class RedisService {
/**
* 默认编码
*/
private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
/**
* key序列化
*/
private static final StringRedisSerializer STRING_SERIALIZER = new StringRedisSerializer();
/**
* value 序列化
*/
private static final JdkSerializationRedisSerializer OBJECT_SERIALIZER = new JdkSerializationRedisSerializer();
/**
* Spring Redis Template
*/
private RedisTemplate<String, Object> redisTemplate;
public RedisService(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
this.redisTemplate.setKeySerializer(STRING_SERIALIZER);
this.redisTemplate.setValueSerializer(OBJECT_SERIALIZER);
}
/**
* 获取链接工厂
*/
public RedisConnectionFactory getConnectionFactory() {
return this.redisTemplate.getConnectionFactory();
}
/**
* 获取 RedisTemplate对象
*/
public RedisTemplate<String, Object> getRedisTemplate() {
return redisTemplate;
}
/**
* 清空DB
*
* @param node redis 节点
*/
public void flushDB(RedisClusterNode node) {
this.redisTemplate.opsForCluster().flushDb(node);
}
/**
* 添加到带有 过期时间的 缓存
*
* @param key redis主键
* @param value 值
* @param time 过期时间(单位秒)
*/
public void setExpire(final byte[] key, final byte[] value, final long time) {
redisTemplate.execute((RedisCallback<Long>) connection -> {
connection.setEx(key, time, value);
log.debug("[redisTemplate redis]放入 缓存 url:{} ========缓存时间为{}秒", key, time);
return 1L;
});
}
/**
* 添加到带有 过期时间的 缓存
*
* @param key redis主键
* @param value 值
* @param time 过期时间(单位秒)
*/
public void setExpire(final String key, final Object value, final long time) {
redisTemplate.execute((RedisCallback<Long>) connection -> {
RedisSerializer<String> serializer = getRedisSerializer();
byte[] keys = serializer.serialize(key);
byte[] values = OBJECT_SERIALIZER.serialize(value);
boolean f = connection.setEx(keys, time, values);
log.info("[redisTemplate redis]放入 缓存 url:{} ========缓存时间为{}秒,{}", key, time, f);
return 1L;
});
}
/**
* 一次性添加数组到 过期时间的 缓存,不用多次连接,节省开销
*
* @param keys redis主键数组
* @param values 值数组
* @param time 过期时间(单位秒)
*/
public void setExpire(final String[] keys, final Object[] values, final long time) {
redisTemplate.execute((RedisCallback<Long>) connection -> {
RedisSerializer<String> serializer = getRedisSerializer();
for (int i = 0; i < keys.length; i++) {
byte[] bKeys = serializer.serialize(keys[i]);
byte[] bValues = OBJECT_SERIALIZER.serialize(values[i]);
connection.setEx(bKeys, time, bValues);
}
return 1L;
});
}
/**
* 一次性添加数组到 过期时间的 缓存,不用多次连接,节省开销
*
* @param keys the keys
* @param values the values
*/
public void set(final String[] keys, final Object[] values) {
redisTemplate.execute((RedisCallback<Long>) connection -> {
RedisSerializer<String> serializer = getRedisSerializer();
for (int i = 0; i < keys.length; i++) {
byte[] bKeys = serializer.serialize(keys[i]);
byte[] bValues = OBJECT_SERIALIZER.serialize(values[i]);
connection.set(bKeys, bValues);
}
return 1L;
});
}
/**
* 添加到缓存
*
* @param key the key
* @param value the value
*/
public void set(final String key, final Object value) {
redisTemplate.execute((RedisCallback<Long>) connection -> {
RedisSerializer<String> serializer = getRedisSerializer();
byte[] keys = serializer.serialize(key);
byte[] values = OBJECT_SERIALIZER.serialize(value);
connection.set(keys, values);
log.debug("[redisTemplate redis]放入 缓存 url:{}", key);
return 1L;
});
}
/**
* 查询在这个时间段内即将过期的key
*
* @param key the key
* @param time the time
* @return the list
*/
public List<String> willExpire(final String key, final long time) {
final List<String> keysList = new ArrayList<>();
redisTemplate.execute((RedisCallback<List<String>>) connection -> {
Set<String> keys = redisTemplate.keys(key + "*");
for (String key1 : keys) {
Long ttl = connection.ttl(key1.getBytes(DEFAULT_CHARSET));
if (0 <= ttl && ttl <= 2 * time) {
keysList.add(key1);
}
}
return keysList;
});
return keysList;
}
/**
* 查询在以keyPatten的所有 key
*
* @param keyPatten the key patten
* @return the set
*/
public Set<String> keys(final String keyPatten) {
return redisTemplate.execute((RedisCallback<Set<String>>) connection -> redisTemplate.keys(keyPatten + "*"));
}
/**
* 利用scan 查询 keyPattern关键字的key集合
* @param keyPattern
* @return
*/
public Set<String> scan(final String keyPattern) {
Set<String> keys = redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
Set<String> keysTmp = new HashSet<>();
Cursor<byte[]> cursor = connection.scan(KeyScanOptions.scanOptions().match( keyPattern + "*").count(1000).build());
while (cursor.hasNext()) {
keysTmp.add(new String(cursor.next()));
}
return keysTmp;
});
return keys;
}
/**
* 根据key获取对象
*
* @param key the key
* @return the byte [ ]
*/
public byte[] get(final byte[] key) {
byte[] result = redisTemplate.execute((RedisCallback<byte[]>) connection -> connection.get(key));
log.debug("[redisTemplate redis]取出 缓存 url:{} ", key);
return result;
}
/**
* 根据key获取对象
*
* @param key the key
* @return the string
*/
public Object get(final String key) {
Object resultStr = redisTemplate.execute((RedisCallback<Object>) connection -> {
RedisSerializer<String> serializer = getRedisSerializer();
byte[] keys = serializer.serialize(key);
byte[] values = connection.get(keys);
return OBJECT_SERIALIZER.deserialize(values);
});
log.debug("[redisTemplate redis]取出 缓存 url:{} ", key);
return resultStr;
}
/**
* 根据key获取对象
*
* @param keyPatten the key patten
* @return the keys values
*/
public Map<String, Object> getKeysValues(final String keyPatten) {
log.debug("[redisTemplate redis] getValues() patten={} ", keyPatten);
return redisTemplate.execute((RedisCallback<Map<String, Object>>) connection -> {
RedisSerializer<String> serializer = getRedisSerializer();
Map<String, Object> maps = new HashMap<>(16);
Set<String> keys = redisTemplate.keys(keyPatten + "*");
if (!CollectionUtils.isEmpty(keys)) {
for (String key : keys) {
byte[] bKeys = serializer.serialize(key);
byte[] bValues = connection.get(bKeys);
Object value = OBJECT_SERIALIZER.deserialize(bValues);
maps.put(key, value);
}
}
return maps;
});
}
/**
* Ops for hash hash operations.
*
* @return the hash operations
*/
public HashOperations<String, String, Object> opsForHash() {
return redisTemplate.opsForHash();
}
/**
* 对HashMap操作
*
* @param key the key
* @param hashKey the hash key
* @param hashValue the hash value
*/
public void putHashValue(String key, String hashKey, Object hashValue) {
log.debug("[redisTemplate redis] putHashValue() key={},hashKey={},hashValue={} ", key, hashKey, hashValue);
opsForHash().put(key, hashKey, hashValue);
}
/**
* 获取单个field对应的值
*
* @param key the key
* @param hashKey the hash key
* @return the hash values
*/
public Object getHashValues(String key, String hashKey) {
log.debug("[redisTemplate redis] getHashValues() key={},hashKey={}", key, hashKey);
return opsForHash().get(key, hashKey);
}
/**
* 根据key值删除
*
* @param key the key
* @param hashKeys the hash keys
*/
public void delHashValues(String key, Object... hashKeys) {
log.debug("[redisTemplate redis] delHashValues() key={}", key);
opsForHash().delete(key, hashKeys);
}
/**
* key只匹配map
*
* @param key the key
* @return the hash value
*/
public Map<String, Object> getHashValue(String key) {
log.debug("[redisTemplate redis] getHashValue() key={}", key);
return opsForHash().entries(key);
}
/**
* 批量添加
*
* @param key the key
* @param map the map
*/
public void putHashValues(String key, Map<String, Object> map) {
opsForHash().putAll(key, map);
}
/**
* 集合数量
*
* @return the long
*/
public long dbSize() {
return redisTemplate.execute(RedisServerCommands::dbSize);
}
/**
* 清空redis存储的数据
*
* @return the string
*/
public String flushDB() {
return redisTemplate.execute((RedisCallback<String>) connection -> {
connection.flushDb();
return "ok";
});
}
/**
* 判断某个主键是否存在
*
* @param key the key
* @return the boolean
*/
public boolean exists(final String key) {
return redisTemplate.execute((RedisCallback<Boolean>) connection -> connection.exists(key.getBytes(DEFAULT_CHARSET)));
}
/**
* 删除key
*
* @param keys the keys
* @return the long
*/
public long del(final String... keys) {
return redisTemplate.execute((RedisCallback<Long>) connection -> {
long result = 0;
for (String key : keys) {
result = connection.del(key.getBytes(DEFAULT_CHARSET));
}
return result;
});
}
/**
* 获取 RedisSerializer
*
* @return the redis serializer
*/
protected RedisSerializer<String> getRedisSerializer() {
return redisTemplate.getStringSerializer();
}
/**
* 对某个主键对应的值加一,value值必须是全数字的字符串
*
* @param key the key
* @return the long
*/
public long incr(final String key) {
return redisTemplate.execute((RedisCallback<Long>) connection -> {
RedisSerializer<String> redisSerializer = getRedisSerializer();
return connection.incr(redisSerializer.serialize(key));
});
}
/**
* 对某个主键对应的值减一,value值必须是全数字的字符串
*
* @param key the key
* @return the long
*/
public long decr(final String key) {
return redisTemplate.execute((RedisCallback<Long>) connection -> {
RedisSerializer<String> redisSerializer = getRedisSerializer();
return connection.decr(redisSerializer.serialize(key));
});
}
/**
* redis List 引擎
*
* @return the list operations
*/
public ListOperations<String, Object> opsForList() {
return redisTemplate.opsForList();
}
/**
* redis set
* @return
*/
public SetOperations<String, Object> opsForSet(){
return redisTemplate.opsForSet();
}
/**
* //集合中添加元素,返回添加个数
* @param setkeyName
* @param value
* @return
*/
public Long addToSet(String setkeyName, String... value){
Long addNum = redisTemplate.opsForSet().add(setkeyName, value);
return addNum;
}
/**
* 获取集合大小
* @param setKeyName
* @return
*/
public Long getSetSize(String setKeyName){
return redisTemplate.opsForSet().size(setKeyName);
}
/**
* 获取所有的元素
* @param setKeyName
* @return
*/
public Set getSetMember(String setKeyName){
Set<Object> members = redisTemplate.opsForSet().members(setKeyName);
return members;
}
/**
* 从集合中删除指定元素
* @param setkeyName
* @param value
* @return
*/
public Long removeFromSet(String setkeyName, String value){
Long removeNum = redisTemplate.opsForSet().remove(setkeyName, value);
return removeNum;
}
/**
* //判断集合中是否存在某元素
* @param setkeyName
* @param value
* @return
*/
public boolean isHaveFromSet(String setkeyName, String value){
return redisTemplate.opsForSet().isMember(setkeyName, value);
}
/**
* redis List数据结构 : 将一个或多个值 value 插入到列表 key 的表头
*
* @param key the key
* @param value the value
* @return the long
*/
public Long leftPush(String key, Object value) {
return opsForList().leftPush(key, value);
}
/**
* redis List数据结构 : 移除并返回列表 key 的头元素
*
* @param key the key
* @return the string
*/
public Object leftPop(String key) {
return opsForList().leftPop(key);
}
/**
* redis List数据结构 :将一个或多个值 value 插入到列表 key 的表尾(最右边)。
*
* @param key the key
* @param value the value
* @return the long
*/
public Long in(String key, Object value) {
return opsForList().rightPush(key, value);
}
/**
* redis List数据结构 : 移除并返回列表 key 的末尾元素
*
* @param key the key
* @return the string
*/
public Object rightPop(String key) {
return opsForList().rightPop(key);
}
/**
* redis List数据结构 : 返回列表 key 的长度 ; 如果 key 不存在,则 key 被解释为一个空列表,返回 0 ; 如果 key 不是列表类型,返回一个错误。
*
* @param key the key
* @return the long
*/
public Long length(String key) {
return opsForList().size(key);
}
/**
* redis List数据结构 : 根据参数 i 的值,移除列表中与参数 value 相等的元素
*
* @param key the key
* @param i the
* @param value the value
*/
public void remove(String key, long i, Object value) {
opsForList().remove(key, i, value);
}
/**
* redis List数据结构 : 将列表 key 下标为 index 的元素的值设置为 value
*
* @param key the key
* @param index the index
* @param value the value
*/
public void set(String key, long index, Object value) {
opsForList().set(key, index, value);
}
/**
* redis List数据结构 : 返回列表 key 中指定区间内的元素,区间以偏移量 start 和 end 指定。
*
* @param key the key
* @param start the start
* @param end the end
* @return the list
*/
public List<Object> getList(String key, int start, int end) {
return opsForList().range(key, start, end);
}
/**
* redis List数据结构 : 批量存储
*
* @param key the key
* @param list the list
* @return the long
*/
public Long leftPushAll(String key, List<String> list) {
return opsForList().leftPushAll(key, list);
}
/***
* redis List数据结构:批量存储列表信息
* @param key
* @param list
* @return
*/
public Long rightPushAllObj(String key, List<Object> list) {
return opsForList().rightPushAll(key,list);
}
/**
* redis List数据结构 : 将值 value 插入到列表 key 当中,位于值 index 之前或之后,默认之后。
*
* @param key the key
* @param index the index
* @param value the value
*/
public void insert(String key, long index, Object value) {
opsForList().set(key, index, value);
}
/**
* 设置缓存
*
* @param key key
* @param value value 存储结果是string,不是16进制
* @param time time大于0,则设置过期时间,否则不设置过期时间
* @return
*/
public boolean set(String key, String value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
redisTemplate.opsForValue().set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 获取key对应的value value 为String
*
* @param key key
* @return
*/
public String getStrValue(String key) {
if(key == null){
return null;
}
Object value = redisTemplate.opsForValue().get(key);
if(null != value){
return (String)value;
}else{
return null;
}
}
/***
* 设置key 的过期时间
* @param key
* @param time
* @param unit
*/
public void expireAt(String key,Long time,TimeUnit unit){
redisTemplate.expire(key,time,unit);
}
/**
* 设置位图
* @param key key
* @param offSet 偏移量
* @param flag true为1 false为0
*/
public void setBit(String key, Long offSet, boolean flag) {
redisTemplate.opsForValue().setBit(key, offSet, flag);
}
/**
* 获取位图
* @param key key
* @param offSet 偏移量
*/
public boolean getBit(String key, Long offSet) {
return redisTemplate.opsForValue().getBit(key, offSet);
}
/**
* 获取指定key的value为1的数量
* @param key
* @return
*/
public Long bitCount(String key) {
return redisTemplate.execute((RedisCallback<Long>) con -> con.bitCount(key.getBytes()));
}
/**
* 获取key的过期时间
* @param key
* @return
*/
public Long getExpire(String key) {
return redisTemplate.opsForValue().getOperations().getExpire(key);
}
/**
*
* @param completeKey
* @param bitmapKey
* @param value
* @return
*/
public Long setLoginByLua(String completeKey, String bitmapKey, String value, Integer loginCount) {
DefaultRedisScript redisScript = new DefaultRedisScript();
redisScript.setLocation(new ClassPathResource("redisSetLogin.lua"));
redisScript.setResultType(String.class);
//logincount转为string是因为StringRedisSerializer
String result = redisTemplate.execute(redisScript, new StringRedisSerializer(), new StringRedisSerializer(),
Arrays.asList(completeKey, bitmapKey), value, String.valueOf(loginCount));
Long count = bitCount(bitmapKey);
log.info("登录统计,KEY:{},人数:{}",bitmapKey,count);
return Long.valueOf(result);
}
/**
* 设置位图偏移量的value为0
* @param bitmapKey 位图key
* @param offset 偏移量
*/
public void setBitmap(String bitmapKey, String offset) {
DefaultRedisScript redisScript = new DefaultRedisScript();
redisScript.setLocation(new ClassPathResource("redisSetBit.lua"));
redisScript.setResultType(Long.class);
redisTemplate.execute(redisScript, new StringRedisSerializer(), new StringRedisSerializer(),
Arrays.asList(bitmapKey), offset);
}
}
4.3 自定义redis配置类
package lilock.cn.common.redis.config;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import lilock.cn.common.redis.properties.RedisDataSourceProperties;
import lilock.cn.common.redis.template.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.*;
import redis.clients.jedis.JedisPoolConfig;
import java.lang.reflect.Method;
import java.time.Duration;
/**
* redis 配置流程
* 1.通过yaml 或者properties配置文件获取对应的redis的相关参数
* 2.利用redis相关参数配置连接池
* 2.利用连接池配置链接工厂
* 3.利用链接工厂设置Redistemplate,设置key 和 value的序列化方式
* 4.封装redis工具,利用redistemplate跟redis交互
*/
@EnableConfigurationProperties
@EnableCaching //开启SpringCache 管理
@Slf4j
public class RedisConfig extends CachingConfigurerSupport {
@Autowired
private RedisDataSourceProperties redisDataSourceProperties;
/**
* 配置key的生成策略
* @return
*/
@Bean
public KeyGenerator keyGenerator(){
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(":");
sb.append(method.getName());
sb.append(":");
for (Object param : params) {
sb.append(param.toString());
}
return sb.toString();
}
};
}
/**
* 配置jedis连接池
* @return
*/
@Bean("jedisPool")
@Primary
public JedisPoolConfig jedisPoolConfig(){
//创建链接池
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
//获取最大空闲数
jedisPoolConfig.setMaxIdle(redisDataSourceProperties.getMaxIdle());
//连接池最大连接数量
jedisPoolConfig.setMaxTotal(redisDataSourceProperties.getMaxTotal());
//连接池最大等待时间
//jedisPoolConfig.setMaxWait(Duration.ofSeconds(redisDataSourceProperties.getMaxTotal()));
//逐出链接最小空闲时间
//jedisPoolConfig.setMinEvictableIdleTime(Duration.ofSeconds(redisDataSourceProperties.getMinEvictableIdleTimeMillis()));
//每次逐出最大数量
jedisPoolConfig.setNumTestsPerEvictionRun(redisDataSourceProperties.getNumTestsPerEvictionRun());
//逐出扫描时间间隔
//jedisPoolConfig.setTimeBetweenEvictionRuns(Duration.ofSeconds(redisDataSourceProperties.getTimeBetweenEvictionRunsMillis()));
//是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
jedisPoolConfig.setTestOnBorrow(redisDataSourceProperties.isTestOnBorrow());
//空闲检查失效性
jedisPoolConfig.setTestWhileIdle(redisDataSourceProperties.isTestWhileIdle());
log.info("项目启动加载Redis连接池信息:{}", JSONObject.toJSONString(redisDataSourceProperties));
return jedisPoolConfig;
}
/**
* 初始化RedisTemplate的配置,配置序列化and工厂
* @param jedisPoolConfig
* @return
*/
@Bean("jedisConnectionFactory")
@Primary
public JedisConnectionFactory jedisConnectionFactory(JedisPoolConfig jedisPoolConfig){
//配置redis链接信息
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(redisDataSourceProperties.getHost(),redisDataSourceProperties.getPort());
//设置密码
redisStandaloneConfiguration.setPassword(RedisPassword.of(redisDataSourceProperties.getPassword()));
//设置默认database
redisStandaloneConfiguration.setDatabase(redisDataSourceProperties.getDatabase());
JedisClientConfiguration.JedisClientConfigurationBuilder jedisClientConfigurationBuilder = JedisClientConfiguration.builder();
//设置超时时间
jedisClientConfigurationBuilder.connectTimeout(Duration.ofSeconds(redisDataSourceProperties.getTimeout()));
//设置链接池
jedisClientConfigurationBuilder.usePooling().poolConfig(jedisPoolConfig);
//创建工厂对象
JedisConnectionFactory factory = new JedisConnectionFactory(redisStandaloneConfiguration,jedisClientConfigurationBuilder.build());
return factory;
}
/**
* 配置redis序列化方式
* @param factory
* @return
*/
@Bean("redisTemplate")
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
//设置链接工厂
redisTemplate.setConnectionFactory(factory);
RedisSerializer keySerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会抛出异常
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// key采用String的序列化方式
redisTemplate.setKeySerializer(keySerializer);
// hashkey采用String的序列化方式
redisTemplate.setHashKeySerializer(keySerializer);
// value序列化方式采用jackson
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// value序列化方式采用jackson
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
@Primary //@Primary: 当出现相同名字的bean是,优先使用使用了 @Primary 注解的bean
public RedisService redisUtil(@Qualifier("redisTemplate") RedisTemplate<String,Object> redisTemplate){
RedisService redisUtil = new RedisService(redisTemplate);
return redisUtil;
}
/**
* 设置SpringCacheManager ,通过在类名启用@EnableCaching 来开启springcache
* 配置完此bean之后,可以通过@Cacheable/@CachePut/@CacheEvict 来进行操作缓存
* @Cacheable : 根据key从缓存中取值,存在则获取后直接返回,不执行业务方法;不存在则执行业务方法,讲业务方法返回的数据存入缓存
* @CachePut : 根据key从缓存中取值,无论数据是否存在,业务方法都会执行,并且业务方法返回的数据存入内存
* @CacheEvict : 执行业务方法之后,删除缓存中的数据
* @param factory
* @return
*/
@Bean("cacheManager")
@Primary
public CacheManager cacheManager(RedisConnectionFactory factory){
RedisCacheConfiguration redisAutoConfiguration = RedisCacheConfiguration
.defaultCacheConfig() //获取redisCache实例
.entryTtl(Duration.ofHours(1L)) //设置缓存过期时间
.computePrefixWith(cacheName -> "cache".concat(":").concat(cacheName).concat(":")) //给key值拼接前缀 cache: 类似于传入 key 最后存的时候 是 cache:key
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) //设置key序列化方式
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())) //设置value序列化方式
;
RedisCacheManager redisCacheManager = RedisCacheManager
.builder(factory) //获取redisCacheManager
.cacheDefaults(redisAutoConfiguration)
.build();
return redisCacheManager;
}
}
4.4 springboot装配文件 spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ lilock.cn.common.redis.properties.RedisDataSourceProperties,\ lilock.cn.common.redis.config.RedisConfig
到目前位置,redis 自动装配已经完成,接下来就是测试了
5.新建lilock-server-user模块
引入 lilock-common-spring-redis-starter
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>lilock-modules</artifactId>
<groupId>lilock.cn</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath/>
</parent>
<modelVersion>4.0.0</modelVersion>
<version>1.0-SNAPSHOT</version>
<artifactId>lilock-service-user</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>lilock.cn</groupId>
<artifactId>lilock-common-spring-redis-starter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
5.1 application.yml配置redis参数
lilock: redis: host: 127.0.0.1 port: 6379 max-idle: 10 #设置最大空闲连接数,默认为8 max-wait-millis: -1 #获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间, 默认-1 max-total: 20 #设置最大连接数,默认18个 min-evictable-idle-time-millis: 18000 #设置连接最小的逐出间隔时间,默认1800000毫秒 num-tests-per-eviction-run: 5 #每次逐出检查时,逐出连接的个数 默认为3 time-between-eviction-runs-millis: -1 #设置连接对象有效性扫描间隔,设置为-1,则不运行逐出线程 timeout: 10 #链接超时时间默认2秒 test-on-borrow: true # 在连接对象返回时,是否测试对象的有效性,默认false test-while-idle: true # 在连接池空闲时是否测试连接对象的有效性,默认false database: 0 password: server: port: 8988 spring: profiles: active: dev
5.2 新建测试类
package lilock.cn.user.controller;
import io.swagger.annotations.Api;
import lilock.cn.common.redis.template.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(path = "/user")
@Api(value = "系统用户",tags = {"系统用户"})
@Slf4j
public class UserController {
@Autowired
private RedisService redisService;
@GetMapping("/test")
public String getUser(){
log.info("{}",redisService);
redisService.setExpire("zs","张三",1000);
String value = redisService.getStrValue("zs");
return value;
}
}
5.3 测试结果
搞定!