發送短信如何限制1小時內最多發送11條短信

發送短信如何限制1小時內最多發送11條短信

場景:
發送短信屬於付費業務,有時爲了防止短信攻擊,須要限制發送短信的頻率,例如在1個小時以內最多發送11條短信.
如何實現呢?java

思路有兩個

截至到當前時刻的1個小時以內,看是否有超過11條短信

Date now=new Date();
Date oneHourAgo= //1個小時以前的時刻
//查詢條件有兩個:時間範圍,手機號
List<SMS> smsList=this.smsService.query(fromTime,toTime,mobile);
if(smsList.size()>11){
System.out.println("超出限制,禁止發送");
}else{
System.out.println("能夠發送");
}

dao中:redis

/***
     * 獲取指定時間長度(範圍)內,發送的短信次數 <br />
     * 在指定時間長度(範圍)內,發送的短信次數是否超出限制
     * @param startDate
     * @param endDate
     * @param mobile
     * @return
     */
    public Long count(String startDate, String endDate, String mobile) {
        CriteriaHelper criteriaHelper = CriteriaHelper.getInstance(this);
       return criteriaHelper.between("createTime",startDate,endDate)
                .eq("mobile",mobile)
                .count();
    }

Service中:優化

/***
     * 在指定時間長度(範圍)內,發送的短信次數是否超出限制
     * @param mobile
     * @return
     */
    public  boolean validateSMSSendCountByTimeRange(String mobile) {
        Date now=new Date();
        //1小時前的時刻
        Date oneHouseAgo = TimeHWUtil.getDateBeforeHour(now, 1);
        Long count = this.sMSDao.count(TimeHWUtil.formatDateTime(oneHouseAgo), TimeHWUtil.formatDateTime(now), mobile);
        if (count >= SMSUtil.LIMITCOUNT_SEND_SMS) {
            String msg="超出限制";
            logger.warn(msg);
            smsLogger.warn(msg);
            return false;
        }
        return true;
    }

最近的11條短信 時間跨度是否小於1小時,若是小於1小時,就禁止發送

每次發送短信,要寫入當前時間戳到redis:
String mobile="13718486139"; String time=String.valueOf(DateTimeUtil.getCurrentMillisecond()); RedisHelper.getInstance().saveKeyCache("limit_one_hour", mobile+"_"+time, time);this

檢查時先獲取全部時間戳:.net

Map map=RedisHelper.getInstance().getAllKeyCache("limit_one_hour");

具體判斷邏輯:code

@Test  
    public void test_limitOneHour2(){  
        String mobile="13718486139";  
        int limitCount=11;  
        int limitTime=60*60;//1小時,單位:秒  
        Map<String,String> map=new HashMap<String,String>();  
        map.put("13718486139_1445429819328", "1445431479437");  
        map.put("13718486139_1445429874699", "1445431485996");  
        map.put("13718486139_1445429874799", "1445431491527");  
        map.put("13718486139_1445430757886", "1445431496853");  
          
        System.out.println(map);  
        List<Long>list=new ArrayList<Long>();  
        for(String key:map.keySet()){  
            if(key.startsWith(mobile)){  
                list.add(Long.parseLong(map.get(key))/1000);  
            }  
        }  
        SortList<Long>sortUtil=new SortList<Long>();  
        sortUtil.Sort(list, "longValue", "desc");  
        int length=list.size();  
        int toIndex=0;//要截取的最大序號  
        if(limitCount>length){  
            toIndex=length;  
        }else{  
            toIndex=limitCount;  
        }  
        List<Long>result=list.subList(0, toIndex);  
        long delter=list.get(0).longValue()-list.get(toIndex-1).longValue();  
        long delterSecond=delter;  
        System.out.println(delterSecond);  
        if(delterSecond<limitTime){  
            System.out.println("超限");  
        }else{  
            System.out.println("能夠繼續發短信");  
        }  
        System.out.println(result);  
    }

步驟:
(1)把當前手機號的全部時間戳放入list中;orm

(2)對list排序,按時間順序,從大到小;(時間越大,表示離如今越近)blog

(3)根據次數(limitCount)限制 來截取list;排序

(4)計算list中第一個元素和最後一個元素的差量,即limitCount條短信的時間跨度delterget

(5)若delter 小於時間限制limitTime,則表示超過限制,那麼禁止發送短信

優化以後的代碼:

public static boolean isLimit() {
        long n = System.currentTimeMillis();
        Map records = RedisCacheUtil2.getPushRecordList();
        if (ValueWidget.isNullOrEmpty(records)) {
            return false;
        }
        List<String> timestamps = new ArrayList<String>(records.values());
        SortList<String> sortUtil = new SortList<String>();
        sortUtil.sort(timestamps, null, "desc");

        // 1 分鐘以內不能超過 4(limitCount)
        int limitCount = 4;
        int limitTime = 60 * 1000;//1 分鐘,單位:豪秒

        int length = timestamps.size();
        if (length < limitCount) {
            //沒有超過限制
            return false;
        }
        int toIndex = 0;//要截取的最大序號
        /*if (limitCount + 1 > length) {
            toIndex = length;
        } else {*/
        toIndex = limitCount;
//        }
        List<String> result = timestamps.subList(0, toIndex);
        //和當前時間比較

        System.out.println("n :" + n);
        long delter = /*result.get(0))*/n - Long.parseLong(result.get(toIndex - 1));
        long delterSecond = delter;
        System.out.println("delter :" + delter);
        System.out.println(delterSecond);
        if (delterSecond < limitTime) {
            System.out.println("record :" + HWJacksonUtils.getJsonP(result));
            System.out.println("timestamps :" + HWJacksonUtils.getJsonP(timestamps));
            System.out.println("超限");
            return true;
        } else {
            System.out.println("能夠繼續發短信");
            return false;
        }
    }

使用限流器

參考: https://my.oschina.net/hanchao/blog/1833612
參考:http://hw1287789687.iteye.com/blog/2250898

相關文章
相關標籤/搜索