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