瀏覽代碼

build 引入redis作为缓存,对接未来的无状态服务,一小时过期

mamingxu 2 天之前
父節點
當前提交
6f27b0c0fa

+ 11 - 0
easier-report-biz/src/main/java/com/yaoyicloud/config/CommonDataCache.java

@@ -12,6 +12,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 @Component
 public class CommonDataCache {
@@ -21,6 +22,7 @@ public class CommonDataCache {
     private final ObjectMapper objectMapper = new ObjectMapper();
     // Redis Hash操作工具
     private final HashOperations<String, String, String> hashOps;
+    private static final long DEF_REPORT_TTL = 1 * 60 * 60 * 1000;
 
     // 构造函数注入RedisTemplate
     public CommonDataCache(RedisTemplate<String, String> redisTemplate) {
@@ -34,6 +36,13 @@ public class CommonDataCache {
         return KEY_PREFIX + relationId;
     }
 
+    /**
+     * 为哈希键设置过期时间(若键已存在,会刷新过期时间)
+     */
+    private void setExpire(String redisKey) {
+        hashOps.getOperations().expire(redisKey, DEF_REPORT_TTL, TimeUnit.MILLISECONDS);
+    }
+
     /**
      * 添加或更新单个键值对
      */
@@ -42,6 +51,7 @@ public class CommonDataCache {
         try {
             // 序列化value并写入Hash
             hashOps.put(redisKey, key, objectMapper.writeValueAsString(value));
+            setExpire(redisKey);
         } catch (JsonProcessingException e) {
             throw new RuntimeException("序列化数据失败: " + key, e);
         }
@@ -66,6 +76,7 @@ public class CommonDataCache {
         }
         // 存入序列化后的 map
         hashOps.putAll(redisKey, serializedMap);
+        setExpire(redisKey);
     }
     /**
      * 获取指定relationId的所有键值对

+ 21 - 0
easier-report-biz/src/main/java/com/yaoyicloud/config/RedisConfig.java

@@ -0,0 +1,21 @@
+package com.yaoyicloud.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+@Configuration
+public class RedisConfig {
+
+  @Bean
+  public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
+    RedisTemplate<String, Object> template = new RedisTemplate<>();
+    template.setConnectionFactory(connectionFactory);
+    template.setKeySerializer(new StringRedisSerializer());
+    template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
+    return template;
+  }
+}

+ 123 - 0
easier-report-biz/src/main/java/com/yaoyicloud/config/RelationCounterRedisUtil.java

@@ -0,0 +1,123 @@
+package com.yaoyicloud.config;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Redis 计数器工具类
+ */
+@Component
+@RequiredArgsConstructor
+public class RelationCounterRedisUtil {
+
+    // Redis 键前缀(避免与其他缓存键冲突)
+    private static final String COUNTER_KEY_PREFIX = "counter:";
+
+    // Redis 模板(注入 String 类型的模板,计数以字符串形式存储)
+    private final RedisTemplate<String, String> redisTemplate;
+    private static final long DEF_REPORT_TTL = 1 * 60 * 60 * 1000;
+
+    /**
+     * 生成 Redis 计数器的完整 key
+     * @param relationId 业务关联 ID
+     * @return 格式:relation:counter:{relationId}
+     */
+    private String getCounterKey(Long relationId) {
+        return COUNTER_KEY_PREFIX + relationId;
+    }
+
+    /**
+     * 初始化计数器(若不存在则设置初始值为 0)
+     * 注意:通常无需主动调用,increment 方法会自动处理不存在的键
+     * @param relationId 业务关联 ID
+     */
+    public void initCounter(Long relationId) {
+        String key = getCounterKey(relationId);
+        // 仅当键不存在时设置初始值为 0(避免覆盖已有计数)
+        redisTemplate.opsForValue().setIfAbsent(key, "1", DEF_REPORT_TTL, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * 计数器自增 1,并返回自增后的值
+     * @param relationId 业务关联 ID
+     * @return 自增后的计数(例如:初始为 0,调用后返回 1)
+     */
+    public int increment(Long relationId) {
+        return increment(relationId, 1);
+    }
+
+    /**
+     * 计数器自增指定步长,并返回自增后的值
+     * @param relationId 业务关联 ID
+     * @param step 自增步长(正整数)
+     * @return 自增后的计数
+     */
+    public int increment(Long relationId, int step) {
+        if (step <= 0) {
+            throw new IllegalArgumentException("自增步长必须为正整数");
+        }
+        String key = getCounterKey(relationId);
+        // Redis 的 INCRBY 命令:原子性自增,返回自增后的值
+        Long newValue = redisTemplate.opsForValue().increment(key, step);
+        return newValue.intValue();
+    }
+
+    /**
+     * 获取当前计数
+     * @param relationId 业务关联 ID
+     * @return 当前计数(若键不存在,返回 0)
+     */
+    public Integer getCount(Long relationId) {
+        String key = getCounterKey(relationId);
+        String value = redisTemplate.opsForValue().get(key);
+        if (value == null) {
+            initCounter(relationId);
+            return 1;
+        }
+
+        return Integer.parseInt(value);
+    }
+
+    /**
+     * 重置计数器为 0
+     * @param relationId 业务关联 ID
+     */
+    public void reset(Long relationId) {
+        String key = getCounterKey(relationId);
+        redisTemplate.opsForValue().set(key, "1", DEF_REPORT_TTL, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * 删除计数器(适用于业务结束后清理资源)
+     * @param relationId 业务关联 ID
+     * @return 是否删除成功(true:键存在且被删除;false:键不存在)
+     */
+    public boolean delete(Long relationId) {
+        String key = getCounterKey(relationId);
+        return Boolean.TRUE.equals(redisTemplate.delete(key));
+    }
+
+    /**
+     * 设置计数器过期时间(避免长期占用 Redis 内存)
+     * @param relationId 业务关联 ID
+     * @param timeout 过期时间
+     * @param unit 时间单位
+     */
+    public void setExpire(Long relationId, long timeout, TimeUnit unit) {
+        String key = getCounterKey(relationId);
+        redisTemplate.expire(key, timeout, unit);
+    }
+
+    /**
+     * 检查计数器是否存在
+     * @param relationId 业务关联 ID
+     * @return true:存在;false:不存在
+     */
+    public boolean exists(Long relationId) {
+        String key = getCounterKey(relationId);
+        return Boolean.TRUE.equals(redisTemplate.hasKey(key));
+    }
+}

+ 15 - 5
easier-report-biz/src/main/java/com/yaoyicloud/config/ReportPathManager.java

@@ -1,18 +1,20 @@
 package com.yaoyicloud.config;
+
 import org.springframework.data.redis.core.ListOperations;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Component;
 
-
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
 @Component
 public class ReportPathManager {
 
     private static final String KEY_PREFIX = "reports:";
-
+    private static final long DEF_REPORT_TTL = 1 * 60 * 60 * 1000;
 
     private final RedisTemplate<String, String> redisTemplate;
     private final ListOperations<String, String> listOps;
@@ -29,12 +31,20 @@ public class ReportPathManager {
         return KEY_PREFIX + sessionId;
     }
 
+    /**
+     * 为列表键设置过期时间(若已存在则刷新过期时间)
+     */
+    private void setExpire(String key) {
+        redisTemplate.expire(key, DEF_REPORT_TTL, TimeUnit.MILLISECONDS);
+    }
+
     /**
      * 添加单个报告路径(按插入顺序有序)
      */
     public void addReportPath(String sessionId, String reportPath) {
         String key = getReportKey(sessionId);
         listOps.rightPush(key, reportPath);
+        setExpire(key);
     }
 
     /**
@@ -43,6 +53,7 @@ public class ReportPathManager {
     public void addReportPaths(String sessionId, Collection<String> reportPaths) {
         String key = getReportKey(sessionId);
         listOps.rightPushAll(key, reportPaths.toArray(new String[0]));
+        setExpire(key);
     }
 
     /**
@@ -61,7 +72,6 @@ public class ReportPathManager {
         return redisTemplate.hasKey(key);
     }
 
-
     /**
      * 获取所有报告路径的总数(注意:需遍历所有key,可能影响性能)
      */
@@ -71,8 +81,8 @@ public class ReportPathManager {
             return 0;
         }
         return keys.stream()
-                .mapToInt(key -> listOps.size(key).intValue())
-                .sum();
+            .mapToInt(key -> listOps.size(key).intValue())
+            .sum();
     }
 
     /**