---------------------------------------------------------------------------------------------
[版权申明:本文系作者原创,转载请注明出处] 
文章出处:https://blog.csdn.net/sdksdk0/article/details/85061646

作者:朱培      ID:sdksdk0     
--------------------------------------------------------------------------------------------

应用场景:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象
都得到通知并被自动更新。如在舆情系统中发现有客户给出差评,就需要2小时内给相应的负责人发送短信通知,在客流系统中,人数超过预警值需要发送短信提醒相关负责人并记录到预警流水表中。

特点:一般由两个角色组成:发布者和订阅者(观察者)。观察者通常有一个回调,也可以没有。例如可以适用于监听器、日志收集、短信通知、邮件通知等场景。

在Java中通过Observable类和Observer接口实现了观察者模式。一个Observer对象监视着一个Observable对象的变化,
当Observable对象发生变化时,Observer得到通知,就可以进行相应的工作。
java.util.Observable中有两个方法对Observer特别重要,一个是setChange()方法用来设置一个内部标志位注明数据发
生了变化;一个是notifyObservers()方法会去调用一个列表中所有的Observer的update()方法,通知它们数据发生了变化。
Observer通过Observable的addObserver()方法把自己添加到这个列表中。这个列表虽然由Observable拥有,但
Observable并不知道到底有哪些Observer正在观察等待通知。Observable只提供一个方法让Observer能把自己添加进列表,
并保证会去通知Observer发生了变化。通过这种机制,可以有任意多个Observer对Observable进行观察,而不影响
Observable的实现。

1、预警类型

public enum WarnTypeEnum {COMMENT,KELIU;}

2、订阅观察者

@Component
public class SubscriberObserver implements Observer{private Map<String, Object> param;private AScenic scenic;private Integer count;private WarnTypeEnum type;@Autowiredprivate IZNoticeWarnService noticeWarnService;@Overridepublic void update(Observable o, Object arg) {if(o instanceof NoticeWarnSubject){noticeWarnService.onSaveNoticeWarn(param,scenic,count,type);}if(o instanceof SMSWarnSubject){noticeWarnService.onSendSMSWarn(param,scenic,count,type);}}public WarnTypeEnum getType() {return type;}public void setType(WarnTypeEnum type) {this.type = type;}public Map<String, Object> getParam() {return param;}public void setParam(Map<String, Object> param) {this.param = param;}public AScenic getScenic() {return scenic;}public void setScenic(AScenic scenic) {this.scenic = scenic;}public Integer getCount() {return count;}public void setCount(Integer count) {this.count = count;}public SubscriberObserver() {super();}}

3、主题对象

@Component
public class SMSWarnSubject extends Observable{public void update(){this.setChanged();this.notifyObservers();}
}
@Component
public class NoticeWarnSubject extends Observable{public void update(){this.setChanged();this.notifyObservers();}
}

4、业务实现,进行短信发送操作(这里只是伪代码,不能直接运行),也要和增加的业务对相应的处理

public void onSendSMSWarn(Map<String, Object> c, AScenic sc, int count, WarnTypeEnum type) {try {if(type.equals(WarnTypeEnum.COMMENT)){if (null!=c&&!StringUtils.isEmpty(c.get("phone").toString())) {String[] param={c.get("name").toString(),c.get("num").toString()};new SmsUtils(c.get("phone").toString(), properties.getSmsCommId(), param).start();}}else if(type.equals(WarnTypeEnum.KELIU)){if (null!=sc&&!StringUtils.isEmpty(sc.getPhone())) {String[] param={sc.getName(),count+""};new SmsUtils(sc.getPhone(), properties.getSmsPersonId(), param).start();} }} catch (Exception e) {e.printStackTrace();}}

5、在定时器中使用,因为我这里使用了一个int类型的count这个参数,所以不能为空,默认可以加个0,例如observer.setCount(0);否则会就报空指针异常

    @Autowiredprivate SubscriberObserver observer;@Autowiredprivate NoticeWarnSubject noticeWarnSubject;@Autowiredprivate SMSWarnSubject  smsWarnSubject;//景区舆情预警,观察者模式@Scheduled(cron="0 */20 * * * ?")public void scenicCommentWarn() throws NoSuchMethodException, SecurityException {log.info("舆情预警V2  start......");List<SubscriberObserver> warnInfo = getCommentInformObserver();addObservers(noticeWarnSubject, warnInfo); //保存到未读通知中addObservers(smsWarnSubject, warnInfo);//发送舆情预警短信通知noticeWarnSubject.update();smsWarnSubject.update();deleteObservers(noticeWarnSubject, warnInfo);deleteObservers(smsWarnSubject, warnInfo);log.info("舆情预警V2  end......");}//客流预警@Scheduled(cron="0 */20 * * * ?")//20分钟一次客流预警public void scenicPersonWarn() {log.info("客流预警V2  start......");List<SubscriberObserver> warnInfo = getKeliutInformObserver();addObservers(noticeWarnSubject, warnInfo); //保存到未读通知中addObservers(smsWarnSubject, warnInfo);//发送客流预警短信通知noticeWarnSubject.update();smsWarnSubject.update();deleteObservers(noticeWarnSubject, warnInfo);deleteObservers(smsWarnSubject, warnInfo);log.info("客流预警V2  end......");}private List<SubscriberObserver> getKeliutInformObserver() {List<SubscriberObserver> obs = new ArrayList<SubscriberObserver>();Calendar cal = Calendar.getInstance(); List<AScenic> list=mapper.selectListByType(1);String endTime = DateUtil.format(cal.getTime(), "yyyy-MM-dd HH:mm:ss");cal.add(Calendar.MINUTE, -20);String beginTime = DateUtil.format(cal.getTime(), "yyyy-MM-dd HH:mm:ss");for (AScenic sc : list) { int count = passengerCountMapper.selectMaxCountBySecond(sc.getName(),beginTime,endTime);if(count>=sc.getWarnNum()){//触发预警observer.setCount(count);observer.setScenic(sc);observer.setType(WarnTypeEnum.KELIU);obs.add(observer);}}     return obs;}private List<SubscriberObserver> getCommentInformObserver() {List<SubscriberObserver> obs = new ArrayList<SubscriberObserver>();Calendar cal = Calendar.getInstance();String endTime = DateUtil.format(cal.getTime(), "yyyy-MM-dd HH:mm:ss");cal.add(Calendar.HOUR, -2);String beginTime = DateUtil.format(cal.getTime(), "yyyy-MM-dd HH:mm:ss");//查询这两个小时新产生的差评条数List<Map<String,Object>> selectCommentListTask = commentMapper.selectCommentListWarnTask(null,null,null, null, beginTime, endTime, 0, 2, null);for(Map<String,Object> c:selectCommentListTask){observer.setParam(c);observer.setCount(0);observer.setType(WarnTypeEnum.COMMENT);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);}}

以上就是观察者模式来实现短信通知和预警日志记录的操作步骤了。

使用观察者模式进行短信通知、预警日志记录相关推荐

  1. Oracle中预警表,Oracle DB 查看预警日志

    "Database(数据库)"主页>"Related Links相关链接)"区域> "Alert Log Content (预警日志内容) ...

  2. 论文系统Step1:从日志记录中提取特定信息

    论文系统Step1:从日志记录中提取特定信息 前言 论文数据需要,需要实现从服务器日志中提取出用户的特定交互行为信息.日志内容如下: 自己需要获取"请求数据包一行的信息"及&quo ...

  3. 度量,跟踪和日志记录

    今天,我有幸参加了2017年的分布式追踪峰会,其中有很多来自AWS / X-Ray,OpenZipkin,OpenTracing,Instana,Datadog,Librato等公司的人员,我很遗憾我 ...

  4. log4j日志记录级别是如何工作?

    级别p的级别使用q,在记录日志请求时,如果p>=q启用.这条规则是log4j的核心.它假设级别是有序的.对于标准级别它们关系如下:ALL < DEBUG < INFO < WA ...

  5. 小巧的日志记录组件 - 开源研究系列文章

    今天给大家带来一个小巧的日志记录组件LogHelper.这个组件是由Log4Net这个组件的由来而来的,不过只是写入.txt文本文件而已.如果能够对大家的项目有帮助那就更好了. 首先,打开.SLN解决 ...

  6. 集成服务入门(实验9)日志记录和邮件通知

    在默认情况下,所有的SSIS任务都可以触发事件并且被"执行结果"选项卡捕获.也可以有选择性的捕获部分事件并且记录到SSIS日志记录. 为了获知任务执行是否成功,可以通过添加一个&q ...

  7. 日志记录组件[Log4net]详细介绍(转)

    一 Log4net简介 Log4net是基于.net开发的一款非常著名的记录日志开源组件.他最早是2001年7月由NeoWorks Limited启动的项目,基本的框架源于另外的一个非常著名的姐妹组件 ...

  8. 自定义注解妙用,一行代码搞定用户操作日志记录,你学会了吗?

    来源:https://blog.csdn.net/yjt520557/article/details/85099115 | 简介 我在使用spring完成项目的时候需要完成记录日志,我开始以为Spri ...

  9. php实现项目的日志记录功能,tp5框架使用composer实现日志记录功能示例

    本文实例讲述了tp5框架使用composer实现日志记录功能.分享给大家供大家参考,具体如下: tp5实现日志记录 1.安装 psr/log composer require psr/log 它的作用 ...

  10. 配置Haproxy增加日志记录功能

    2019独角兽企业重金招聘Python工程师标准>>> CentOS 7上yum安装的Haproxy,默认没有记录日志.需要做一下配置才能记录日志. 1.创建日志文件/var/log ...

最新文章

  1. 转]网络上收集的Visual Studio 2008的一些小技巧
  2. 业务分析之--权限管理
  3. hdu1428(spfa与记忆化搜索)
  4. 2014_anshan_onsite
  5. arcgis字段计算器利用python按两列要求编号
  6. 飞鸽传书mayfish 数据入库验证
  7. pcb板可挖孔吗_PCB板微孔加工方法之机械钻孔
  8. java正则过滤小括号,java正则表达式获取大括号小括号内容并判断数字和小数亲测可用...
  9. linux常用vim命令大全,Linux基础入门 vim常用命令详解
  10. 告别码公式的痛苦,公式OCR终于来了!
  11. 下载文件HTTP请求及处理过程
  12. 软考——中级软件设计师备考建议
  13. docker操作记录-6
  14. 流年里写给30岁的自己
  15. android 控制空调,控制精灵空调遥控器
  16. 网络策略(networkpolicy随笔记)
  17. Win10截图和草图无法使用怎么办
  18. C语言输入三角形三条边边长 算三角形面积
  19. python画图颜色代码rgb_如何获取matplotlib颜色方案的RGB值?
  20. AM Best将中国再保险(集团)股份有限公司及其子公司的发行人信用评级展望调整为正面,并确认中国再保险(香港)股份有限公司的信用评级

热门文章

  1. IT学习网站,各大主流网站
  2. 感性负载,容性负载,阻性负载
  3. flask-uploads上传插件上传文件
  4. 手机传感器你知道多少个?
  5. 摄影测量空间后方交会python实现
  6. 浏览网页隐藏图片 html,Html、Js实现网页图片切换及隐藏
  7. matlab二极管伏安特性,基于Matlab对Spice二极管特性受温度影响的研究
  8. Electron入门——代码压缩与打包exe文件
  9. 服务器装win7没有硬盘模式,联想电脑BIOS里硬盘的SATA,AHCI模式里面怎么没有I...-联想p310工作站装win7,联想电脑工作站...
  10. 【汇编】更灵活的定位内存地址方式——and,or命令、SI、DI变址寄存器、直接寻址[idata]、寄存器间接寻址[bx]、寄存器相对寻址[bx+idata]、基址变址寻址、相对基址变址寻址