java發送短信系列之限制日發送次數。本站提示廣大學習愛好者:(java發送短信系列之限制日發送次數)文章只能為提供參考,不一定能成為您想要的結果。以下是java發送短信系列之限制日發送次數正文
在前兩篇文章中, 我們完成了同步/異步發送短信和限制發送短信頻率.這一篇, 我們引見一上限制逐日向統一個用戶(依據手機號和ip斷定)發送短信的次數
1、數據表構造
因為須要記載成天的發送記載, 是以這裡我們將數據保留到數據庫中. 數據表構造以下:
type為驗證碼的類型, 好比注冊, 重置暗碼等.
sendTime的默許值為以後時光.
2、限制日發送次數
我們這裡須要用到上一篇中提到的接口和實體類.
DailyCountFilter.java
public class DailyCountFilter implements SmsFilter { private int ipDailyMaxSendCount; private int mobileDailyMaxSendCount; private SmsDao smsDao; // 省略了部門無用代碼 @Override public boolean filter(SmsEntity smsEntity) { if (smsDao.getMobileCount(smsEntity.getMobile()) >= mobileDailyMaxSendCount) { return false; } if (smsDao.getIPCount(smsEntity.getIp()) >= ipDailyMaxSendCount) { return false; } smsDao.saveEntity(smsEntity); return true; } }
重要代碼很簡略, 起首斷定向指定的手機號發送的次數能否到達了日最年夜發送次數, 以後再斷定指定的ip要求發送的次數能否到達了最年夜次數. 假如都沒有, 則將本次發送的手機號, ip等信息保留到數據庫中.
固然, 這個類存在必定的成績: 在斷定能否跨越最年夜次數到保留實體數據之間能夠曾經有其他線程保留了新的數據. 形成下面的兩個斷定其實不是相對的精確.
我們可使用序列化品級的事務包管不會產生毛病, 然則價值太高. 是以我們這裡不做處置. 由於我們後面曾經完成了限制發送頻率. 假如先應用FrequencyFilter過濾一次, 限制發送頻率, 那末根本上弗成能湧現後面說的成績.
還有一個成績: 跟著時光的推移, 這個表會愈來愈年夜, 形成查詢的機能相當的差. 我們可以向上一篇中那樣, 每隔一段時光就刪除無用的數據; 也能夠靜態的創立表, 然後向新表中拔出數據.
3、應用靜態表
這裡我們采取第二種計劃: 數據表的名字為"sms_四位年_兩位月", 好比"sms_2016_02". 拔出數據時依據如今的時光取得表名, 然後再拔出. 別的應用Quartz在每個月的20號2點生成下個月和下下個月的數據表:
我們起首修正DailyCountFilter類, 在這個類中添加義務籌劃, 准時生成數據表:
DailyCountFilter.java
// 在下面代碼的基本上, 再添加以下代碼 public class DailyCountFilter implements SmsFilter { private Scheduler sched; @Override public void init() throws SchedulerException { smsDao.createTable(0); // 創立這個月的數據表 smsDao.createTable(1); // 創立下個月的數據表 SchedulerFactory sf = new StdSchedulerFactory(); sched = sf.getScheduler(); // 創立Quartz容器 JobDataMap jobDataMap = new JobDataMap(); jobDataMap.put("smsDao", smsDao); // 創立運轉義務時須要應用的數據map // 創立job對象, 該對象履行現實的義務 JobDetail job = JobBuilder.newJob(CreateSmsTableJob.class) .usingJobData(jobDataMap) .withIdentity("create sms table job").build(); // 創立trigger對象, 該對象用來描寫觸發履行job的時光規矩 // 好比這裡的每個月20號2點 CronTrigger trigger = TriggerBuilder.newTrigger() .withIdentity("create sms table trigger") .withSchedule(CronScheduleBuilder.cronSchedule("0 0 2 20 * ?"))// 每個月的20號2點 .build(); sched.scheduleJob(job, trigger); // 注冊義務和觸發規矩 sched.start(); // 啟動調劑 } @Override public void destroy() { try { sched.shutdown(); } catch (SchedulerException e) {} } public static class CreateSmsTableJob implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { JobDataMap dataMap = context.getJobDetail().getJobDataMap(); SmsDao smsDao = (SmsDao) dataMap.get("smsDao"); // 取得傳過去的smsDao對象 smsDao.createTable(1); // 創立下個月的數據表 smsDao.createTable(2); // 創立下下個月的數據表 } } }
接上去, 我們看看SmsDao的部門代碼:
SmsDao.java
public class SmsDao { /** * 創立新的日記表 * * @param monthExcursion 偏移的月數 */ public void createTable(int monthExcursion){ String sql = "CREATE TABLE IF NOT EXISTS " + getTableName(monthExcursion) + " LIKE sms"; // 履行sql語句 } /** * 保留SmsEntity實體對象 */ public void saveEntity(SmsEntity smsEntity){ String sql = "INSERT INTO " + getNowTableName() + " (mobile, ip, type) VALUES(?, ?, ?)"; // 履行sql語句 } /** * 取得指定手機號明天要求發送短信的次數 * * @param mobile 用戶手機號 * @return 明天要求發送短信的次數 */ public long getMobileCount(String mobile){ String sql = "SELECT count(id) FROM " + getNowTableName() + " WHERE mobile=? AND time >= CURDATE()"; // 履行sql語句, 前往查詢成果 } // 省略了getIPCount辦法 /** * 取得如今應用的表的名字 */ private String getNowTableName() { return getTableName(0); } private DateFormat dateFormat = new SimpleDateFormat("yyyy_MM"); /** * 取得絕對如今偏移monthExcursion月的表名 * * @param monthExcursion 偏移的月數 * @return 對應月的表名 */ private String getTableName(int monthExcursion) { Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.MONTH, monthExcursion); Date date = calendar.getTime(); return "sms_" + dateFormat.format(date); } }
SmsDao中的createTable辦法勝利運轉有個條件, 就是存在sms數據表. createTable辦法會復制sms表的構造創立新的數據表.
我們保存發送短信的數據(手機號, ip, 時光等), 而不是直接刪除, 是由於今後能夠須要剖析這些數據, 獲得我們想要的信息, 好比斷定辦事商短信的達到率、能否有人歹意發送短信等. 乃至能夠取得不測的"欣喜".
以上就是本文的全體內容,願望年夜家可以持續存眷。