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 <T> void setCacheObject(final String key, final T value) {
|
redisTemplate.opsForValue().set(key, value);
|
}
|
|
/**
|
* 缓存基本的对象,Integer、String、实体类等
|
*
|
* @param key 缓存的键值
|
* @param value 缓存的值
|
* @param timeout 时间
|
* @param 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 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> T getCacheObject(final String key) {
|
ValueOperations<String, T> 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 <T> long setCacheList(final String key, final List<T> dataList) {
|
Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
|
return count == null ? 0 : count;
|
}
|
|
/**
|
* 获得缓存的list对象
|
*
|
* @param key 缓存的键值
|
* @return 缓存键值对应的数据
|
*/
|
public <T> List<T> getCacheList(final String key)
|
{
|
return redisTemplate.opsForList().range(key, 0, -1);
|
}
|
|
/**
|
* 缓存Set
|
*
|
* @param key 缓存键值
|
* @param dataSet 缓存的数据
|
* @return 缓存数据的对象
|
*/
|
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());
|
}
|
return setOperation;
|
}
|
|
/**
|
* 获得缓存的set
|
*
|
* @param key key
|
* @return 集合的内容
|
*/
|
public <T> Set<T> getCacheSet(final String key)
|
{
|
return redisTemplate.opsForSet().members(key);
|
}
|
|
/**
|
* 缓存Map
|
*
|
* @param key key
|
* @param dataMap 数据映射
|
*/
|
public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
|
if (dataMap != null) {
|
redisTemplate.opsForHash().putAll(key, dataMap);
|
}
|
}
|
|
/**
|
* 获得缓存的Map
|
*
|
* @param key key
|
* @return 映射
|
*/
|
public <T> Map<String, T> getCacheMap(final String key)
|
{
|
return redisTemplate.opsForHash().entries(key);
|
}
|
|
/**
|
* 往Hash中存入数据
|
*
|
* @param key Redis键
|
* @param hKey Hash键
|
* @param value 值
|
*/
|
public <T> 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> T getCacheMapValue(final String key, final String hKey) {
|
HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
|
return opsForHash.get(key, hKey);
|
}
|
|
/**
|
* 获取多个Hash中的数据
|
*
|
* @param key Redis键
|
* @param hKeys Hash键集合
|
* @return Hash对象集合
|
*/
|
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) {
|
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();
|
}
|
}
|