From 13fbd2d9fdc7146cc5709b30b3f04e81c829f86f Mon Sep 17 00:00:00 2001
From: cl <1442464845@qq.com>
Date: 星期二, 24 三月 2026 16:53:21 +0800
Subject: [PATCH] 大屏接口
---
src/main/java/com/zy/common/utils/RedisUtil.java | 196 +++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 183 insertions(+), 13 deletions(-)
diff --git a/src/main/java/com/zy/common/utils/RedisUtil.java b/src/main/java/com/zy/common/utils/RedisUtil.java
index 41cef35..02e3278 100644
--- a/src/main/java/com/zy/common/utils/RedisUtil.java
+++ b/src/main/java/com/zy/common/utils/RedisUtil.java
@@ -1,28 +1,43 @@
package com.zy.common.utils;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
/**
* redisTemplate灏佽
*
*/
+@Slf4j
@Component
public class RedisUtil {
+
+ private static final long LOCAL_NO_EXPIRE = Long.MAX_VALUE;
+ /** 鏃� TTL 鍐欏叆 Redis 澶辫触鏃讹紝鍐呭瓨鏉$洰榛樿淇濈暀鏃堕暱锛堢锛� */
+ private static final long LOCAL_DEFAULT_TTL_SEC = 86400L;
// @Autowired
// private RedisTemplate<String, Object> redisTemplate;
@Autowired
private RedisTemplate redisTemplate;
+
+ private final ConcurrentHashMap<String, LocalCacheEntry> localCache = new ConcurrentHashMap<>();
+ private final Object fallbackLock = new Object();
+ private volatile boolean redisFallbackMode = false;
+ private final Set<String> fallbackLocalKeys = ConcurrentHashMap.newKeySet();
public RedisTemplate getRedisTemplate() {
return redisTemplate;
@@ -72,7 +87,7 @@
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
- return false;
+ return localHasValid(key);
}
}
@@ -84,10 +99,19 @@
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
- if (key.length == 1) {
- redisTemplate.delete(key[0]);
- } else {
- redisTemplate.delete(CollectionUtils.arrayToList(key));
+ try {
+ if (key.length == 1) {
+ redisTemplate.delete(key[0]);
+ } else {
+ redisTemplate.delete(CollectionUtils.arrayToList(key));
+ }
+ } catch (Exception e) {
+ // Redis 涓嶅彲鐢ㄦ椂浠嶆竻鐞嗘湰鍦版潯鐩�
+ }
+ for (String k : key) {
+ if (k != null) {
+ localCache.remove(k);
+ }
}
}
}
@@ -101,7 +125,18 @@
* @return 鍊�
*/
public Object get(String key) {
- return key == null ? null : redisTemplate.opsForValue().get(key);
+ if (key == null) {
+ return null;
+ }
+ try {
+ Object v = redisTemplate.opsForValue().get(key);
+ notifyRedisAvailable();
+ return v;
+ } catch (Exception e) {
+ enterFallbackIfNeeded();
+ log.info("Redis 涓嶅彲鐢紝浠� JVM 鍐呭瓨璇诲彇 key={}锛屽師鍥�: {}", key, e.getMessage());
+ return localGet(key);
+ }
}
/**
@@ -140,10 +175,13 @@
break;
}
}
+ localCache.remove(key);
+ notifyRedisAvailable();
return true;
} catch (Exception e) {
- e.printStackTrace();
- return false;
+ log.debug("Redis set 澶辫触", e);
+ localPutFallback(key, value, LOCAL_DEFAULT_TTL_SEC);
+ return true;
}
}
@@ -157,10 +195,13 @@
public boolean setAsync(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
+ localCache.remove(key);
+ notifyRedisAvailable();
return true;
} catch (Exception e) {
- e.printStackTrace();
- return false;
+ log.debug("Redis setAsync 澶辫触", e);
+ localPutFallback(key, value, LOCAL_DEFAULT_TTL_SEC);
+ return true;
}
}
@@ -178,11 +219,16 @@
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
+ return true;
}
+ localCache.remove(key);
+ notifyRedisAvailable();
return true;
} catch (Exception e) {
- e.printStackTrace();
- return false;
+ log.debug("Redis set(expire) 澶辫触", e);
+ long ttl = time > 0 ? time : LOCAL_DEFAULT_TTL_SEC;
+ localPutFallback(key, value, ttl);
+ return true;
}
}
@@ -630,7 +676,15 @@
* @return
*/
public Set keys(String pattern) {
- return redisTemplate.keys(pattern);
+ try {
+ Set<?> s = redisTemplate.keys(pattern);
+ notifyRedisAvailable();
+ return s;
+ } catch (Exception e) {
+ enterFallbackIfNeeded();
+ log.info("Redis 涓嶅彲鐢紝浠� JVM 鍐呭瓨鍖归厤 keys锛宲attern={}锛屽師鍥�: {}", pattern, e.getMessage());
+ return localKeysMatching(pattern);
+ }
}
/**
@@ -643,6 +697,122 @@
redisTemplate.convertAndSend(channel, message);
}
+ private void enterFallbackIfNeeded() {
+ synchronized (fallbackLock) {
+ if (!redisFallbackMode) {
+ redisFallbackMode = true;
+ log.warn("Redis 涓嶅彲鐢紝瀛楃涓茬浉鍏崇紦瀛樺皢鏆傚瓨浜� JVM 鍐呭瓨锛屽緟 Redis 鎭㈠鍚庤嚜鍔ㄥ垏鍥� Redis 骞舵竻鐞嗕笂杩伴敭");
+ }
+ }
+ }
+
+ private void notifyRedisAvailable() {
+ if (!redisFallbackMode && fallbackLocalKeys.isEmpty()) {
+ return;
+ }
+ synchronized (fallbackLock) {
+ if (!redisFallbackMode && fallbackLocalKeys.isEmpty()) {
+ return;
+ }
+ int n = fallbackLocalKeys.size();
+ for (String k : new ArrayList<>(fallbackLocalKeys)) {
+ localCache.remove(k);
+ }
+ fallbackLocalKeys.clear();
+ redisFallbackMode = false;
+ if (n > 0) {
+ log.info("Redis 宸叉仮澶嶏紝宸叉竻鐞� JVM 鍐呭瓨涓� {} 涓洜 Redis 涓嶅彲鐢ㄨ�屾殏瀛樼殑閿�", n);
+ } else {
+ log.info("Redis 宸叉仮澶�");
+ }
+ }
+ }
+
+ private void localPutFallback(String key, Object value, long ttlSeconds) {
+ if (key == null) {
+ return;
+ }
+ synchronized (fallbackLock) {
+ if (!redisFallbackMode) {
+ redisFallbackMode = true;
+ log.warn("Redis 涓嶅彲鐢紝瀛楃涓茬浉鍏崇紦瀛樺皢鏆傚瓨浜� JVM 鍐呭瓨锛屽緟 Redis 鎭㈠鍚庤嚜鍔ㄥ垏鍥� Redis 骞舵竻鐞嗕笂杩伴敭");
+ }
+ fallbackLocalKeys.add(key);
+ localPut(key, value, ttlSeconds);
+ }
+ log.info("Redis 涓嶅彲鐢紝閿凡鍐欏叆 JVM 鍐呭瓨: {}", key);
+ }
+
+ private void localPut(String key, Object value, long ttlSeconds) {
+ if (key == null) {
+ return;
+ }
+ long expireAt = ttlSeconds > 0
+ ? System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(ttlSeconds)
+ : LOCAL_NO_EXPIRE;
+ localCache.put(key, new LocalCacheEntry(value, expireAt));
+ }
+
+ private Object localGet(String key) {
+ LocalCacheEntry e = localCache.get(key);
+ if (e == null) {
+ return null;
+ }
+ if (e.expireAtMillis != LOCAL_NO_EXPIRE && System.currentTimeMillis() > e.expireAtMillis) {
+ localCache.remove(key, e);
+ return null;
+ }
+ return e.value;
+ }
+
+ private boolean localHasValid(String key) {
+ return localGet(key) != null;
+ }
+
+ private Set<String> localKeysMatching(String pattern) {
+ if (pattern == null) {
+ return new HashSet<>();
+ }
+ Pattern p = Pattern.compile(globToRegex(pattern));
+ Set<String> out = new HashSet<>();
+ for (String k : localCache.keySet()) {
+ if (localGet(k) == null) {
+ continue;
+ }
+ if (p.matcher(k).matches()) {
+ out.add(k);
+ }
+ }
+ return out;
+ }
+
+ private static String globToRegex(String glob) {
+ StringBuilder sb = new StringBuilder("^");
+ for (int i = 0; i < glob.length(); i++) {
+ char c = glob.charAt(i);
+ if (c == '*') {
+ sb.append(".*");
+ } else if (c == '?') {
+ sb.append('.');
+ } else if ("\\.[]{}()+-^$|".indexOf(c) >= 0) {
+ sb.append('\\').append(c);
+ } else {
+ sb.append(c);
+ }
+ }
+ sb.append('$');
+ return sb.toString();
+ }
+
+ private static final class LocalCacheEntry {
+ final Object value;
+ final long expireAtMillis;
+
+ LocalCacheEntry(Object value, long expireAtMillis) {
+ this.value = value;
+ this.expireAtMillis = expireAtMillis;
+ }
+ }
}
--
Gitblit v1.9.1