RedisTemplate 封装的工具类
package hk.com.easyview.common.helper;import com.alibaba.fastjson.JSONObject;import com.fasterxml.jackson.databind.ObjectMapper;import hk.com.easyview.common.util.ArrayUtils;import hk.com.easyview.common.util.FastJsonUtil;import hk.com.easyview.common.util.MapUtils;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang3.StringUtils;import org.apache.poi.ss.formula.functions.T;import org.springframework.data.redis.core.*;import org.springframework.data.redis.core.script.RedisScript;import org.apache.commons.collections4.CollectionUtils;import java.nio.charset.StandardCharsets;import java.util.*;import java.util.concurrent.TimeUnit;import java.util.stream.Collectors;@Slf4jpublic class RedisHelper {private final ObjectMapper objectMapper = new ObjectMapper();private RedisTemplate redisTemplate;public void setRedisTemplate(RedisTemplate redisTemplate) {this.redisTemplate = redisTemplate;}public <T> T convertToBean(Object cacheData, Class <T> clazz) {return objectMapper.convertValue(cacheData, clazz);}// =============================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 (ArrayUtils.isEmpty(key)) {return;}if (key.length == 1) {redisTemplate.delete(key[0]);} else {redisTemplate.delete(Arrays.asList(key));}}// ============================String=============================/*** 普通缓存获取** @param key 键* @return 值*/public Object get(String key) {if (StringUtils.isEmpty(key)) {return null;}return redisTemplate.opsForValue().get(key);}public <T> T get(String key, Class <T> clazz) {Object obj = get(key);if (obj == null) {return null;}return convertToBean(obj, clazz);}/*** 普通缓存放入** @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);}/*** 位图数据*/public long bitcount(String key, int start, int end) {return (long) redisTemplate.execute((RedisCallback<Long>) con -> con.bitCount(key.getBytes(), start, end));}/*** 位图数据*/public long bitcount(String key) {return (long) redisTemplate.execute((RedisCallback<Long>) con -> con.bitCount(key.getBytes()));}/*** 位图设置*/public Boolean bitset(String key, long offset, boolean value) {return redisTemplate.opsForValue().setBit(key, offset, value);}public Boolean bitget(String key, long offset) {return redisTemplate.opsForValue().getBit(key, offset);}/*** 获取所有的符合的keys* @apiNote 仅允许按次使用,不允许频繁调用。可能会造成业务阻塞* @param pattern*/public Set<String> keys(String pattern) {return redisTemplate.keys(pattern);}// ================================Map=================================/*** HashGet** @param key 键 不能为null* @param item 项 不能为null* @return 值*/public Object hget(String key, String item) {return redisTemplate.opsForHash().get(key, item);}/*** HashGet** @param key 键 不能为null* @param item 项 不能为null* @param tClass 项 数据类型* @return 值*/public <T> T hget(String key, String item,Class<T> tClass) {Object value = redisTemplate.opsForHash().get(key, item);return convert(value,tClass);}private <T> T convert(Object value,Class<T> tClass){if (Objects.isNull(value)) {return null;}T t;if (value instanceof String) {t = FastJsonUtil.toBean((String) value, tClass);} else if (value instanceof JSONObject) {t = FastJsonUtil.toBean((JSONObject) value, tClass);} else {t = FastJsonUtil.toBean(FastJsonUtil.toJSONNoFeatures(value), tClass);}return t;}/*** 获取hashKey对应的所有键值** @param key 键* @return 对应的多个键值*/public Map<String, Object> hmget(String key) {return redisTemplate.<String, Object>opsForHash().entries(key);}/*** 获取hashKey对应的所有键值** @param key 键* @return 对应的多个键值*/public <T> Map<String, T> hmget(String key,Class<T> tClass) {Map entries = redisTemplate.<String, Object>opsForHash().entries(key);HashMap<String, T> resultMap = new HashMap<>(entries.size());if (MapUtils.isEmpty(entries)) {return resultMap;}entries.forEach((mapKey,value)->{if (Objects.isNull(value)) {return;}T convert = convert(value, tClass);resultMap.put(mapKey.toString(),convert);});return resultMap;}public List<Object> hmget(String key, Collection<String> item) {List list = redisTemplate.<String, T>opsForHash().multiGet(key, item);if (CollectionUtils.isNotEmpty(list)) {list.removeAll(Collections.singletonList(null));}return list;}public <K, T> List<T> hmget(String key, Collection<K> items, Class<T> tClass) {if (CollectionUtils.isEmpty(items)) {return Collections.emptyList();}List<String> itemKeys = items.stream().map(String::valueOf).collect(Collectors.toList());List list = redisTemplate.<String, T>opsForHash().multiGet(key, itemKeys);if (CollectionUtils.isNotEmpty(list)) {list.removeAll(Collections.singletonList(null));}List<T> resultList = ArrayUtils.safeConvertListByFunction(list, obj ->convert(obj,tClass));return resultList;}/*** HashSet** @param key 键* @param map 对应多个键值* @return true 成功 false 失败*/public <T> boolean hmset(String key, Map<String, T> map) {try {redisTemplate.<String, T>opsForHash().putAll(key, map);return true;} catch (Exception e) {e.printStackTrace();return false;}}public <T> boolean hmSet(String key, Map<String, T> map, long time) {try {redisTemplate.<String, T>opsForHash().putAll(key, map);if (time > 0) {expire(key, time);}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.<String, Object>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);}public void hDel(String key,Collection item) {if(CollectionUtils.isEmpty(item)){return;}redisTemplate.opsForHash().delete(key, item.toArray());}/*** 判断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);}/*** hash大小** @param key 键* @return hash数目*/public Long hsize(String key) {return redisTemplate.opsForHash().size(key);}/*** 获取hash所有的Key* @param key 键*/public Set hKeys(String key) {return redisTemplate.opsForHash().keys(key);}/*** 获取hash所有的Value* @param key*/public List<String> hValues(String key) {return redisTemplate.opsForHash().values(key);}// ============================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 sHasValue(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;}}// ===============================zset=================================/*** 返回有序集中元素个数** @param key* @return*/public Long zCard(String key) {try {return redisTemplate.opsForZSet().size(key);} catch (Exception e) {e.printStackTrace();return null;}}/*** 返回有序集中,成员的分数值** @param key* @param value* @return*/public Double zScore(String key, Object value) {try {return redisTemplate.opsForZSet().score(key, value);} catch (Exception e) {e.printStackTrace();return null;}}/*** 单个数据放入zset缓存** @param key* @param value* @param score* @return*/public boolean zAdd(String key, Object value, double score) {try {return redisTemplate.opsForZSet().add(key, value, score);} catch (Exception e) {e.printStackTrace();return false;}}/*** 多个数据放入zset缓存** @param key* @param value* @return*/public long zAdd(String key, Set<ZSetOperations.TypedTuple <Object>> value) {try {return redisTemplate.opsForZSet().add(key, value);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 计算指定区间分数的成员数** @param key* @param start* @param end* @return*/public long zCount(String key, double start, double end) {try {return redisTemplate.opsForZSet().count(key, start, end);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 通过分数返回有序集合指定区间内的成员** @param key* @param start* @param end* @return*/public Set <Object> zRangeByScore(String key, double start, double end) {try {return redisTemplate.opsForZSet().rangeByScore(key, start, end);} catch (Exception e) {e.printStackTrace();return null;}}public Set<ZSetOperations.TypedTuple<Object>> zRangeWithScore(String key, long start, long end) {try {return redisTemplate.opsForZSet().rangeWithScores(key, start, end);} catch (Exception e) {e.printStackTrace();return null;}}/*** 通过索引区间返回有序集合成指定区间内的成员** @param key* @param start* @param end* @return*/public Set <Object> zRange(String key, long start, long end) {try {return redisTemplate.opsForZSet().range(key, start, end);} catch (Exception e) {e.printStackTrace();return null;}}public Set <Object> zRevRange(String key, long start, long end) {try {return redisTemplate.opsForZSet().reverseRange(key, start, end);} catch (Exception e) {e.printStackTrace();return null;}}public Set<ZSetOperations.TypedTuple <Object>> zRevRangeWithScore(String key, long start, long end) {try {return redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);} catch (Exception e) {e.printStackTrace();return null;}}public Set <Object> zRevRangeByScore(String key, double start, double end) {try {return redisTemplate.opsForZSet().reverseRangeByScore(key, start, end);} catch (Exception e) {e.printStackTrace();return null;}}public Set<ZSetOperations.TypedTuple <Object>> zRevRangeByScoreWithScore(String key, double start, double end) {try {return redisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, start, end);} catch (Exception e) {e.printStackTrace();return null;}}/*** 返回有序集合中指定成员的索引** @param key* @param value* @return*/public Long zRank(String key, Object value) {try {return redisTemplate.opsForZSet().rank(key, value);} catch (Exception e) {e.printStackTrace();return null;}}/*** 移除有序集合中成员** @param key* @param value* @return*/public long zRemove(String key, Object... value) {try {return redisTemplate.opsForZSet().remove(key, value);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 移除有序集合中给定的字典区间的所有成员** @param key* @param start* @param end* @return*/public long zRemoveRange(String key, long start, long end) {try {return redisTemplate.opsForZSet().removeRange(key, start, end);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 移除有序集合中给定的分数区间的所有成员** @param key* @param start* @param end* @return*/public long zRemoveRangeByScore(String key, double start, double end) {try {return redisTemplate.opsForZSet().removeRangeByScore(key, start, end);} 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;}}public void lLeftPush(String key, Object value) {redisTemplate.opsForList().leftPush(key, value);}/*** 将list放入缓存** @param key 键* @param value 值* @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 值* @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;}}/*** 移除列表的最后一个元素,返回值为移除的元素** @param key 键* @return*/public Object lRightPop(String key) {try {return redisTemplate.opsForList().rightPop(key);} catch (Exception e) {e.printStackTrace();return null;}}/*** 移除N个值为value** @param key 键* @param count 移除多少个* @param value 值* @return 移除的个数*/public long lRemove(String key, long count, Object value) {try {return redisTemplate.opsForList().remove(key, count, value);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 发布消息** @param topic* @param message*/public void convertAndSend(String topic, Object message) {redisTemplate.convertAndSend(topic, message);}public <K, V> Boolean setIfAbsent(K key, V value, long timeout, TimeUnit unit) {try {return redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit);} catch (Exception e) {e.printStackTrace();return false;}}public <K, V> Boolean setIfAbsent(K key, V value) {try {return redisTemplate.opsForValue().setIfAbsent(key, value);} catch (Exception e) {e.printStackTrace();return false;}}public <T, K> Object execute(RedisScript <T> script, List<K> keys, Object... args) {return redisTemplate.execute(script, keys, args);}/*** 根据前缀获取所有符合条件的键值对** @param prefix*/public Map<String, Object> getAllByPrefix(String prefix) {Map<String, Object> resultMap = new HashMap<>();try {// 使用scan方法,不用keys方法ScanOptions scanOptions = ScanOptions.scanOptions().match(prefix + "*").build();Cursor<byte[]> cursor = redisTemplate.getConnectionFactory().getConnection().scan(scanOptions);while (cursor.hasNext()) {byte[] keyBytes = cursor.next();String key = new String(keyBytes, StandardCharsets.UTF_8); // 转换byte[]为StringObject value = redisTemplate.opsForValue().get(key);resultMap.put(key, value);}} catch (Exception e) {e.printStackTrace();}return resultMap;}}其中有个方法,用于加锁
public Boolean setIfAbsent(K key, V value, long timeout, TimeUnit unit) {
try {
return redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}Boolean setIfAbsent(K key, V value, long timeout, TimeUnit unit);这是RedisTemplate提供的一个原子操作方法。
当且仅当redis中key不存在时,设置该k-v,并且指定过期时间。
返回值:
true:键不存在,并且成功设置
false:键已存在,未执行任何操作。
底层调用的是redis的set命令,结合nx(not exist)
使用场景:
1,分布式锁(防并发重复创建)// 尝试获取锁,锁有效期 30 秒boolean isLocked = redisTemplate.opsForValue().setIfAbsent("user:123:lock", "locked", 30, TimeUnit.SECONDS);if (isLocked) {// 执行业务逻辑} else {// 锁已被占用}//创建员工@Transactional(rollbackFor = Exception.class)@Overridepublic void createNewUser(UserInfoParam userInfoParam) throws Exception {String lockKey = RedisContants.USER_CREATE_LOCK + userInfoParam.getUserInfo().getUserName();if (!redisHelper.setIfAbsent(lockKey, 1, RedisContants.WIRTE_LOCK_TIME_OUT, TimeUnit.SECONDS)) {throw new CustomException(ResultCode.SUBMIT_REPEATED);}try {//创建用户的逻辑} finally {redisHelper.del(lockKey);}}//创建机构@Override@Transactional(rollbackFor = Exception.class)public void addNewOrganization(OrgParam orgParam) throws CustomException {String lockKey = RedisContants.ORG_INSERT_LOCK + orgParam.getName();boolean access = redisHelper.setIfAbsent(lockKey, 1, 3, TimeUnit.SECONDS);if (!access) {throw new CustomException(ResultCode.CREATE_REPEATED);}try {//创建机构逻辑} finally {redisHelper.del(lockKey);}}