用Redis實現頻繁操作的攔截,例如一天內只允許一個用戶登錄5次

    上次看到一個問題:如何用Redis實現只允許一個用戶一天內登錄五次。

    想到Redis中可以給string設置過期時間,所以我們可以利用這個特性來實現。

    作爲一個java程序猿,我們使用Jedis,具體使用到的API是:

  /**
   * The command is exactly equivalent to the following group of commands:
   * {@link #set(String, String) SET} + {@link #expire(String, int) EXPIRE}. The operation is atomic.
   */
  public String setex(final String key, final int seconds, final String value) {
    checkIsInMultiOrPipeline();
    client.setex(key, seconds, value);
    return client.getStatusCodeReply();
  }
    具體的代碼如下:
package com.test.redis.test;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Set;

import org.junit.Test;

import redis.clients.jedis.Jedis;
//By John 2018-04-02
public class TestRedis002 {
	private final static int TIME_LIMIT =  24; 					//一個週期,這裏爲了測試方便,我將週期設置的比較小
	private static Jedis jedis;
	private static int next = 0;								//爲了避免key相互覆蓋,我們加上一個自增後綴,使得key不會一樣
	private final static int MOST_TIMES_IN_TIME_LIMIT = 5;		//一個週期內最多的操作次數
	private final static String SEPERATOR = "~~";				//爲了爲了避免next後綴和原來的key互相影響,加上一個分隔字符串
	static{
		jedis = new Jedis("127.0.0.1", 6379);
	}
	private boolean login(String username, String password){
		if ( ! simpleValidation(username) || ! simpleValidation(password)) return false;		//進行一下簡單的格式攔截
		System.out.println(getCurTimeAsStr());					//當前操作時間
		
		Set<String> keys = jedis.keys(username + "*");			//爲了搜索出當前操作用戶的週期內(也就是沒有過期的)記錄
		if (keys != null &&  keys.size() >= MOST_TIMES_IN_TIME_LIMIT) {
			//週期內的操作次數爲容許次數
			System.out.println(TIME_LIMIT + " 秒內只能操作" + MOST_TIMES_IN_TIME_LIMIT + " 次");
			return false;
		}
		
		/**
		 * 生成一個包含有操作用戶標識的唯一key
		 * 每次操作的next都會自增1,防止key相同
		 */
		String strengthenStr = username + SEPERATOR + (next ++ );
		jedis.setex(strengthenStr, TIME_LIMIT, password);			//給key設置過期時間
		System.out.println(strengthenStr + "   操作成功");
		return true;
	}
	private boolean simpleValidation(String test){
		return test != null && test.length() > 5;
	}
	private String getCurTimeAsStr(){
		return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
	}
}

以及測試代碼:

	@Test
	public void test() throws InterruptedException{
		String username = "username123";
		String password = "password234";
		login(username, password);
		login(username, password);
		login(username, password);
		login(username, password);
		login(username, password);
		login(username, password);
		login(username, password);
		Thread.sleep((TIME_LIMIT + 2) * 1000);	//	過了一個週期之後再次進行測試
		login(username, password);
	}
測試結果:
2018-04-02 22:16:21
username123~~0   操作成功
2018-04-02 22:16:21
username123~~1   操作成功
2018-04-02 22:16:21
username123~~2   操作成功
2018-04-02 22:16:21
username123~~3   操作成功
2018-04-02 22:16:21
username123~~4   操作成功
2018-04-02 22:16:21
24 秒內只能操作5 次    
2018-04-02 22:16:21
24 秒內只能操作5 次
2018-04-02 22:16:47
username123~~5   操作成功
由測試結果可知,前面5次都成功了,隨後的兩次都因爲在一個週期之內,所以沒有成功。一個週期之後,至少第一次存在緩存數據庫中的key已經過期了(實際上經過26秒後,前面五次的都已經過期了),這就給最後一次操作騰出了空間,所以最後一次也成功了。
發佈了22 篇原創文章 · 獲贊 1 · 訪問量 8788
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章