Background: Due to the self-developed framework, many companies package their own Redis, so they need to package Redis separately and use it as a public module for business systems. I won’t introduce the principle of automatic assembly. I searched a lot on the Internet, and all of them are good. There are not many nonsense, let’s go to the code
Table of contents
1. springboot version number selection
2. Project root pom configuration lilock-framework
3. Common module pom configuration lilock-commons
4. Redis module pom configuration lilock-redis-spring-boot-starter
4.1 Custom redis parameter configuration class
4.2 Customize redis tool class RedisService
4.3 Custom redis configuration class
4.4 springboot assembly file spring.factories
5. Create a new lilock-server-user module
5.1 application.yml configuration redis parameters
Project structure:
lilock-framework lilock-commons lilock-common-spring-boot-starter lilock-redis-spring-boot-starter lilock-modules lilock-service-user
1. springboot version number selection
The version number I selected is 2.3.12.RELEASE, which can be selected according to the version number of springboot in my company
<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. Project root pom configuration 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. Common module pom configuration 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 module pom configuration 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>
Configure all the configurations of the Redis automatic assembly module above, and start to enter the topic
4.1 Custom redis parameter configuration class
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 Customize redis tool class 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 Custom redis configuration class
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 assembly file spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ lilock.cn.common.redis.properties.RedisDataSourceProperties,\ lilock.cn.common.redis.config.RedisConfig
So far, redis automatic assembly has been completed, and the next step is to test
5. Create a new lilock-server-user module
Introduce 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 configuration redis parameters
lilock: redis: host: 127.0.0.1 port: 6379 max-idle: 10 #Set the maximum number of idle connections, the default is 8 max-wait-millis: -1 #The maximum number of milliseconds to wait for a connection (if set to block BlockWhenExhausted), throw an exception if it times out, less than zero: block for an uncertain time, default -1 max-total: 20 #Set the maximum number of connections, default 18 min-evictable-idle-time-millis: 18000 #Set the minimum connection The eviction interval time, the default is 1800000 milliseconds num-tests-per-eviction-run: 5 #When each eviction check, the number of eviction connections defaults to 3 time-between-eviction-runs-millis: -1 # Set the validity scanning interval of the connection object, if it is set to -1, the eviction thread will not run timeout: 10 #The connection timeout defaults to 2 seconds test-on-borrow: true # When the connection object returns, whether to test the validity of the object, Default false test-while-idle: true # Whether to test the validity of the connection object when the connection pool is idle, default false database: 0 password: server: port: 8988 spring: profiles: active: dev
5.2 Create a new test class
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 Test results
Done!