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

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 应用场景:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象 都得到通知并被自动更新。如在舆情系统中发现有客户给出差评,就需要2小时内给相应的负责人发送短信通知,在客流系统中,人数超过预警值需要发送短信提醒相关负责人并记录到预警流水表中...
应用场景:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象
都得到通知并被自动更新。如在舆情系统中发现有客户给出差评,就需要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;
 
    @Autowired
    private IZNoticeWarnService noticeWarnService;
 
    @Override
    public 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);否则会就报空指针异常

    @Autowired
private SubscriberObserver observer;
@Autowired
private NoticeWarnSubject noticeWarnSubject;
@Autowired
private 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);
        }
    }
以上就是观察者模式来实现短信通知和预警日志记录的操作步骤了。
--------------------- 
作者:朱培 
来源:CSDN 
原文:https://blog.csdn.net/sdksdk0/article/details/85061646 
版权声明:本文为博主原创文章,转载请附上博文链接!
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
7月前
|
调度
等待和通知
等待和通知
|
7月前
|
弹性计算 安全 机器人
一键搞定定时自动化通知
您是否经常忘了需要每周要填报工作时长?您的团队是否需要每月定时盘点HC?您是否每月末都在工作群提醒大家更新OKR? 这些简单的定时任务是不是经常会忘记或者占用您的精力?如果你也有这些烦恼,是时候来试试这个应用与数据集成平台——阿里云计算巢AppFlow了,它能够像一个神经中枢,高效地串联起所有关键数据流,并且能够巧妙地运用现代化的通讯工具如钉钉群机器人,实现定时消息通知,让每一个重要信息都能准时送达,不再因为简单重复的定时工作而占用您的时间和精力~
|
SQL JSON Prometheus
14-TDengine安装报警模块实现报警监测Webhook回调与邮件推送
14-TDengine安装报警模块实现报警监测Webhook回调与邮件推送
602 0
14-TDengine安装报警模块实现报警监测Webhook回调与邮件推送
|
1月前
|
存储 监控 安全
邮件告警通知
【10月更文挑战第20天】
|
资源调度 运维 Java
定时任务报警通知解决方案详解
随着微服务和云计算的兴起,定时任务技术也是发展迅速,不仅能做单机的定时任务,而且在分布式系统下应用也很广泛,成为了业务做兜底、数据处理的第一选择。
2578 3
定时任务报警通知解决方案详解
|
监控
限制SLS告警通知时段的几种常见方法
在对系统进行监控告警的过程中,有时候并非在任何时候都要接收告警通知,本文会介绍几种常见的限制告警通知时段的方法,以及它们各自所适用的场景。
424 0
限制SLS告警通知时段的几种常见方法
|
安全 网络安全 开发者
紧急事件的告警通知|学习笔记
快速学习紧急事件的告警通知
146 0
|
Prometheus 监控 Cloud Native
5分钟理解SLS告警通知时机
SLS告警支持丰富的告警管理功能,例如合并抑制静默等功能,跟SLS旧版告警相比增加了很多告警降噪抑制的功能,和用户管理,值班组和可定制复用的内容模板功能。在使用的过程中,因为增加了告警的降噪功能,从告警产生到发送通知这个过程增加了一个告警降噪的过程;因为降噪机制的存在,可能会出现告警触发但不一定会立即发出通知的情况。了解SLS告警通知时机将有助于理解这些情况。
861 0
5分钟理解SLS告警通知时机