完成后端移除Redis改造
This commit is contained in:
@@ -1,11 +1,18 @@
|
||||
package com.ruoyi.common.core.cache;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class InMemoryCacheStore
|
||||
{
|
||||
private final ConcurrentHashMap<String, InMemoryCacheEntry> entries = new ConcurrentHashMap<>();
|
||||
@@ -21,10 +28,11 @@ public class InMemoryCacheStore
|
||||
|
||||
public void set(String key, Object value, long timeout, TimeUnit unit)
|
||||
{
|
||||
long expireAtMillis = System.currentTimeMillis() + unit.toMillis(timeout);
|
||||
long expireAtMillis = System.currentTimeMillis() + Math.max(0L, unit.toMillis(timeout));
|
||||
putEntry(key, new InMemoryCacheEntry(value, expireAtMillis));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T get(String key)
|
||||
{
|
||||
InMemoryCacheEntry entry = readEntry(key);
|
||||
@@ -41,6 +49,16 @@ public class InMemoryCacheStore
|
||||
return entries.remove(key) != null;
|
||||
}
|
||||
|
||||
public boolean delete(Collection<String> keys)
|
||||
{
|
||||
boolean deleted = false;
|
||||
for (String key : keys)
|
||||
{
|
||||
deleted = delete(key) || deleted;
|
||||
}
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public Set<String> keys(String pattern)
|
||||
{
|
||||
purgeExpiredEntries();
|
||||
@@ -54,6 +72,63 @@ public class InMemoryCacheStore
|
||||
return matchedKeys;
|
||||
}
|
||||
|
||||
public boolean expire(String key, long timeout, TimeUnit unit)
|
||||
{
|
||||
Objects.requireNonNull(unit, "TimeUnit must not be null");
|
||||
long expireAtMillis = System.currentTimeMillis() + Math.max(0L, unit.toMillis(timeout));
|
||||
return entries.computeIfPresent(key, (cacheKey, entry) -> entry.isExpired(System.currentTimeMillis())
|
||||
? null
|
||||
: new InMemoryCacheEntry(entry.value(), expireAtMillis)) != null;
|
||||
}
|
||||
|
||||
public long getExpire(String key)
|
||||
{
|
||||
return getExpire(key, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public long getExpire(String key, TimeUnit unit)
|
||||
{
|
||||
InMemoryCacheEntry entry = readEntry(key);
|
||||
if (entry == null)
|
||||
{
|
||||
return -2L;
|
||||
}
|
||||
if (entry.expireAtMillis() == null)
|
||||
{
|
||||
return -1L;
|
||||
}
|
||||
long remainingMillis = Math.max(0L, entry.expireAtMillis() - System.currentTimeMillis());
|
||||
long unitMillis = Math.max(1L, unit.toMillis(1));
|
||||
return (remainingMillis + unitMillis - 1) / unitMillis;
|
||||
}
|
||||
|
||||
public long increment(String key, long timeout, TimeUnit unit)
|
||||
{
|
||||
Objects.requireNonNull(unit, "TimeUnit must not be null");
|
||||
AtomicLong result = new AtomicLong();
|
||||
entries.compute(key, (cacheKey, currentEntry) -> {
|
||||
long now = System.currentTimeMillis();
|
||||
boolean missingOrExpired = currentEntry == null || currentEntry.isExpired(now);
|
||||
long nextValue = missingOrExpired ? 1L : toLong(currentEntry.value()) + 1L;
|
||||
Long expireAtMillis = missingOrExpired || currentEntry.expireAtMillis() == null
|
||||
? now + Math.max(0L, unit.toMillis(timeout))
|
||||
: currentEntry.expireAtMillis();
|
||||
if (missingOrExpired && currentEntry != null)
|
||||
{
|
||||
expiredCount.incrementAndGet();
|
||||
}
|
||||
result.set(nextValue);
|
||||
return new InMemoryCacheEntry(nextValue, expireAtMillis);
|
||||
});
|
||||
writeCount.incrementAndGet();
|
||||
return result.get();
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
entries.clear();
|
||||
}
|
||||
|
||||
public InMemoryCacheStats snapshot()
|
||||
{
|
||||
purgeExpiredEntries();
|
||||
@@ -67,6 +142,64 @@ public class InMemoryCacheStore
|
||||
writeCount.get());
|
||||
}
|
||||
|
||||
public <T> Map<String, T> getMap(String key)
|
||||
{
|
||||
Map<String, T> value = get(key);
|
||||
return value == null ? null : new HashMap<>(value);
|
||||
}
|
||||
|
||||
public <T> void putMap(String key, Map<String, T> dataMap)
|
||||
{
|
||||
set(key, new HashMap<>(dataMap));
|
||||
}
|
||||
|
||||
public <T> void putMapValue(String key, String mapKey, T value)
|
||||
{
|
||||
long ttl = getExpire(key, TimeUnit.MILLISECONDS);
|
||||
Map<String, T> current = getMap(key);
|
||||
if (current == null)
|
||||
{
|
||||
current = new HashMap<>();
|
||||
}
|
||||
current.put(mapKey, value);
|
||||
setWithOptionalTtl(key, current, ttl);
|
||||
}
|
||||
|
||||
public boolean deleteMapValue(String key, String mapKey)
|
||||
{
|
||||
long ttl = getExpire(key, TimeUnit.MILLISECONDS);
|
||||
Map<String, Object> current = getMap(key);
|
||||
if (current == null || !current.containsKey(mapKey))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
current.remove(mapKey);
|
||||
setWithOptionalTtl(key, current, ttl);
|
||||
return true;
|
||||
}
|
||||
|
||||
public <T> Set<T> getSet(String key)
|
||||
{
|
||||
Set<T> value = get(key);
|
||||
return value == null ? null : new HashSet<>(value);
|
||||
}
|
||||
|
||||
public <T> void putSet(String key, Set<T> dataSet)
|
||||
{
|
||||
set(key, new HashSet<>(dataSet));
|
||||
}
|
||||
|
||||
public <T> java.util.List<T> getList(String key)
|
||||
{
|
||||
java.util.List<T> value = get(key);
|
||||
return value == null ? null : new java.util.ArrayList<>(value);
|
||||
}
|
||||
|
||||
public <T> void putList(String key, java.util.List<T> dataList)
|
||||
{
|
||||
set(key, new java.util.ArrayList<>(dataList));
|
||||
}
|
||||
|
||||
private void putEntry(String key, InMemoryCacheEntry entry)
|
||||
{
|
||||
entries.put(key, entry);
|
||||
@@ -122,4 +255,23 @@ public class InMemoryCacheStore
|
||||
}
|
||||
return key.equals(pattern);
|
||||
}
|
||||
|
||||
private long toLong(Object value)
|
||||
{
|
||||
if (value instanceof Number number)
|
||||
{
|
||||
return number.longValue();
|
||||
}
|
||||
return Long.parseLong(String.valueOf(value));
|
||||
}
|
||||
|
||||
private void setWithOptionalTtl(String key, Object value, long ttlMillis)
|
||||
{
|
||||
if (ttlMillis > 0)
|
||||
{
|
||||
set(key, value, ttlMillis, TimeUnit.MILLISECONDS);
|
||||
return;
|
||||
}
|
||||
set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,268 +1,169 @@
|
||||
package com.ruoyi.common.core.redis;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
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.stereotype.Component;
|
||||
import com.ruoyi.common.core.cache.InMemoryCacheStats;
|
||||
import com.ruoyi.common.core.cache.InMemoryCacheStore;
|
||||
|
||||
/**
|
||||
* spring redis 工具类
|
||||
* 本地缓存门面,保留原有 RedisCache 业务入口。
|
||||
*
|
||||
* @author ruoyi
|
||||
**/
|
||||
@SuppressWarnings(value = { "unchecked", "rawtypes" })
|
||||
@SuppressWarnings("unchecked")
|
||||
@Component
|
||||
public class RedisCache
|
||||
{
|
||||
@Autowired
|
||||
public RedisTemplate redisTemplate;
|
||||
private final InMemoryCacheStore cacheStore;
|
||||
|
||||
public RedisCache(InMemoryCacheStore cacheStore)
|
||||
{
|
||||
this.cacheStore = cacheStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存基本的对象,Integer、String、实体类等
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @param value 缓存的值
|
||||
*/
|
||||
public <T> void setCacheObject(final String key, final T value)
|
||||
{
|
||||
redisTemplate.opsForValue().set(key, value);
|
||||
cacheStore.set(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存基本的对象,Integer、String、实体类等
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @param value 缓存的值
|
||||
* @param timeout 时间
|
||||
* @param timeUnit 时间颗粒度
|
||||
*/
|
||||
public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit)
|
||||
{
|
||||
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
|
||||
cacheStore.set(key, value, timeout.longValue(), 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);
|
||||
return cacheStore.expire(key, timeout, unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取有效时间
|
||||
*
|
||||
* @param key Redis键
|
||||
* @return 有效时间
|
||||
*/
|
||||
public long getExpire(final String key)
|
||||
{
|
||||
return redisTemplate.getExpire(key);
|
||||
return cacheStore.getExpire(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 key是否存在
|
||||
*
|
||||
* @param key 键
|
||||
* @return true 存在 false不存在
|
||||
*/
|
||||
public Boolean hasKey(String key)
|
||||
{
|
||||
return redisTemplate.hasKey(key);
|
||||
return cacheStore.hasKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的基本对象。
|
||||
*
|
||||
* @param key 缓存键值
|
||||
* @return 缓存键值对应的数据
|
||||
*/
|
||||
public <T> T getCacheObject(final String key)
|
||||
{
|
||||
ValueOperations<String, T> operation = redisTemplate.opsForValue();
|
||||
return operation.get(key);
|
||||
return cacheStore.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除单个对象
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
public boolean deleteObject(final String key)
|
||||
{
|
||||
return redisTemplate.delete(key);
|
||||
return cacheStore.delete(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除集合对象
|
||||
*
|
||||
* @param collection 多个对象
|
||||
* @return
|
||||
*/
|
||||
public boolean deleteObject(final Collection collection)
|
||||
{
|
||||
return redisTemplate.delete(collection) > 0;
|
||||
if (collection == null || collection.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
List<String> keys = new ArrayList<>(collection.size());
|
||||
for (Object item : collection)
|
||||
{
|
||||
keys.add(String.valueOf(item));
|
||||
}
|
||||
return cacheStore.delete(keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存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;
|
||||
cacheStore.putList(key, dataList);
|
||||
return dataList == null ? 0 : dataList.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的list对象
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @return 缓存键值对应的数据
|
||||
*/
|
||||
public <T> List<T> getCacheList(final String key)
|
||||
{
|
||||
return redisTemplate.opsForList().range(key, 0, -1);
|
||||
return cacheStore.getList(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存Set
|
||||
*
|
||||
* @param key 缓存键值
|
||||
* @param dataSet 缓存的数据
|
||||
* @return 缓存数据的对象
|
||||
*/
|
||||
public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet)
|
||||
public <T> long 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;
|
||||
cacheStore.putSet(key, dataSet);
|
||||
return dataSet == null ? 0 : dataSet.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的set
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public <T> Set<T> getCacheSet(final String key)
|
||||
{
|
||||
return redisTemplate.opsForSet().members(key);
|
||||
return cacheStore.getSet(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存Map
|
||||
*
|
||||
* @param key
|
||||
* @param dataMap
|
||||
*/
|
||||
public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
|
||||
{
|
||||
if (dataMap != null) {
|
||||
redisTemplate.opsForHash().putAll(key, dataMap);
|
||||
if (dataMap != null)
|
||||
{
|
||||
cacheStore.putMap(key, dataMap);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的Map
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public <T> Map<String, T> getCacheMap(final String key)
|
||||
{
|
||||
return redisTemplate.opsForHash().entries(key);
|
||||
return cacheStore.getMap(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);
|
||||
cacheStore.putMapValue(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);
|
||||
Map<String, T> map = cacheStore.getMap(key);
|
||||
return map == null ? null : map.get(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);
|
||||
Map<String, T> map = cacheStore.getMap(key);
|
||||
if (map == null || hKeys == null || hKeys.isEmpty())
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<T> values = new ArrayList<>(hKeys.size());
|
||||
for (Object hKey : hKeys)
|
||||
{
|
||||
values.add(map.get(String.valueOf(hKey)));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除Hash中的某条数据
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param hKey Hash键
|
||||
* @return 是否成功
|
||||
*/
|
||||
public boolean deleteCacheMapValue(final String key, final String hKey)
|
||||
{
|
||||
return redisTemplate.opsForHash().delete(key, hKey) > 0;
|
||||
return cacheStore.deleteMapValue(key, hKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的基本对象列表
|
||||
*
|
||||
* @param pattern 字符串前缀
|
||||
* @return 对象列表
|
||||
*/
|
||||
public Collection<String> keys(final String pattern)
|
||||
{
|
||||
return redisTemplate.keys(pattern);
|
||||
return cacheStore.keys(pattern);
|
||||
}
|
||||
|
||||
public long increment(String key, long timeout, TimeUnit unit)
|
||||
{
|
||||
return cacheStore.increment(key, timeout, unit);
|
||||
}
|
||||
|
||||
public InMemoryCacheStats getCacheStats()
|
||||
{
|
||||
return cacheStore.snapshot();
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
cacheStore.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.ruoyi.common.constant.CacheConstants;
|
||||
import com.ruoyi.common.core.domain.entity.SysDictData;
|
||||
import com.ruoyi.common.core.redis.RedisCache;
|
||||
@@ -41,10 +41,14 @@ public class DictUtils
|
||||
*/
|
||||
public static List<SysDictData> getDictCache(String key)
|
||||
{
|
||||
JSONArray arrayCache = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
|
||||
if (StringUtils.isNotNull(arrayCache))
|
||||
Object cacheObject = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
|
||||
if (cacheObject instanceof List<?> listCache)
|
||||
{
|
||||
return arrayCache.toList(SysDictData.class);
|
||||
return (List<SysDictData>) listCache;
|
||||
}
|
||||
if (StringUtils.isNotNull(cacheObject))
|
||||
{
|
||||
return JSON.parseArray(JSON.toJSONString(cacheObject), SysDictData.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user