您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關java怎么使用觀察者模式異步短信/郵箱提醒用戶群,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
需求
用戶中有人設置了賬戶余額達到閾值時,短信/郵箱進行提醒的服務。我們將需要在他賬戶余額閾值達到指定數值的時候進行短信/郵箱消息通知,允許賬戶余額閾值出現偏差的時候通知,如果某個用戶48小時內已經短信/郵箱進行過通知了,那么將不再進行通知。
剖析
存在兩個主題:短信通知和郵箱通知
存在兩種觀察者:設置了短信通知且賬戶余額到達閾值的用戶,設置了郵箱通知且賬戶余額到達閾值的用戶。
用spring的定時器,每10分鐘去數據庫獲取某個主題已經達到閾值且開始了該主題的提醒功能的用戶
用spring的@Asycn注解異步短信通知,郵箱通知的相關方法
用redis設置用戶短信/郵箱為鍵名,設置過期時間為48小時。如果獲取不到該鍵值對,說明其在觀察者行列
代碼
觀察者父類
/** * 訂閱觀察者 * @author Administrator * */ @Component //標志為多例 @Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class SubscriberObserver implements Observer{ private String email; private String phone; private String username; @Autowired UserFunctionService UserFunctionService; @Override public void update(Observable o, Object arg) { if(o instanceof EmailAlertSubject){ UserFunctionService.alertUserEmail(email,username); } if(o instanceof PhoneAlertSubject){ UserFunctionService.alertUserPhone(phone,username); } } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public SubscriberObserver() { super(); // TODO Auto-generated constructor stub } }
主題
/** * email提醒主題 * @author Administrator * */ @Component public class EmailAlertSubject extends Observable{ public void alert(){ this.setChanged(); //如果用拉的方式,這么調用 this.notifyObservers(); } }
/** * 短信提醒主題 * @author Administrator * */ @Component public class PhoneAlertSubject extends Observable{ public void alert(){ this.setChanged(); //如果用拉的方式,這么調用 this.notifyObservers(); } }
定時器
/** * 定時給訂閱了短信提醒和email提醒的用戶服務 * @author Administrator * */ @Component public class TimeAlertTaskUtil { @Autowired CommonUserService commonUserService; @Autowired JedisConnectionFactory factory; @Autowired EmailAlertSubject emailSubject; @Autowired PhoneAlertSubject phoneSubject; private static final String emailKeyName = "emailAlert:"; private static final String phoneKeyName = "phoneAlert:"; /** * 定時獲取需要email提醒的用戶,每10分鐘調用一次 */ @Scheduled(fixedDelay = 1000 * 60 * 10) public void alertEmailTask() { // 1.獲取數據庫中達到了閾值的用戶 List<User> emails = commonUserService.getUserAlertEmailAndName(); // 2.查看redis中是否有達到閾值,且48小時已經通知的用戶,將其排除在觀察者行列,最終得出觀察者隊伍 List<SubscriberObserver> informEmail = getInformObserver(emails); // 3.創建主題,添加觀察者 addObservers(emailSubject, informEmail); // 4.通知 emailSubject.alert(); // 5.將已經通知的觀察者信息存儲到reids內,設置過期時間為一天 setRedisCache(emails); // 6.將觀察者從主題中移除 deleteObservers(emailSubject, informEmail); } /** * 定時獲取需要短信提醒的用戶,每10分鐘調用一次 * */ @Scheduled(fixedDelay = 1000 * 60 * 10) public void alertPhoneTask() { // 1.獲取數據庫中達到了閾值的用戶 List<User> phones = commonUserService.getUserAlertPhoneAndName(); // 2.查看redis中是否有達到閾值,且今天已經通知的用戶,將其排除在觀察者行列,最終得出觀察者隊伍 List<SubscriberObserver> informPhones = getInformObserver(phones); // 3.創建主題,添加觀察者 addObservers(phoneSubject, informPhones); // 4.通知 phoneSubject.alert(); // 5.將已經通知的觀察者信息存儲到reids內,設置過期時間為一天 setRedisCache(phones); // 6.將觀察者從主題中移除 deleteObservers(phoneSubject, informPhones); } /** * ------------------------------------------------------------------------ * ----------------------------------------------------- **/ /** * 過濾掉今天已經email提醒的用戶,返回真正需要提醒的觀察者列表 * * @param emails * @return */ private List<SubscriberObserver> getInformObserver( List<User> users) { List<SubscriberObserver> obs = new ArrayList<SubscriberObserver>(); Jedis jedis = factory.getConnection().getNativeConnection(); for (User user : users) { String value; SubscriberObserver observer = (SubscriberObserver) SpringConfigTool .getBean("subscriberObserver"); if (user.getEmail()!=null) { value = jedis.get(emailKeyName + user.getEmail()); if (value == null || !value.equals("success")) { observer.setEmail(user.getEmail()); observer.setUsername(user.getName()); obs.add(observer); } } else { value = jedis.get(phoneKeyName + user.getPhone()); if (value == null || !value.equals("success")) { observer.setPhone(user.getPhone()); observer.setUsername(user.getName()); obs.add(observer); } } } return obs; } /** * 將指定的觀察者列表添加到指定的主題 * * @param subject * @param list */ private void addObservers(Observable subject, List<SubscriberObserver> list) { for (SubscriberObserver obs : list) { subject.addObserver(obs); } } private void deleteObservers(Observable subject, List<SubscriberObserver> list) { for (SubscriberObserver obs : list) { subject.deleteObserver(obs); } } /** * 將列表的值作為鍵,存入redis,過期時間為48小時 * * @param list */ private void setRedisCache(List<User> users) { Jedis jedis = factory.getConnection().getNativeConnection(); for (User user : users) { if (user.getEmail()!=null) { jedis.set(emailKeyName + user.getEmail(), "success", "NX", "EX", 60 * 60 * 24 * 2); } else { jedis.set(phoneKeyName + user.getPhone(), "success", "NX", "EX", 60 * 60 * 24 * 2); } } } }
總結
代碼是不全面的,只是個示例而已。關于短信通知和郵箱通知的服務類和工具類并沒有給出,因為里面涉及到一些隱私參數。所以關于異步通知示例代碼沒有,但使用Spring管理的@Async注解和在spring進行一定的配置即可,可以在我的另外一篇博客找到關于異步通知的示例代碼。
事實上根據需求,可以使用redis的發布訂閱,或者消息隊列mq來實現類似的功能。但為了加深對設計模式的理解,所以寫了一個不是很純正的觀察者模式來模仿發布訂閱的操作。
關于“java怎么使用觀察者模式異步短信/郵箱提醒用戶群”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。