package com.dsh.account.util; import com.alibaba.csp.sentinel.util.StringUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.Pipeline; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * Redis工具类 */ @Component public class RedisUtil { @Autowired private JedisPool jedisPool; /** * 向redis中存储字符串没有过期时间 * Storing strings in Redis without an expiration time. * * @param key * @param value */ public void setStrValue(String key, String value) { if (StringUtil.isNotEmpty(key)) { Jedis resource = jedisPool.getResource(); String set = resource.set(key, value); closeJedis(resource); } } /** * 以分钟为单位设置存储值(设置过期时间) * Set storage value in minutes (set expiration time) as units. * * @param key * @param value * @param time 秒 */ public void setStrValue(String key, String value, int time) { if (StringUtil.isNotEmpty(key)) { Jedis resource = jedisPool.getResource(); String setex = resource.setex(key, time, value); closeJedis(resource); } } /** * 从redis中获取值 * * @param key * @return */ public String getValue(String key) { if (StringUtil.isNotEmpty(key)) { Jedis resource = jedisPool.getResource(); String data = resource.get(key); closeJedis(resource); return data; } return null; } /** * 仅当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.emptyList()); } } /** * 批量获取 * * @param kes * @return */ public List getValues(List kes) { if (null != kes) { Jedis resource = jedisPool.getResource(); Pipeline pipelined = resource.pipelined(); for (String key : kes) { pipelined.get(key); } List list = pipelined.syncAndReturnAll(); closeJedis(resource); pipelined.clear(); try { pipelined.close(); } catch (IOException e) { e.printStackTrace(); } List data = new ArrayList<>(); for (Object o : list) { if (null != o) { data.add(o); } } return data; } return null; } /** * 删除key * * @param key */ public void remove(String key) { if (StringUtil.isNotEmpty(key)) { Jedis resource = jedisPool.getResource(); Long del = resource.del(key); closeJedis(resource); } } /** * 删除资源 * * @param jedis */ public void closeJedis(Jedis jedis) { if (null != jedis) { jedis.close(); } } }