基本思路:通过一个队列保存最近10次的登录记录,下一次登录请求来时,通过与队列中的第一条进行比较,如果在1分钟之内则拒绝请求,否则移除队首元素,将新的登录记录加到队尾。
package cn.com.learn;
import java.util.LinkedList;
import java.util.Random;
import static java.lang.Thread.sleep;
/**
* 模拟同一用户快速多次登录(请求),通过(UserLoginLimiter)限制
* Created by Jason li on 2015/8/6.
*/
public class UserLoginTimeController {
public static void main(String[] args) {
//限制器,限制在1秒之内最多登录10次
UserLoginLimiter limiter = new UserLoginLimiter(1000, 10);
Random r = new Random();
int allowCount = 0;
int denyCount = 0;
//模拟100次登录请求
for (int i = 0; i < 100; i++) {
LoginRecord loginRecord = new LoginRecord("123.456.789.10", System.currentTimeMillis(), "Jason.Li");
try {
sleep(r.nextInt(50)); //两次登录之间间隔的毫秒数
} catch (InterruptedException e) {
e.printStackTrace();
}
if (limiter.check(loginRecord)) {
System.out.println(loginRecord + "允许登录!");
allowCount ++;
} else {
System.out.println(loginRecord + "禁止登录!");
denyCount ++;
}
}
System.out.println("允许数量:" + allowCount );
System.out.println("拒绝数量:" + denyCount );
}
}
/**
* 用户登录记录限制类
* 限制在一定时长(thresholdInMillisecond)内最多登录(maxLoginTimes)次
*/
class UserLoginLimiter {
private int maxLoginTimes; //一定时间(thresholdInMillisecond值)内的最多登录次数
private int thresholdInMillisecond; //时长
private LinkedList<LoginRecord> loginRecordList; //最近的登录队列
/**
* 检查登录记录,
* 对在(thresholdInMillisecond)时长内超过(maxloginTimes)次的登录记录返回false,否则返回true;
* @param curLR
* @return
*/
public boolean check(LoginRecord curLR) {
//检查设置的值,对0及负数表示不限制登录
if (maxLoginTimes <= 0 || thresholdInMillisecond <= 0) return true;
//队列长度未到maxLoginTimes的不用限制
if (loginRecordList.size() < maxLoginTimes) {
loginRecordList.addLast(curLR);
return true;
}
//队列长度达到maxLoginTimes的,清理和当前记录比较超过thresholdInMillisecond值的记录
LoginRecord firstLR = loginRecordList.getFirst();
while (loginRecordList.size() > 0 && firstLR.getTime() + thresholdInMillisecond < curLR.getTime()) {
loginRecordList.removeFirst();
if (loginRecordList.size() > 0) {
firstLR = loginRecordList.getFirst();
} else {
break;
}
}
//检查队列是否有空间添加新的记录
if (loginRecordList.size() < maxLoginTimes) {
loginRecordList.addLast(curLR);
return true;
} else {
return false; //队列中的记录与当前登录记录发生在thresholdInMillisecond内,拒绝
}
}
private UserLoginLimiter() {}
public UserLoginLimiter(int thresholdInMillisecond, int maxLoginTimes) {
this.thresholdInMillisecond = thresholdInMillisecond;
this.maxLoginTimes = maxLoginTimes;
loginRecordList = new LinkedList<LoginRecord>();
}
}
/**
* 用户登录记录类
*/
class LoginRecord {
private String ip;
private long time;
private String username;
public LoginRecord(String ip, long time, String username) {
this.ip = ip;
this.time = time;
this.username = username;
}
public String getIp() {
return ip;
}
public long getTime() {
return time;
}
public String getUsername() {
return username;
}
@Override
public String toString() {
return "LoginRecord{" +
"ip='" + ip + '\'' +
", time=" + time +
", username='" + username + '\'' +
'}';
}
}