激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - java發送短信系列之限制日發送次數

java發送短信系列之限制日發送次數

2020-04-02 13:28BK JAVA教程

這篇文章主要為大家詳細介紹了java發送短信系列之限制日發送次數,詳細介紹了限制每日向同一個用戶(根據手機號和ip判斷)發送短信次數的方法,感興趣的小伙伴們可以參考一下

在前兩篇文章中, 我們實現了同步/異步發送短信以及限制發送短信頻率.這一篇, 我們介紹一下限制每日向同一個用戶(根據手機號和ip判斷)發送短信的次數

1、數據表結構

由于需要記錄整天的發送記錄, 因此這里我們將數據保存到數據庫中. 數據表結構如下:

java發送短信系列之限制日發送次數

type為驗證碼的類型, 比如注冊, 重置密碼等.
sendTime的默認值為當前時間.

2、限制日發送次數

我們這里需要用到上一篇中提到的接口和實體類.

DailyCountFilter.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// 在上面代碼的基礎上, 再添加如下代碼
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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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, 時間等), 而不是直接刪除, 是因為以后可能需要分析這些數據, 獲取我們想要的信息, 比如判斷服務商短信的到達率、是否有人惡意發送短信等. 甚至可能獲得意外的"驚喜".

以上就是本文的全部內容,希望大家可以繼續關注。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美成人小视频 | www.com超碰 | 久久经典国产视频 | 精品久久久久久国产三级 | 久草在线综合 | 欧美城网站地址 | 免费永久看羞羞片网站入口 | 国产精品久久久久久久久久电影 | 999视频网 | 精品亚洲视频在线 | 91香蕉影视 | 成人激情视频网站 | 一级美女大片 | 一级欧美日韩 | 手机在线看片国产 | 中文字幕欧美亚洲 | 依依成人精品视频 | 欧美成人一二区 | 中文在线免费观看 | 一级大片在线观看 | 久热久操 | 国产免费观看a大片的网站 欧美成人一级 | 精品国产乱码久久久久久丨区2区 | 永久免费毛片 | 国产精品剧情一区二区在线观看 | 欧美激情999 | 成人午夜亚洲 | 国产欧美日韩在线播放 | 国产精品av久久久久久网址 | 久久精品视频69 | 久久96国产精品久久久 | 欧美性色黄大片www 操碰网 | 久久性生活免费视频 | 2019亚洲日韩新视频 | 看片一区二区三区 | 欧美另类激情 | 色屁屁xxxxⅹ在线视频 | v片在线看 | 精品国产91一区二区三区 | 中文字幕在线免费播放 | 欧美黄在线 |