观察者模式实现报表实时更新

前提

       最近重构的项目涉及到很多报表的统计,重构之前报表的数据更新为每小时更新一次,这次重构过程希望可以做到实时更新,一方面可以减少测试成本,另一方面从根本上提供用户体验度。其实做实时查询,业界有很多成熟的方案,最近最常用的就是es,solr等搜索引擎,小编这次的项目数据量从零开始,短时间内容达不到那么高,其次能用技术方案解决就尽可能减少设备的投入,尽可能减少成本。

需求现状

       报表的统计数据以天为维度,隔天的数据存在发生变动的可能,隔天如果存在改动则需要更新报表,而且隔天修改数据的量比较小,希望做到每天的数据都可以每小时实时更新,最好实时更新。

落地方案

在开发过程不断重构改善,迭代几个方案

1、实时从数据库中抓取,计算做到实时更新(潜在风险,系统运行一段时间可能就要用其他方案来优化)

2、保持和重构之前一样,无论哪天的数据均小时为维度更新(实现最简单,定时任务+数据缓存即可)

3、利用数据库新增统计表,隔天的数据落库保存,当天数据实时计算(效果,当前数据实时变动,隔天的数据小时维度更新)

4、利用数据库统计表+观察者模式,实现实时更新(无需考虑数据库数据量大后,系统运行缓慢问题)

小编主要说一下最后一种落地方案

       隔天的数据利用观察者模式进行更新数据库统计表中数据,统计隔天的数据可以减少数据表中统计次数,避免不必要的资源浪费,报表查询利用统计数据+当前数据实时查询(当前数据量有限,数据级别可以实时查询),组合两者结果即真正的报表显示数据。

       利用观察者模式实现消息订阅,监听工单保存动作(被观察者),多张报表统计(观察者),当工单数据发生变化完成保存操作后异步通知观察者,多个报表作为的观查均能收到消息,根据新旧工单,自主更新工单数据。利用观察者模式,可以降低工单数据变动和报表的耦合,而且便于扩展,新增报表时只需新增一个观察者即可。

//被观察者
public class WorkOrderSubject {
    //观察者队列
    List<IWorkOrderObserver> observerList;

    public void setObserverList(List<IWorkOrderObserver> observerList) {
        this.observerList = observerList;
    }

    public void notifyObserver(WorkOrder oldWorkOrder, WorkOrder newWorkOrder) {
        if (CollectionUtil.isNotEmpty(observerList) && !CallDateUtils.isToday(oldWorkOrder.getCreateTime())) {
            observerList.forEach(observer -> observer.updateReport(oldWorkOrder, newWorkOrder));
        }
    }

注册者注册利用bean的xml进行注册

 <bean id="reportResourceService" class="com.service.report.impl.ReportResourceServiceImpl"/>
    <bean id="reportCallAnalyseService" class="com.service.report.impl.ReportCallAnalyseServiceImpl"/>

    <bean id="workOrderSubject" class="com.service.report.WorkOrderSubject">
        <property name="observerList">
            <list>
                <ref bean="reportCallAnalyseService"/>
                <ref bean="reportResourceService"/>
            </list>
        </property>
    </bean>

具体观察者

public class ReportCallAnalyseServiceImpl implements IReportCountService<CallAnalyseRes>, IWorkOrderObserver{

  /**
     * 定时任务每天执行一次,新增到报表中
     * @return
     */
    boolean batchInsertReport(Map<Integer, LocalDateTime> timeRange,int reportDay){
        //实现省略
    }


    /**
     * 查询城市、坐席,渠道 报表
     * @param reportWorkOrderReq
     * @return
     */
    List<T> queryReportByType(ReportReq.ReportWorkOrderReq reportWorkOrderReq){
        //实现省略
    }

 /**
     * 根据修改该内容自动更新
     * @param oldWorkOrder
     * @param newWorkOrder
     */
    void updateReport(WorkOrder oldWorkOrder, WorkOrder newWorkOrder){
        //实现省略
    }
}

工单保存通知订阅者

public boolean saveWorkOrder(TempWorkOrder tempWorkOrder){
//其他逻辑省略
//异步通知订阅者
taskExecutor.execute(() -> workOrderSubject.notifyObserver(oldWorkOrder, workOrder));
}

总结

      代码就是一个不断重构的过程,有些复杂的逻辑大部分情况不能一步到位,只有不断的迭代,重构,才能做到更好。很多内容除了想象,脚踏实地可能会更重要。

       好久不写博客,都生疏了,之前每周一篇习惯,更会让人有积极向上的动力,丢掉的都会慢慢找回来的,坚信我能变成原来自己喜欢的样子。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mandy_i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值