pom
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
整合SpringBoot
package com.wx.cp.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
@Configuration
public class JedisConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.timeout:2000}")
private int timeout;
@Value("${spring.redis.jedis.pool.max-active:20}")
private int maxActive;
@Value("${spring.redis.jedis.pool.max-idle:8}")
private int maxIdle;
@Value("${spring.redis.jedis.pool.min-idle:2}")
private int minIdle;
@Bean
public JedisPool jedisPool() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMinIdle(minIdle);
jedisPoolConfig.setMaxTotal(maxActive);
JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, password,3);
return jedisPool;
}
}
package com.wx.cp.utils;
import cn.hutool.core.lang.UUID;
import lombok.extern.slf4j.Slf4j;
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 redis.clients.jedis.Response;
@Slf4j
@Component
public class SimpleSlidingWindowUtil {
@Autowired
private JedisPool jedisPool;
public Jedis getJedis() {
return jedisPool.getResource();
}
public void close(Jedis jedis) {
if (jedis != null) {
jedis.close();
}
}
public boolean isActionAllowed(String userId, int maxCount) {
int period = 1;
return this.coreMethod(userId, period, maxCount);
}
public boolean isActionAllowed(String userId, int period, int maxCount) {
return this.coreMethod(userId, period, maxCount);
}
public String getKey(String userId, String actionKey) {
return String.format("wechat:%s:%s", userId, actionKey);
}
private boolean coreMethod(String userId, int period, int maxCount) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
if (jedis != null) {
long ts = System.currentTimeMillis();
String actionKey = String.valueOf(ts / 1000);
String key = this.getKey(userId, actionKey);
Pipeline pipe = jedis.pipelined();
pipe.multi();
pipe.zadd(key, ts, UUID.randomUUID().toString());
pipe.zremrangeByScore(key, 0, ts - (period * 1000L));
Response<Long> count = pipe.zcard(key);
pipe.pexpire(key, period * 1000L);
pipe.exec();
pipe.close();
log.info("简单滑动窗口Util,Jedis状态 : {}, key :{}, 状态:{} ", jedis.ping(), key, count.get() <= maxCount);
return count.get() <= maxCount;
}
} catch (Exception e) {
log.error("简单滑动窗口Util,isActionAllowed方法报错:{}", e.getMessage(), e);
} finally {
jedisPool.returnResource(jedis);
}
return false;
}
}
测试的代码
package com.wx.cp.utils;
import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Response;
import java.io.IOException;
@Slf4j
public class SimpleSlidingWindowByZSet {
private Jedis jedis;
public SimpleSlidingWindowByZSet(Jedis jedis) {
this.jedis = jedis;
}
public boolean isActionAllowedAll(String userId, String actionKey, int period, int maxCount) throws IOException {
String key = this.key(userId, actionKey);
long ts = System.currentTimeMillis();
Pipeline pipe = jedis.pipelined();
pipe.multi();
pipe.zadd(key, ts, String.valueOf(ts));
pipe.zremrangeByScore(key, 0, ts - (period * 1000));
Response<Long> count = pipe.zcard(key);
pipe.expire(key, period);
pipe.exec();
pipe.close();
return count.get() <= maxCount;
}
public boolean isActionAllowed(String userId, int maxCount) {
try {
String actionKey = String.valueOf(DateUtil.currentSeconds());
int period = 1;
String key = this.key(userId, actionKey);
long ts = System.currentTimeMillis();
Pipeline pipe = jedis.pipelined();
pipe.multi();
pipe.zadd(key, ts, String.valueOf(ts));
pipe.zremrangeByScore(key, 0, ts - (period * 1000));
Response<Long> count = pipe.zcard(key);
pipe.expire(key, period);
pipe.exec();
pipe.close();
return count.get() <= maxCount;
} catch (Exception e) {
log.error("简单滑动窗口Util,isActionAllowed方法报错:{}", e.getMessage(), e);
}
return false;
}
public String key(String userId, String actionKey) {
return String.format("limit:%s:%s", userId, actionKey);
}
}
package com.wx.cp.utils;
import cn.hutool.core.date.DateUtil;
import org.springframework.beans.factory.annotation.Value;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.concurrent.TimeUnit;
public class SimpleSlidingWindowUtilTest {
@Value("${spring.redis.host}")
private static String host;
@Value("${spring.redis.port}")
private static Integer port;
@Value("${spring.redis.database}")
private String database;
@Value("${spring.redis.password}")
private static String password;
public static JedisPool pool = null;
static {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxIdle(8);
config.setMaxTotal(18);
pool = new JedisPool(config, "127.0.0.1", 6379, 2000, "123456",3);
}
public static void main(String[] args) throws Exception {
Jedis jedis = pool.getResource();
System.out.println(jedis.ping());
SimpleSlidingWindowByZSet slidingWindow = new SimpleSlidingWindowByZSet(jedis);
for (int i = 1; i <= 1000; i++) {
long l = DateUtil.currentSeconds();
boolean actionAllowed = slidingWindow.isActionAllowedAll("wechat", String.valueOf(l), 1, 5);
if (actionAllowed){
System.out.println("第" + i +"次操作 = " + (actionAllowed ? "成功" : "失败") + "时间戳 = " + l);
}
TimeUnit.MILLISECONDS.sleep(1);
}
jedis.close();
}
}