今天是個周六,還在苦逼加班的我對那些休周末的同行表達羨慕嫉妒践叠,對那么同樣加班的同行共勉吧~~
整理了下這周的工作進度。除了項目試上線以外也就是補充補充之前遺留下的小問題了。這篇文章就是說手機號每天接受驗證碼的條數(shù)限制宫峦。
我們現(xiàn)在的好多程序注冊需要手機號并且發(fā)送驗證碼來驗證手機號的真?zhèn)巍R郧俺S玫木褪前⒗锏陌l(fā)送短信的功能(感覺這個真的很常用玫鸟,阿里的產(chǎn)品還是值得信賴的)斗遏。不過我們這個項目采用的是極光的短信功能。不過這個其實不重要鞋邑,因為我們來限制一個手機號 一天可以發(fā)多少短信和短信平臺無關诵次。我這里是因為老板說聽說某某程序員說受到過這樣的攻擊,不到一個小時一個產(chǎn)品發(fā)出去幾千塊錢的短信費用枚碗。而且我另一個朋友也說過如果不加以限制可能他一個多線程跑過去我們平臺的短信費用立刻欠費逾一。
這里說一下具體的思路:因為確實有時候我們在注冊的時候會發(fā)送各種意外。比如當時信號不好啊肮雨,或者莫名其妙的手機短信沒收到啊不可避免的遵堵,所以一個人一天只能發(fā)一條短信肯定也不合理。然后我們老板目前設置的是一個人一天能接收的驗證碼是10條(多了少了是可以設置的怨规。不過我接下的例子也是一個手機號碼一天可以接收十條驗證碼)陌宿。我這里采用的是存redis來實現(xiàn)這一個功能的(感覺這里數(shù)據(jù)庫也可以實現(xiàn),但是不如reids好波丰。最近敲喜歡redis的說壳坪,用起來得心應手,哈哈)掰烟。就是每次調(diào)用發(fā)送驗證碼這個接口都會判斷手機號碼是否在redis中存為key了爽蝴。如果沒有則創(chuàng)建一個key為手機號碼value是1.因為redis中不支持數(shù)字所以我是1+“”將其變?yōu)榱藄tring類型。如果redis中已經(jīng)有這個key了則將此key的值取出來加1再存進redis中纫骑。這里在做的時候過期問題有一點小糾結(jié)蝎亚。最后想明白了。我們老板的要求是每天先馆。也就是這個key-value的存活期應該是到今天結(jié)束发框。所以我又專門做了個小工具類來獲取當前時間到今天結(jié)束時間(也就是23點59分59秒999毫秒+1毫秒的時間)的毫秒數(shù)。并將此作為這個key的到期時間的(關于這個我是給予我的實際情況來設計的煤墙,如果親們有啥別的具體的需求可以酌情更改)梅惯。
這里上一下代碼:
首先是獲取當前時間到今天結(jié)束時間所剩余的毫秒數(shù):
/**
* 獲取當前時間到今天結(jié)束 的毫秒數(shù)
*因為這個是工具類里面的方法所以是靜態(tài)的
* @return
*/
public static long getEndTime() {
//獲取當前時間的毫秒數(shù)
long time = new java.util.Date().getTime();
//獲取到今天結(jié)束的毫秒數(shù)
Calendar todayEnd = Calendar.getInstance();
todayEnd.set(Calendar.HOUR_OF_DAY, 23); // Calendar.HOUR 12小時制顾患。HOUR_OF_DAY 24小時制
todayEnd.set(Calendar.MINUTE, 59);
todayEnd.set(Calendar.SECOND, 59);
todayEnd.set(Calendar.MILLISECOND, 999);
long endTime = todayEnd.getTimeInMillis();
//這里endTime-time獲取的是到23:59:59:999的毫秒數(shù)。再加1才是到24點整的毫秒數(shù)
return endTime-time+1;
}
然后發(fā)送短信接口的代碼:
public ResultBean SendSMSCode(String tel) {
if("10".equals(stringRedisTemplate.opsForValue().get(tel))) {
return Tools.result(200, "您的手機號碼已達到發(fā)送驗證碼次數(shù)上限", null, false);
}
SMSClient client = new SMSClient(masterSecret, appkey);
SMSPayload payload = SMSPayload.newBuilder().setMobileNumber(tel).setTempId(1).build();
try {
//這句代碼是真正發(fā)送驗證碼的方法个唧。如果你們用別的平臺的接口也應該有一句話是真正發(fā)送的代碼江解。
SendSMSResult res =client.sendSMSCode(payload);
if(stringRedisTemplate.opsForValue().get(tel)==null) {
stringRedisTemplate.opsForValue().set(tel, "1", Tools.getEndTime(), TimeUnit.MILLISECONDS);
}else {
String value = stringRedisTemplate.opsForValue().get(tel);
int times = Integer.parseInt(value)+1;
String timesStr = String.valueOf(times);
stringRedisTemplate.opsForValue().set(tel, timesStr, Tools.getEndTime(), TimeUnit.MILLISECONDS);
}
return Tools.result(200, "發(fā)送驗證碼成功", res, true);
} catch (Exception e) {
LOG.info("Error Message: " + e.getMessage());
return Tools.result(500, "發(fā)送驗證碼失敗", null, false);
}
}
額,還是大概說一下代碼的邏輯吧徙歼。首先進入到這個接口就要判斷此手機號是否已經(jīng)發(fā)到了10次上限犁河。如果已經(jīng)發(fā)到了則直接返回限制。如果沒達到每日上限才往下繼續(xù)魄梯。然后加粗的這幾句都是發(fā)送短信的代碼桨螺。平臺不一樣肯定不是一種寫法。就不多說了酿秸。然后是等短信發(fā)送成功了才操作的灭翔。這一點很注意,短信發(fā)送成功才算一次次數(shù)辣苏。然后判斷redis中是否有次手機號為key肝箱,如果沒有則創(chuàng)建一個,值是1稀蟋,如果有則在原來的基礎上+1煌张。沒啥復雜的邏輯操作,就是一個思路而已退客。然后每次過期時間都是根據(jù)當前時間來獲取的骏融。單位是毫秒。如果業(yè)務需求是24小時什么的也可以靈活改動萌狂。
感覺代碼中也沒啥有難度的地方档玻。如果說有看不懂的比如說對redis操作看不懂可以跳轉(zhuǎn)專門講StringRedisTemplate的文章:
然后有更好的實現(xiàn)方式或者思路的可以留言或者私聊我~~
全文手打~~這么不容易的寫個文~~如果你覺得用到了~留個言點個贊轉(zhuǎn)個發(fā)什么的啊~