| | |
| | | package com.vci.web.redis; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.Iterator; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import java.util.concurrent.TimeUnit; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.data.redis.core.BoundSetOperations; |
| | | import org.springframework.data.redis.core.HashOperations; |
| | | import org.springframework.data.redis.core.RedisTemplate; |
| | | import org.springframework.data.redis.core.ValueOperations; |
| | | 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 wang1 |
| | | * @author dangsn |
| | | **/ |
| | | @SuppressWarnings(value = { "unchecked", "rawtypes" }) |
| | | @Component |
| | | @Slf4j |
| | | public class RedisService |
| | | { |
| | | @Autowired(required = false) |
| | |
| | | * @param key 缓存的键值 |
| | | * @param value 缓存的值 |
| | | */ |
| | | public <T> void setCacheObject(final String key, final T value) |
| | | { |
| | | public <T> void setCacheObject(final String key, final T value) { |
| | | redisTemplate.opsForValue().set(key, value); |
| | | } |
| | | |
| | |
| | | * @param timeout 时间 |
| | | * @param timeUnit 时间颗粒度 |
| | | */ |
| | | public <T> void setCacheObject(final String key, final T value, final Long timeout, final TimeUnit timeUnit) |
| | | { |
| | | public <T> void setCacheObject(final String key, final T value, final Long timeout, final TimeUnit timeUnit) { |
| | | redisTemplate.opsForValue().set(key, value, timeout, timeUnit); |
| | | } |
| | | |
| | |
| | | * @param unit 时间单位 |
| | | * @return true=设置成功;false=设置失败 |
| | | */ |
| | | public boolean expire(final String key, final long timeout, final TimeUnit unit) |
| | | { |
| | | public boolean expire(final String key, final long timeout, final TimeUnit unit) { |
| | | return redisTemplate.expire(key, timeout, unit); |
| | | } |
| | | |
| | |
| | | * @param key 键 |
| | | * @return true 存在 false不存在 |
| | | */ |
| | | public Boolean hasKey(String key) |
| | | { |
| | | public Boolean hasKey(String key) { |
| | | return redisTemplate.hasKey(key); |
| | | } |
| | | |
| | |
| | | * @param key 缓存键值 |
| | | * @return 缓存键值对应的数据 |
| | | */ |
| | | public <T> T getCacheObject(final String key) |
| | | { |
| | | public <T> T getCacheObject(final String key) { |
| | | ValueOperations<String, T> operation = redisTemplate.opsForValue(); |
| | | return operation.get(key); |
| | | } |
| | |
| | | /** |
| | | * 删除单个对象 |
| | | * |
| | | * @param key |
| | | * @param key 可以 |
| | | * @return 删除是否成功 |
| | | */ |
| | | public boolean deleteObject(final String key) |
| | | { |
| | |
| | | * 删除集合对象 |
| | | * |
| | | * @param collection 多个对象 |
| | | * @return |
| | | * @return 删除的个数 |
| | | */ |
| | | public long deleteObject(final Collection collection) |
| | | { |
| | |
| | | } |
| | | |
| | | /** |
| | | * list的长度 |
| | | * |
| | | * @param key 缓存的键值 |
| | | * @return 缓存的对象 |
| | | */ |
| | | public <T> Long listSize(final String key) |
| | | { |
| | | return redisTemplate.opsForList().size(key); |
| | | } |
| | | |
| | | /** |
| | | * 从左边取出一个list元素 |
| | | * |
| | | * @param key 缓存的键值 |
| | | * @return 缓存的对象 |
| | | */ |
| | | public <T> Object leftPop(final String key) |
| | | { |
| | | return redisTemplate.opsForList().leftPop(key); |
| | | } |
| | | |
| | | /** |
| | | * 从右边缓存List数据 |
| | | * 缓存List数据 |
| | | * |
| | | * @param key 缓存的键值 |
| | | * @param dataList 待缓存的List数据 |
| | | * @return 缓存的对象 |
| | | */ |
| | | public <T> long setCacheList(final String key, final List<T> dataList) |
| | | { |
| | | public <T> long setCacheList(final String key, final List<T> dataList) { |
| | | Long count = redisTemplate.opsForList().rightPushAll(key, dataList); |
| | | return count == null ? 0 : count; |
| | | } |
| | | |
| | | /** |
| | | * 删除list中元素value |
| | | * @param key |
| | | * @param value |
| | | * @param <T> |
| | | * @return |
| | | */ |
| | | public <T> long deleteCacheListByKeyAndValue(final String key, final T value) |
| | | { |
| | | Long count = redisTemplate.opsForList().remove(key,0,value); |
| | | return count == null ? 0 : count; |
| | | } |
| | | |
| | |
| | | return redisTemplate.opsForList().range(key, 0, -1); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * 缓存Set |
| | | * |
| | |
| | | * @param dataSet 缓存的数据 |
| | | * @return 缓存数据的对象 |
| | | */ |
| | | public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) |
| | | { |
| | | public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) { |
| | | BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key); |
| | | Iterator<T> it = dataSet.iterator(); |
| | | while (it.hasNext()) |
| | | { |
| | | setOperation.add(it.next()); |
| | | } |
| | | String i = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + |
| | | "<Datas>\n" + |
| | | "\t<Data code=\"A1100012\" deptLevel=\"开发部门#测试部门\">\n" + |
| | | "\t\t<prop sName=\"供应商名称\" tName =\"供应商名称1\" >\n" + |
| | | "\t\t\t北京宏博远达科技有限公司2\n" + |
| | | "\t\t</prop>\n" + |
| | | "\t\t<prop sName=\"户头\" tName =\"户头1\">\n" + |
| | | "\t\t\t1111100012\n" + |
| | | "\t\t</prop>\n" + |
| | | "\t\t<prop sName=\"联系人\" tName=\"联系人1\">\n" + |
| | | "\t\t\t谢军2\n" + |
| | | "\t\t</prop>\n" + |
| | | "\t</Data>\n" + |
| | | "</Datas>"; |
| | | return setOperation; |
| | | } |
| | | |
| | | /** |
| | | * 获得缓存的set |
| | | * |
| | | * @param key |
| | | * @return |
| | | * @param key key |
| | | * @return 集合的内容 |
| | | */ |
| | | public <T> Set<T> getCacheSet(final String key) |
| | | { |
| | |
| | | /** |
| | | * 缓存Map |
| | | * |
| | | * @param key |
| | | * @param dataMap |
| | | * @param key key |
| | | * @param dataMap 数据映射 |
| | | */ |
| | | public <T> void setCacheMap(final String key, final Map<String, T> dataMap) |
| | | { |
| | | public <T> void setCacheMap(final String key, final Map<String, T> dataMap) { |
| | | if (dataMap != null) { |
| | | redisTemplate.opsForHash().putAll(key, dataMap); |
| | | } |
| | |
| | | /** |
| | | * 获得缓存的Map |
| | | * |
| | | * @param key |
| | | * @return |
| | | * @param key key |
| | | * @return 映射 |
| | | */ |
| | | public <T> Map<String, T> getCacheMap(final String key) |
| | | { |
| | |
| | | * @param hKey Hash键 |
| | | * @param value 值 |
| | | */ |
| | | public <T> void setCacheMapValue(final String key, final String hKey, final T value) |
| | | { |
| | | public <T> void setCacheMapValue(final String key, final String hKey, final T value) { |
| | | redisTemplate.opsForHash().put(key, hKey, value); |
| | | } |
| | | |
| | |
| | | * @param hKey Hash键 |
| | | * @return Hash中的对象 |
| | | */ |
| | | public <T> T getCacheMapValue(final String key, final String hKey) |
| | | { |
| | | public <T> T getCacheMapValue(final String key, final String hKey) { |
| | | HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash(); |
| | | return opsForHash.get(key, hKey); |
| | | } |
| | |
| | | * @param hKeys Hash键集合 |
| | | * @return Hash对象集合 |
| | | */ |
| | | public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) |
| | | { |
| | | public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) { |
| | | return redisTemplate.opsForHash().multiGet(key, hKeys); |
| | | } |
| | | |
| | |
| | | * @param pattern 字符串前缀 |
| | | * @return 对象列表 |
| | | */ |
| | | public Collection<String> keys(final String pattern) |
| | | { |
| | | public Collection<String> 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<Object>) 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<String> list = new LinkedList<>(); |
| | | ScanOptions build = ScanOptions.scanOptions().match(keyPrefix+":*").count(5000).build(); |
| | | RedisSerializer<String> 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 <T> List<T> findKeysByPrefix(final String keyPrefix) { |
| | | |
| | | List<T> list = new ArrayList<>(); |
| | | ScanOptions build = ScanOptions.scanOptions().match(keyPrefix+":*").count(5000).build(); |
| | | RedisSerializer<String> 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<Boolean> redisScript = new DefaultRedisScript<>(str2,Boolean.class); |
| | | Boolean execute = (Boolean) redisTemplate.execute(redisScript, Collections.singletonList(key)); |
| | | return execute; |
| | | } |
| | | /** |
| | | * GEO 添加数据(经纬度) |
| | | * @param key |
| | | * @return |
| | | */ |
| | | public <T extends Point> void addGEO(String key, Map<String,T> map) { |
| | | redisTemplate.opsForGeo().add(key,map); |
| | | } |
| | | |
| | | /** |
| | | * GEO 添加数据(经纬度) |
| | | * @param key |
| | | * @return |
| | | */ |
| | | public <T extends Point> void addGEO(String key, Point point, String member) { |
| | | redisTemplate.opsForGeo().add(key,point,member); |
| | | } |
| | | |
| | | |
| | | public <T extends Point> void removeGEO(String key,String... member) { |
| | | redisTemplate.opsForGeo().remove(key,member); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * GEO 查询距离 |
| | | * @param point 需要查询的地址 |
| | | * @param key 城市 |
| | | * @param members 节点 |
| | | * @return map(商铺,距离) |
| | | */ |
| | | public Map<String,String> distanceGEO(Point point,String key, List<String> members) { |
| | | GeoOperations geo = redisTemplate.opsForGeo(); |
| | | long l = System.currentTimeMillis(); |
| | | String member = "geo"+l; |
| | | addGEO(key,point,member); |
| | | Map<String,String> 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(); |
| | | } |
| | | } |