liujie
2026-08-26 d7fd9123c3e100e5fc8079fea8d9cacf8afd4a32
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