package com.vci.web.redis; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.geo.Distance; import org.springframework.data.geo.Metrics; import org.springframework.data.geo.Point; import org.springframework.data.redis.core.*; import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.data.redis.core.script.RedisScript; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.*; import java.util.concurrent.TimeUnit; /** * spring redis 工具类 * @author dangsn **/ @SuppressWarnings(value = { "unchecked", "rawtypes" }) @Component @Slf4j public class RedisService { @Autowired(required = false) public RedisTemplate redisTemplate; /** * 缓存基本的对象,Integer、String、实体类等 * * @param key 缓存的键值 * @param value 缓存的值 */ public void setCacheObject(final String key, final T value) { redisTemplate.opsForValue().set(key, value); } /** * 缓存基本的对象,Integer、String、实体类等 * * @param key 缓存的键值 * @param value 缓存的值 * @param timeout 时间 * @param timeUnit 时间颗粒度 */ public void setCacheObject(final String key, final T value, final Long timeout, final TimeUnit timeUnit) { redisTemplate.opsForValue().set(key, value, timeout, timeUnit); } /** * 设置有效时间 * * @param key Redis键 * @param timeout 超时时间 * @return true=设置成功;false=设置失败 */ public boolean expire(final String key, final long timeout) { return expire(key, timeout, TimeUnit.SECONDS); } /** * 设置有效时间 * * @param key Redis键 * @param timeout 超时时间 * @param unit 时间单位 * @return true=设置成功;false=设置失败 */ public boolean expire(final String key, final long timeout, final TimeUnit unit) { return redisTemplate.expire(key, timeout, unit); } /** * 获取有效时间 * * @param key Redis键 * @return 有效时间 */ public long getExpire(final String key) { return redisTemplate.getExpire(key); } /** * 判断 key是否存在 * * @param key 键 * @return true 存在 false不存在 */ public Boolean hasKey(String key) { return redisTemplate.hasKey(key); } /** * 获得缓存的基本对象。 * * @param key 缓存键值 * @return 缓存键值对应的数据 */ public T getCacheObject(final String key) { ValueOperations operation = redisTemplate.opsForValue(); return operation.get(key); } /** * 删除单个对象 * * @param key 可以 * @return 删除是否成功 */ public boolean deleteObject(final String key) { return redisTemplate.delete(key); } /** * 删除集合对象 * * @param collection 多个对象 * @return 删除的个数 */ public long deleteObject(final Collection collection) { return redisTemplate.delete(collection); } /** * 缓存List数据 * * @param key 缓存的键值 * @param dataList 待缓存的List数据 * @return 缓存的对象 */ public long setCacheList(final String key, final List dataList) { Long count = redisTemplate.opsForList().rightPushAll(key, dataList); return count == null ? 0 : count; } /** * 获得缓存的list对象 * * @param key 缓存的键值 * @return 缓存键值对应的数据 */ public List getCacheList(final String key) { return redisTemplate.opsForList().range(key, 0, -1); } /** * 缓存Set * * @param key 缓存键值 * @param dataSet 缓存的数据 * @return 缓存数据的对象 */ public BoundSetOperations setCacheSet(final String key, final Set dataSet) { BoundSetOperations setOperation = redisTemplate.boundSetOps(key); Iterator it = dataSet.iterator(); while (it.hasNext()) { setOperation.add(it.next()); } return setOperation; } /** * 获得缓存的set * * @param key key * @return 集合的内容 */ public Set getCacheSet(final String key) { return redisTemplate.opsForSet().members(key); } /** * 缓存Map * * @param key key * @param dataMap 数据映射 */ public void setCacheMap(final String key, final Map dataMap) { if (dataMap != null) { redisTemplate.opsForHash().putAll(key, dataMap); } } /** * 获得缓存的Map * * @param key key * @return 映射 */ public Map getCacheMap(final String key) { return redisTemplate.opsForHash().entries(key); } /** * 往Hash中存入数据 * * @param key Redis键 * @param hKey Hash键 * @param value 值 */ public void setCacheMapValue(final String key, final String hKey, final T value) { redisTemplate.opsForHash().put(key, hKey, value); } /** * 获取Hash中的数据 * * @param key Redis键 * @param hKey Hash键 * @return Hash中的对象 */ public T getCacheMapValue(final String key, final String hKey) { HashOperations opsForHash = redisTemplate.opsForHash(); return opsForHash.get(key, hKey); } /** * 获取多个Hash中的数据 * * @param key Redis键 * @param hKeys Hash键集合 * @return Hash对象集合 */ public List getMultiCacheMapValue(final String key, final Collection hKeys) { return redisTemplate.opsForHash().multiGet(key, hKeys); } /** * 获得缓存的基本对象列表 * * @param pattern 字符串前缀 * @return 对象列表 */ public Collection keys(final String pattern) { return redisTemplate.keys(pattern); } /** * 设置分布式锁 * @param key 锁的key * @param value 值 * @return true表示存在,false表示不存在 */ public synchronized Boolean setNX(final String key, final String value) throws Exception{ Object obj = null; try { obj = redisTemplate.execute((RedisCallback) connection -> { StringRedisSerializer serializer = new StringRedisSerializer(); Boolean success = connection.setNX(serializer.serialize(key), serializer.serialize(value)); connection.close(); return success; }); } catch (Exception e) { log.error("setNX redis error, key : {} - {}", key,e); throw e; } return obj != null ? (Boolean) obj : false; } /** * 设置分布式锁,超时间单位秒 * @param key 锁的key * @param value 值 * @param timeOut 超时时间 * @return true表示存在,false表示不存在 */ public synchronized Boolean setNX(final String key, final String value,long timeOut) throws Exception { boolean b = this.setNX(key,value); redisTemplate.expire(key,timeOut,TimeUnit.SECONDS); return b; } /** * 删除锁 * @param key 锁的key */ public void unlock(final String key) { redisTemplate.delete(key); } /** * 自减 大于等于0 * @param key 锁的key * @return Boolean */ public Boolean decrement(final String key) { return redisTemplate.opsForValue().decrement(key) >= 0; } public Boolean decrement(final String key, long count) { return redisTemplate.opsForValue().decrement(key,count) >= 0; } /** * 自减 * @param key 锁的key * @return Boolean */ public Long decrementLong(final String key) { return redisTemplate.opsForValue().decrement(key); } /** * 自增 * @param key 锁的key * @return Boolean */ public Long increment(final String key) { return redisTemplate.opsForValue().increment(key); } public Long increment(final String key, long count) { return redisTemplate.opsForValue().increment(key,count); } /** * 前缀匹配删除 * @param keyPrefix key前缀 */ public Boolean deleteByPrefix(final String keyPrefix) { List list = new LinkedList<>(); ScanOptions build = ScanOptions.scanOptions().match(keyPrefix+":*").count(5000).build(); RedisSerializer redisSerializer = redisTemplate.getKeySerializer(); Cursor cursor = (Cursor) redisTemplate.executeWithStickyConnection(redis -> new ConvertingCursor<>(redis.scan(build), redisSerializer::deserialize)); if (cursor != null){ try { while ( cursor.hasNext()) { list.add(cursor.next().toString()); } try { cursor.close(); } catch (IOException e) { e.printStackTrace(); log.error("redis中的Cursor关闭失败!"); } } finally { try { cursor.close(); } catch (IOException e) { e.printStackTrace(); } } Long delete = redisTemplate.delete(list); log.info("删除菜单key: "+delete+"个。\n 详情:"+list.toString()); return delete > 0L; } return false; } /** * 前缀匹配 * @param keyPrefix key前缀 * */ public List findKeysByPrefix(final String keyPrefix) { List list = new ArrayList<>(); ScanOptions build = ScanOptions.scanOptions().match(keyPrefix+":*").count(5000).build(); RedisSerializer redisSerializer = redisTemplate.getKeySerializer(); Cursor cursor = (Cursor) redisTemplate.executeWithStickyConnection(redis -> new ConvertingCursor<>(redis.scan(build), redisSerializer::deserialize)); if (cursor != null){ try { while (cursor.hasNext()) { list.add(getCacheObject(cursor.next().toString())); } try { cursor.close(); } catch (IOException e) { e.printStackTrace(); } } finally { try { cursor.close(); } catch (IOException e) { e.printStackTrace(); } } return list; } return new ArrayList<>(); } /** * 基于Lua脚本实现原子查询并删除 * @param key * @return */ public Boolean deleteLuaByKey(String key) { String str2 = "if redis.call('EXISTS', KEYS[1]) == 1 then redis.call('DEL', KEYS[1]) return 1 else return 0 end"; RedisScript redisScript = new DefaultRedisScript<>(str2,Boolean.class); Boolean execute = (Boolean) redisTemplate.execute(redisScript, Collections.singletonList(key)); return execute; } /** * GEO 添加数据(经纬度) * @param key * @return */ public void addGEO(String key, Map map) { redisTemplate.opsForGeo().add(key,map); } /** * GEO 添加数据(经纬度) * @param key * @return */ public void addGEO(String key, Point point, String member) { redisTemplate.opsForGeo().add(key,point,member); } public void removeGEO(String key,String... member) { redisTemplate.opsForGeo().remove(key,member); } /** * GEO 查询距离 * @param point 需要查询的地址 * @param key 城市 * @param members 节点 * @return map(商铺,距离) */ public Map distanceGEO(Point point,String key, List members) { GeoOperations geo = redisTemplate.opsForGeo(); long l = System.currentTimeMillis(); String member = "geo"+l; addGEO(key,point,member); Map map = new HashMap<>(); members.forEach(e->{ Distance distance = geo.distance(key, member, e, Metrics.KILOMETERS); map.put(e,String.valueOf(distance.getValue())); }); removeGEO(key,key,member); return map; } /** * 获取List集合操作 * @return 操作 */ public ListOperations opsForList(){ return this.redisTemplate.opsForList(); } /** * 获取Set集合操作 * @return 操作 */ public SetOperations opsForSet(){ return this.redisTemplate.opsForSet(); } /** * 获取hash操作 * @return 操作 */ public HashOperations opsForHash(){ return this.redisTemplate.opsForHash(); } }