您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)java怎么使用觀察者模式異步短信/郵箱提醒用戶群,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
需求
用戶中有人設(shè)置了賬戶余額達(dá)到閾值時(shí),短信/郵箱進(jìn)行提醒的服務(wù)。我們將需要在他賬戶余額閾值達(dá)到指定數(shù)值的時(shí)候進(jìn)行短信/郵箱消息通知,允許賬戶余額閾值出現(xiàn)偏差的時(shí)候通知,如果某個(gè)用戶48小時(shí)內(nèi)已經(jīng)短信/郵箱進(jìn)行過通知了,那么將不再進(jìn)行通知。
剖析
存在兩個(gè)主題:短信通知和郵箱通知
存在兩種觀察者:設(shè)置了短信通知且賬戶余額到達(dá)閾值的用戶,設(shè)置了郵箱通知且賬戶余額到達(dá)閾值的用戶。
用spring的定時(shí)器,每10分鐘去數(shù)據(jù)庫獲取某個(gè)主題已經(jīng)達(dá)到閾值且開始了該主題的提醒功能的用戶
用spring的@Asycn注解異步短信通知,郵箱通知的相關(guān)方法
用redis設(shè)置用戶短信/郵箱為鍵名,設(shè)置過期時(shí)間為48小時(shí)。如果獲取不到該鍵值對,說明其在觀察者行列
代碼
觀察者父類
/** * 訂閱觀察者 * @author Administrator * */ @Component //標(biāo)志為多例 @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(); //如果用拉的方式,這么調(diào)用 this.notifyObservers(); } }
/** * 短信提醒主題 * @author Administrator * */ @Component public class PhoneAlertSubject extends Observable{ public void alert(){ this.setChanged(); //如果用拉的方式,這么調(diào)用 this.notifyObservers(); } }
定時(shí)器
/** * 定時(shí)給訂閱了短信提醒和email提醒的用戶服務(wù) * @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:"; /** * 定時(shí)獲取需要email提醒的用戶,每10分鐘調(diào)用一次 */ @Scheduled(fixedDelay = 1000 * 60 * 10) public void alertEmailTask() { // 1.獲取數(shù)據(jù)庫中達(dá)到了閾值的用戶 List<User> emails = commonUserService.getUserAlertEmailAndName(); // 2.查看redis中是否有達(dá)到閾值,且48小時(shí)已經(jīng)通知的用戶,將其排除在觀察者行列,最終得出觀察者隊(duì)伍 List<SubscriberObserver> informEmail = getInformObserver(emails); // 3.創(chuàng)建主題,添加觀察者 addObservers(emailSubject, informEmail); // 4.通知 emailSubject.alert(); // 5.將已經(jīng)通知的觀察者信息存儲(chǔ)到reids內(nèi),設(shè)置過期時(shí)間為一天 setRedisCache(emails); // 6.將觀察者從主題中移除 deleteObservers(emailSubject, informEmail); } /** * 定時(shí)獲取需要短信提醒的用戶,每10分鐘調(diào)用一次 * */ @Scheduled(fixedDelay = 1000 * 60 * 10) public void alertPhoneTask() { // 1.獲取數(shù)據(jù)庫中達(dá)到了閾值的用戶 List<User> phones = commonUserService.getUserAlertPhoneAndName(); // 2.查看redis中是否有達(dá)到閾值,且今天已經(jīng)通知的用戶,將其排除在觀察者行列,最終得出觀察者隊(duì)伍 List<SubscriberObserver> informPhones = getInformObserver(phones); // 3.創(chuàng)建主題,添加觀察者 addObservers(phoneSubject, informPhones); // 4.通知 phoneSubject.alert(); // 5.將已經(jīng)通知的觀察者信息存儲(chǔ)到reids內(nèi),設(shè)置過期時(shí)間為一天 setRedisCache(phones); // 6.將觀察者從主題中移除 deleteObservers(phoneSubject, informPhones); } /** * ------------------------------------------------------------------------ * ----------------------------------------------------- **/ /** * 過濾掉今天已經(jīng)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,過期時(shí)間為48小時(shí) * * @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); } } } }
總結(jié)
代碼是不全面的,只是個(gè)示例而已。關(guān)于短信通知和郵箱通知的服務(wù)類和工具類并沒有給出,因?yàn)槔锩嫔婕暗揭恍╇[私參數(shù)。所以關(guān)于異步通知示例代碼沒有,但使用Spring管理的@Async注解和在spring進(jìn)行一定的配置即可,可以在我的另外一篇博客找到關(guān)于異步通知的示例代碼。
事實(shí)上根據(jù)需求,可以使用redis的發(fā)布訂閱,或者消息隊(duì)列mq來實(shí)現(xiàn)類似的功能。但為了加深對設(shè)計(jì)模式的理解,所以寫了一個(gè)不是很純正的觀察者模式來模仿發(fā)布訂閱的操作。
關(guān)于“java怎么使用觀察者模式異步短信/郵箱提醒用戶群”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),請把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。