));
/使用RedisCacheConfiguration创建RedisCacheManager/
RedisCacheManager manager = RedisCacheManager.builder(factory)
.cacheDefaults(cacheConfiguration)
.build();
return manager;
}
@Bean
CacheManager yzmManager(RedisConnectionFactory factory) {
RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.computePrefixWith(cacheName -> cacheName + “:-yzm-:”)
/设置缓存过期时间/
.entryTtl(Duration.ofSeconds(60))
/禁用缓存空值,不缓存null校验/
.disableCachingNullValues()
/设置CacheManager的值序列化方式为json序列化,可使用加入@Class属性/
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(
new GenericJackson2JsonRedisSerializer()
));
/使用RedisCacheConfiguration创建RedisCacheManager/
RedisCacheManager manager = RedisCacheManager.builder(factory)
.cacheDefaults(cacheConfiguration)
.build();
return manager;
}
@Bean
@Primary
// redis操作对象
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(factory);
RedisSerializer stringSerializer = new StringRedisSerializer();
/* key序列化 */
redisTemplate.setKeySerializer(stringSerializer);
/* value序列化 */
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
/* Hash key序列化 */
redisTemplate.setHashKeySerializer(stringSerializer);
/* Hash value序列化 */
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
@Primary
@Override
// 主键生成器
public KeyGenerator keyGenerator() {
return (Object target, Method method, Object… params) -> {
final int NO_PARAM_KEY = 0;
final int NULL_PARAM_KEY = 53;
StringBuilder key = new StringBuilder();
/* Class.Method: */
key.append(target.getClass().getSimpleName())
.append(“.”)
.append(method.getName())
.append(“:”);
if (params.length == 0) {
return key.append(NO_PARAM_KEY).toString();
}
int count = 0;
for (Object param : params) {
/* 参数之间用,进行分隔 */
if (0 != count) {
key.append(‘,’);
}
if (param == null) {
key.append(NULL_PARAM_KEY);
} else if (ClassUtils.isPrimitiveArray(param.getClass())) {
int length = Array.getLength(param);
for (int i = 0; i < length; i++) {
key.append(Array.get(param, i));
key.append(‘,’);
}
} else if (ClassUtils.isPrimitiveOrWrapper(param.getClass()) || param instanceof String) {
key.append(param);
} else {
/JavaBean一定要重写hashCode和equals/
key.append(param.hashCode());
}
count++;
}
return key.toString();
};
}
}
Ⅴ、导入util包
RedisUtil :
package com.lv.code.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.redis.RedisSystemException;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.connection.jedis.JedisConnection;
import org.springframework.data.redis.connection.lettuce.LettuceConnection;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.stereotype.Component;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
/**
-
Redis工具类
-
-
声明: 此工具只简单包装了redisTemplate的大部分常用的api,没有包装redisTemplate所有的api
-
如果对此工具类中的功能不太满意,或对StringRedisTemplate提供的api不太满意,
-
那么可自行实现相应的{@link StringRedisTemplate}类中的对应execute方法,以达
-
到自己想要的效果; 至于如何实现,则可参考源码或{@link LockOps}中的方法
-
-
注: 此工具类依赖spring-boot-starter-data-redis类库
-
注: 更多javadoc细节,可详见{@link RedisOperations}
-
-
统一说明一: 方法中的key、 value都不能为null
-
统一说明二: 不能跨数据类型进行操作,否者会操作失败/操作报错
-
如: 向一个String类型的做Hash操作,会失败/报错…等等
*/
@Slf4j
@Component
@SuppressWarnings(“unused”)
public class RedisUtil implements ApplicationContextAware {
/**
- 使用StringRedisTemplate(,其是RedisTemplate的定制化升级)
*/
private static StringRedisTemplate redisTemplate;
private static final ObjectMapper mapper = new ObjectMapper();
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
RedisUtil.redisTemplate = applicationContext.getBean(StringRedisTemplate.class);
}
/**
- key相关操作
*/
public static class KeyOps {
/**
-
根据key,删除redis中的对应key-value
-
-
注: 若删除失败,则返回false
-
-
若redis中,不存在该key,那么返回的也是false
-
所以,不能因为返回了false,就认为redis中一定还存
-
在该key对应的key-value
-
@param key 要删除的key
-
@return 删除是否成功
*/
public static Boolean delete(String key) {
log.info(“delete(…) => key -> {}”, key);
// 返回值只可能为true/false,不可能为null
Boolean result = redisTemplate.delete(key);
log.info(“delete(…) => result -> {}”, result);
if (result == null) {
throw new RedisOpsResultIsNullException();
}
return result;
}
/**
-
根据keys,批量删除key-value
-
-
注: 若redis中,不存在对应的key,那么计数不会加1,即:
-
redis中存在的key-value里,有名为a1、a2的key,
-
删除时,传的集合是a1、a2、a3,那么返回结果为2
-
@param keys 要删除的key集合
-
@return 删除了的key-value个数
*/
public static long delete(Collection keys) {
log.info(“delete(…) => keys -> {}”, keys);
Long count = redisTemplate.delete(keys);
log.info(“delete(…) => count -> {}”, count);
if (count == null) {
throw new RedisOpsResultIsNullException();
}
return count;
}
/**
-
将key对应的value值进行序列化,并返回序列化后的value值
-
-
注: 若不存在对应的key,则返回null
-
注: dump时,并不会删除redis中的对应key-value
-
注: dump功能与restore相反
-
@param key 要序列化的value的key
-
@return 序列化后的value值
*/
public static byte[] dump(String key) {
log.info(“dump(…) =>key -> {}”, key);
byte[] result = redisTemplate.dump(key);
log.info(“dump(…) => result -> {}”, result);
return result;
}
/**
-
将给定的value值,反序列化到redis中,形成新的key-value
-
@param key value对应的key
-
@param value 要反序列的value值
-
注: 这个值可以由{@link this#dump(String)}获得 -
@param timeToLive 反序列化后的key-value的存活时长
-
@param unit timeToLive的单位
-
@throws RedisSystemException 如果redis中已存在同样的key时,抛出此异常
*/
public static void restore(String key, byte[] value, long timeToLive, TimeUnit unit) {
restore(key, value, timeToLive, unit, false);
}
/**
-
将给定的value值,反序列化到redis中,形成新的key-value
-
@param key value对应的key
-
@param value 要反序列的value值
-
注: 这个值可以由{@link this#dump(String)}获得 -
@param timeout 反序列化后的key-value的存活时长
-
@param unit timeout的单位
-
@param replace 若redis中已经存在了相同的key,是否替代原来的key-value
-
@throws RedisSystemException 如果redis中已存在同样的key,且replace为false时,抛出此异常
*/
public static void restore(String key, byte[] value, long timeout, TimeUnit unit, boolean replace) {
log.info(“restore(…) => key -> {},value -> {},timeout -> {},unit -> {},replace -> {}”,
key, value, timeout, unit, replace);
redisTemplate.restore(key, value, timeout, unit, replace);
}
/**
-
redis中是否存在,指定key的key-value
-
@param key 指定的key
-
@return 是否存在对应的key-value
*/
public static boolean hasKey(String key) {
log.info(“hasKey(…) => key -> {}”, key);
Boolean result = redisTemplate.hasKey(key);
log.info(“hasKey(…) => result -> {}”, result);
if (result == null) {
throw new RedisOpsResultIsNullException();
}
return result;
}
/**
-
给指定的key对应的key-value设置: 多久过时
-
-
注:过时后,redis会自动删除对应的key-value
-
注:若key不存在,那么也会返回false
-
@param key 指定的key
-
@param timeout 过时时间
-
@param unit timeout的单位
-
@return 操作是否成功
*/
public static boolean expire(String key, long timeout, TimeUnit unit) {
log.info(“expire(…) => key -> {},timeout -> {},unit -> {}”, key, timeout, unit);
Boolean result = redisTemplate.expire(key, timeout, unit);
log.info(“expire(…) => result is -> {}”, result);
if (result == null) {
throw new RedisOpsResultIsNullException();
}
return result;
}
/**
-
给指定的key对应的key-value设置: 什么时候过时
-
-
注:过时后,redis会自动删除对应的key-value
-
注:若key不存在,那么也会返回false
-
@param key 指定的key
-
@param date 啥时候过时
-
@return 操作是否成功
*/
public static boolean expireAt(String key, Date date) {
log.info(“expireAt(…) => key -> {},date -> {}”, key, date);
Boolean result = redisTemplate.expireAt(key, date);
log.info(“expireAt(…) => result is -> {}”, result);
if (result == null) {
throw new RedisOpsResultIsNullException();
}
return result;
}
/**
-
找到所有匹配pattern的key,并返回该key的结合.
-
-
提示:若redis中键值对较多,此方法耗时相对较长,慎用!慎用!慎用!
-
@param pattern 匹配模板
-
注: 常用的通配符有: -
? 有且只有一个; -
* >=0个; -
@return 匹配pattern的key的集合 可能为null
*/
public static Set keys(String pattern) {
log.info(“keys(…) => pattern -> {}”, pattern);
Set keys = redisTemplate.keys(pattern);
log.info(“keys(…) => keys -> {}”, keys);
return keys;
}
/**
-
将当前数据库中的key对应的key-value,移动到对应位置的数据库中
-
-
注:单机版的redis,默认将存储分为16个db,index为0 到 15
-
注:同一个db下,key唯一; 但是在不同db中,key可以相同
-
注:若目标db下,已存在相同的key,那么move会失败,返回false
-
@param key 定位要移动的key-value的key
-
@param dbIndex 要移动到哪个db
-
@return 移动是否成功
-
注: 若目标db下,已存在相同的key,那么move会失败,返回false
*/
public static boolean move(String key, int dbIndex) {
log.info(“move(…) => key -> {},dbIndex -> {}”, key, dbIndex);
Boolean result = redisTemplate.move(key, dbIndex);
log.info(“move(…) =>result -> {}”, result);
if (result == null) {
throw new RedisOpsResultIsNullException();
}
return result;
}
/**
-
移除key对应的key-value的过期时间,使该key-value一直存在
-
-
注: 若key对应的key-value,本身就是一直存在(无过期时间的),那么persist方法会返回false;
-
若没有key对应的key-value存在,本那么persist方法会返回false;
-
@param key 定位key-value的key
-
@return 操作是否成功
*/
public static boolean persist(String key) {
log.info(“persist(…) => key -> {}”, key);
Boolean result = redisTemplate.persist(key);
log.info(“persist(…) => result -> {}”, result);
if (result == null) {
throw new RedisOpsResultIsNullException();
}
return result;
}
/**
-
获取key对应的key-value的过期时间
-
-
注: 若key-value永不过期,那么返回的为-1
-
注: 若不存在key对应的key-value,那么返回的为-2
-
注:若存在零碎时间不足1 SECONDS,则(大体上)四舍五入到SECONDS级别
-
@param key 定位key-value的key
-
@return 过期时间(单位s)
*/
public static long getExpire(String key) {
return getExpire(key, TimeUnit.SECONDS);
}
/**
-
获取key对应的key-value的过期时间
-
-
注: 若key-value永不过期,那么返回的为-1
-
注: 若不存在key对应的key-value,那么返回的为-2
-
注:若存在零碎时间不足1 unit,则(大体上)四舍五入到unit别
-
@param key 定位key-value的key
-
@return 过期时间(单位unit)
*/
public static long getExpire(String key, TimeUnit unit) {
log.info(“getExpire(…) =>key -> {},unit is -> {}”, key, unit);
Long result = redisTemplate.getExpire(key, unit);
log.info(“getExpire(…) => result -> {}”, result);
if (result == null) {
throw new RedisOpsResultIsNullException();
}
return result;
}
/**
-
从redis的所有key中,随机获取一个key
-
-
注: 若redis中不存在任何key-value,那么这里返回null
-
@return 随机获取到的一个key
*/
public static String randomKey() {
String result = redisTemplate.randomKey();
log.info(“randomKey(…) => result is -> {}”, result);
return result;
}
/**
-
重命名对应的oldKey为新的newKey
-
-
注: 若oldKey不存在,则会抛出异常.
-
注: 若redis中已存在与newKey一样的key,
-
那么原key-value会被丢弃,
-
只留下新的key,以及原来的value
-
示例说明: 假设redis中已有 (keyAlpha,valueAlpha) 和 (keyBeta,valueBeat),
-
在使用rename(keyAlpha,keyBeta)替换后,redis中只会剩下(keyBeta,valueAlpha)
-
@param oldKey 旧的key
-
@param newKey 新的key
-
@throws RedisSystemException 若oldKey不存在时,抛出此异常
*/
public static void rename(String oldKey, String newKey) {
log.info(“rename(…) => oldKey -> {},newKey -> {}”, oldKey, newKey);
redisTemplate.rename(oldKey, newKey);
}
/**
-
当redis中不存在newKey时,重命名对应的oldKey为新的newKey
-
否者不进行重命名操作
-
-
注: 若oldKey不存在,则会抛出异常.
-
@param oldKey 旧的key
-
@param newKey 新的key
-
@throws RedisSystemException 若oldKey不存在时,抛出此异常
*/
public static boolean renameIfAbsent(String oldKey, String newKey) {
log.info(“renameIfAbsent(…) => oldKey -> {},newKey -> {}”, oldKey, newKey);
Boolean result = redisTemplate.renameIfAbsent(oldKey, newKey);
log.info(“renameIfAbsent(…) => result -> {}”, result);
if (result == null) {
throw new RedisOpsResultIsNullException();
}
return result;
}
/**
-
获取key对应的value的数据类型
-
-
注: 若redis中不存在该key对应的key-value,那么这里返回NONE
-
@param key 用于定位的key
-
@return key对应的value的数据类型
*/
public static DataType type(String key) {
log.info(“type(…) => key -> {}”, key);
DataType result = redisTemplate.type(key);
log.info(“type(…) => result -> {}”, result);
return result;
}
}
/**
- string相关操作
*/
public static class StringOps {
/**
-
设置key-value
-
-
注: 若已存在相同的key,那么原来的key-value会被丢弃
-
@param key key
-
@param value key对应的value
*/
public static void set(String key, String value) {
log.info(“set(…) => key -> {},value -> {}”, key, value);
redisTemplate.opsForValue().set(key, value);
}
/**
-
处理redis中key对应的value值,将第offset位的值,设置为1或0
-
-
说明: 在redis中,存储的字符串都是以二级制的进行存在的; 如存储的key-value里,值为abc,实际上,
-
在redis里面存储的是011000010110001001100011,前8为对应a,中间8为对应b,后面8位对应c
-
示例:这里如果setBit(key,6,true)的话,就是将索引位置6的那个数,设置值为1,值就变成
-
了011000110110001001100011
-
追注:offset即index,从0开始
-
-
注: 参数value为true,则设置为1;参数value为false,则设置为0
-
-
注: 若redis中不存在对应的key,那么会自动创建新的
-
注: offset可以超过value在二进制下的索引长度
-
@param key 定位value的key
-
@param offset 要改变的bit的索引
-
@param value 改为1或0,true - 改为1,false - 改为0
-
@return set是否成功
*/
public static boolean setBit(String key, long offset, boolean value) {
log.info(“setBit(…) => key -> {},offset -> {},value -> {}”, key, offset, value);
Boolean result = redisTemplate.opsForValue().setBit(key, offset, value);
log.info(“setBit(…) => result -> {}”, result);
if (result == null) {
throw new RedisOpsResultIsNullException();
}
return result;
}
/**
-
设置key-value
-
-
注: 若已存在相同的key,那么原来的key-value会被丢弃
-
@param key key
-
@param value key对应的value
-
@param timeout 过时时长
-
@param unit timeout的单位
*/
public static void setEx(String key, String value, long timeout, TimeUnit unit) {
log.info(“setEx(…) => key -> {},value -> {},timeout -> {},unit -> {}”,
key, value, timeout, unit);
redisTemplate.opsForValue().set(key, value, timeout, unit);
}
/**
-
若不存在key时,向redis中添加key-value,返回成功/失败
-
若存在,则不作任何操作,返回false
-
@param key key
-
@param value key对应的value
-
@return set是否成功
*/
public static boolean setIfAbsent(String key, String value) {
log.info(“setIfAbsent(…) => key -> {},value -> {}”, key, value);
Boolean result = redisTemplate.opsForValue().setIfAbsent(key, value);
log.info(“setIfAbsent(…) => result -> {}”, resul

最低0.47元/天 解锁文章
8504

被折叠的 条评论
为什么被折叠?



