From d7fd9123c3e100e5fc8079fea8d9cacf8afd4a32 Mon Sep 17 00:00:00 2001
From: liujie <1793218484@qq.com>
Date: 星期三, 26 八月 2026 09:29:06 +0800
Subject: [PATCH] update

---
 cloud-server-account/src/main/java/com/dsh/account/util/RedisUtil.java |   80 ++++++++++++++++++++++++++++++++++++++++
 1 files changed, 80 insertions(+), 0 deletions(-)

diff --git a/cloud-server-account/src/main/java/com/dsh/account/util/RedisUtil.java b/cloud-server-account/src/main/java/com/dsh/account/util/RedisUtil.java
index 8fc0825..afe45ca 100644
--- a/cloud-server-account/src/main/java/com/dsh/account/util/RedisUtil.java
+++ b/cloud-server-account/src/main/java/com/dsh/account/util/RedisUtil.java
@@ -9,6 +9,8 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 
@@ -73,6 +75,84 @@
 
 
     /**
+     * 仅当key不存在时写入,并设置过期时间。
+     *
+     * @param key key
+     * @param value value
+     * @param time 过期时间,单位:秒
+     * @return 是否写入成功
+     */
+    public boolean setIfAbsent(String key, String value, int time) {
+        if (StringUtil.isEmpty(key)) {
+            return false;
+        }
+        try (Jedis resource = jedisPool.getResource()) {
+            return "OK".equals(resource.set(key, value, "NX", "EX", time));
+        }
+    }
+
+
+    /**
+     * 原子比较并删除。key存在时无论是否匹配都会被删除,避免验证码被暴力枚举。
+     */
+    public boolean consumeIfEquals(String key, String expectedValue) {
+        if (StringUtil.isEmpty(key) || expectedValue == null) {
+            return false;
+        }
+        String script = "local value = redis.call('get', KEYS[1]); "
+                + "if not value then return 0 end; "
+                + "redis.call('del', KEYS[1]); "
+                + "if value == ARGV[1] then return 1 else return 0 end";
+        try (Jedis resource = jedisPool.getResource()) {
+            Object result = resource.eval(
+                    script,
+                    Collections.singletonList(key),
+                    Collections.singletonList(expectedValue)
+            );
+            return Long.valueOf(1L).equals(result);
+        }
+    }
+
+
+    /**
+     * 获取固定时间窗口内的一个名额。
+     */
+    public boolean tryAcquireFixedWindow(String key, int maxCount, int windowSeconds) {
+        if (StringUtil.isEmpty(key) || maxCount <= 0 || windowSeconds <= 0) {
+            return false;
+        }
+        String script = "local current = tonumber(redis.call('get', KEYS[1]) or '0'); "
+                + "if current >= tonumber(ARGV[2]) then return 0 end; "
+                + "current = redis.call('incr', KEYS[1]); "
+                + "if current == 1 then redis.call('expire', KEYS[1], ARGV[1]) end; return 1";
+        try (Jedis resource = jedisPool.getResource()) {
+            Object result = resource.eval(
+                    script,
+                    Collections.singletonList(key),
+                    Arrays.asList(String.valueOf(windowSeconds), String.valueOf(maxCount))
+            );
+            return Long.valueOf(1L).equals(result);
+        }
+    }
+
+
+    /**
+     * 释放固定时间窗口内已获取的名额,用于下游调用失败后的补偿。
+     */
+    public void releaseFixedWindow(String key) {
+        if (StringUtil.isEmpty(key)) {
+            return;
+        }
+        String script = "local current = tonumber(redis.call('get', KEYS[1]) or '0'); "
+                + "if current <= 1 then redis.call('del', KEYS[1]); "
+                + "else redis.call('decr', KEYS[1]); end; return 1";
+        try (Jedis resource = jedisPool.getResource()) {
+            resource.eval(script, Collections.singletonList(key), Collections.<String>emptyList());
+        }
+    }
+
+
+    /**
      * 批量获取
      *
      * @param kes

--
Gitblit v1.7.1