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

本文涉及的产品
日志服务 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 
版权声明:本文为博主原创文章,转载请附上博文链接!
相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
目录
相关文章
|
存储 网络协议 数据安全/隐私保护
POP3/SMTP/IMAP邮件协议的区别
POP3/SMTP/IMAP邮件协议的区别
POP3/SMTP/IMAP邮件协议的区别
|
9月前
|
存储 算法 安全
.NET 平台 SM2 国密算法 License 证书生成深度解析
授权证书文件的后缀通常取决于其编码格式和具体用途。本文档通过一个示例程序展示了如何在 .NET 平台上使用国密 SM2 算法生成和验证许可证(License)文件。该示例不仅详细演示了 SM2 国密算法的实际应用场景,还提供了关于如何高效处理大规模许可证文件生成任务的技术参考。通过对不同并发策略的性能测试,开发者可以更好地理解如何优化许可证生成流程,以满足高并发和大数据量的需求。 希望这段描述更清晰地传达了程序的功能和技术亮点。
1066 14
.NET 平台 SM2 国密算法 License 证书生成深度解析
|
8月前
|
数据处理
鸿蒙开发:ArkTs字符串string
字符串类型是开发中非常重要的一个数据类型,除了上述的方法概述之外,还有String对象,正则等其他的用处,我们放到以后得篇章中讲述。
449 19
|
12月前
|
SQL 自然语言处理 数据库
XiYan-SQL:一种多生成器集成的Text-to-SQL框架
XiYan-SQL 是一种创新的多生成器集成Text-to-SQL框架,通过M-Schema增强模型对数据库结构的理解,结合ICL与SFT方法提升SQL生成质量和多样性,经实验证明在多个数据集上表现优异,特别是在Spider和SQL-Eval上取得了领先成绩。
2059 7
|
存储 Linux 数据库
云计算的体系结构
云计算的体系结构由5部分组成,分别为应用层,平台层,资源层,用户访问层和管理层,云计算的本质是通过网络提供服务,所以其体系结构以服务为核心。 如下图: 1,资源层 资源池层是指基础架构屋面的云计算服务,这些服务可以提供虚拟化的资源,从而隐藏物理资源的复杂性。
4713 0
|
存储 Java 数据建模
基于 SpringBoot+Vue 的网上图书商城管理系统(附源码,教程)上
基于 SpringBoot+Vue 的网上图书商城管理系统(附源码,教程)
|
监控 安全 Java
手把手带你实战 AGP 7.x ASM 字节码插桩
本文介绍了如何使用 AGP 7.0 推荐的 Transform Action API 来实现 ASM 插桩。
1812 0
手把手带你实战 AGP 7.x ASM 字节码插桩
|
Web App开发 缓存 运维
CentOS命令大全:从入门到精通
CentOS命令大全:从入门到精通
1763 1
|
定位技术 API
高德导航断网后恢复网络不重新规划路径问题及解决方案
高德导航断网后恢复网络不重新规划路径问题及解决方案
649 0
|
测试技术 开发工具 git
【git 实用指南】Git提交指南:如何制定团队友好的提交规则
【git 实用指南】Git提交指南:如何制定团队友好的提交规则
641 0