前一篇文章讲到我们项目的工作流,这一篇我们扒一扒项目中的消息中心,msgcenter。消息可以分成很多种消息:留存可重复查看的DB消息,短暂保存在redis的comet消息,短信形式的msg消息,推送到手机的push消息等等。但是不管是哪种类型的消息,在我们的项目中都有统一的格式。(不管是db,msg或者是push都是一样的格式),这样就能保证存储和显示已经推送的一致性。

项目中的消息中心也是独立的模块,用maven依赖被各个网关层使用,当然简单方便,不过后来看了一篇文章,讲到微服务,我就在想是不是可以把消息模块独立出来做一个微服务,这样对消息中心做的优化就不用再修改别的网关应用了。不过这个是架构师哥哥处理的问题,我就是这么简单的想想。

废话不说,我们看msgcenter的层次

还是统一的层次,因为是模型,没有集成web层。dal是数据库持久层,domain是模型层(最接近模型的层),facade层是对外提供能力的层(外观模式,定义了对外提供能力的接口),biz是实现facade层的实例层,integration是集成其他模块的层(这一层很有意思,到时候我们单独写一篇文章介绍),test是测试层

那既然我们的消息中心是一个模型,供其他系统调用,那我们就看下facade对外提供的能力吧。

看facade层只有两个接口类(我们只关注MsgSenderFacade接口),

public interface MsgSenderFacade {
    /**
     * 发送消息
     *
     * @param list
     * @return
     */
    List<MsgBodyDTO> sendMsgs(List<MsgBodyDTO> list);

我们简单的看下发送消息的方法,系统中所有的消息调用的都是这个方法,是不是很屌,原因上面我们讲到过,不管什么类型的消息,他们都有统一的格式,那就是MsgBodyDTO,里面就是我们平常类的ID,消息模板ID,模板的替换数组,接收用户的ID,接收用户的电话号码,业务号,标题,真实内容,创建时间,更新时间,状态等等属性,我们看下实现方法

fillIdAndStatus(allMsgList);//填充ID,创建时间,初始状态等等
        Map<MsgTypeEnum, List<MsgBodyDTO>> map = splitByMsgType(allMsgList);//根据消息队列的不同消息模板,分开(之后分别处理)
        try {
            for (Map.Entry<MsgTypeEnum, List<MsgBodyDTO>> entry : map
                    .entrySet()) {
                MsgTypeEnum msgType = entry.getKey();
                List<MsgBodyDTO> msgList = entry.getValue();
                switch (msgType) {
                case COMET:
                    LogUtil.info(logger,
                            "start send comet msgs[" + msgList.size() + "]");
                    if (logger.isDebugEnabled()) {
                        LogUtil.debug(logger, JSON.toJSONString(msgList));
                    }
                    cometMsgSenderProcessor.checkParams(msgList);
                    cometMsgSenderProcessor.doSend(msgList);//不同的消息类型我们用不同的消息处理器进行验证和分发。
                    break;
                case DB:
                    LogUtil.info(logger, "start send db msgs[" + msgList.size()
                            + "]");
                    dbMsgSenderProcessor.checkParams(msgList);
                    dbMsgSenderProcessor.doSend(msgList);
                    break;
                case MSG:
                    LogUtil.info(logger,
                            "start send mobile msgs[" + msgList.size() + "]");
                    mobileMsgSenderProcessor.checkParams(msgList);
                    mobileMsgSenderProcessor.doSend(msgList);
                    break;
                case PUSH:
                    LogUtil.info(logger,
                            "start send push msgs[" + msgList.size() + "]");
                    pushMsgSenderProcessor.checkParams(msgList);
                    pushMsgSenderProcessor.doSend(msgList);
                    break;
                default:
                    throw new BizException(
                            ErrorConst.ERROR_SUCH_MESSAGE_NOT_SUPPORT,
                            "不支持当前的消息类型[" + msgType.name() + "]");
                }
            }
            return allMsgList;

这四个处理器都是Spring注入的,我们看下配置,

<bean id="mc_cometMsgSenderProcessor" class="com.opengroup.hongshi.msgcenter.biz.msgSender.processor.comet.CometMsgSenderProcessorImpl" init-method="init"></bean>
    <bean id="mc_dbMsgSenderProcessor" class="com.opengroup.hongshi.msgcenter.biz.msgSender.processor.db.DBMsgSenderProcessorImpl"></bean>
    <bean id="mc_pushMsgSenderProcessor" class="com.opengroup.hongshi.msgcenter.biz.msgSender.processor.push.PushMsgSenderProcessorImpl"></bean>
    <bean id="mc_mobileMsgSenderProcessor" class="com.opengroup.hongshi.msgcenter.biz.msgSender.processor.msg.MobileMsgSenderProcessorImpl" init-method="init">
        <property name="channelList">
            <list>
                <ref bean="mc_channel_lanliang"/>
                <ref bean="mc_channel_qxt"/>
                <ref bean="mc_channel_shiyuan"/>
                <ref bean="mc_channel_yingxiao" />
            </list>
        </property>
    </bean>

我们接下来跟进代码查看具体实现方法 以mobileMsgSenderProcessor为例:

//检查消息不能重复
        checkMsgsValid(domainMsgs);
        for (MsgBody msgBody : domainMsgs) {
            if (realSendMobileMsg) {
                MsgChannel channel = channelMap.get(msgBody.getChannelId());
                if (channel == null) {
                    StringBuilder buffer = new StringBuilder();
                    buffer.append("没有找到channelId=[").append(msgBody.getChannelId()).append("]的定义");
                    throw new CriticalSystemError(buffer.toString());
                } else {
                    String mobile = msgBody.getMobile();
                    try {
                        boolean success = channel.doSend(msgBody);
                        if (success) {
                            LogUtil.info(logger, "send mobile msg success[" + msgBody.getMobile()
                                                 + "][" + msgBody.getRealContent() + "]");
                            kvClient.save(
                                "msg_ok_" + mobile,
                                "["
                                        + DateUtil.format(new Date(),
                                            DateFormatterEnum.DATE_WITH_TIME.getCode()) + "]"
                                        + msgBody.getRealContent(), Integer.MAX_VALUE);
                        } else {
                            LogUtil.error(
                                Logs.ERROR_LOGGER,
                                "send mobile msg fail[" + msgBody.getMobile() + "]["
                                        + msgBody.getRealContent() + "]");
                        }
                    } catch (Exception e) {
                        LogUtil.error(
                            Logs.ERROR_LOGGER,
                            "send mobile msg fail[" + msgBody.getMobile() + "]["
                                    + msgBody.getRealContent() + "]", e);
                    } finally {
                        kvClient.save("msg_idx_" + mobile, msgBody.getChannelId(), 86400);
                    }
                }

标绿的channel就是代表我们当时配置的发送短信的通道,这个通道里面就是调用各大运营商的短信服务了。其实这个msgcenter比较简单,配置起来也不太麻烦。但是一开始调用的时候自己也摸不清头脑,不过一旦自己静下心来反而就看懂了,怕的就是自己浮躁。

实际项目中的消息中心相关推荐

  1. 智能家居DIY连载教程(2)——在实际项目中运用消息队列与邮箱

    前言 千呼万唤始出来,智能家居 DIY 教程连载第二篇终于登场了!本文将重点给大家介绍如何将消息队列与邮箱运用到实际项目中去.一起来看看吧~ DIY 回顾上期: 1.智能家居DIY连载教程(1)--如 ...

  2. 短信验证码整合项目中 含消息服务器(分布式项目、activeMQ

    分析 黑线:短信发送验证码的实现 红线:用户填写用户信息以及验证验证码是否正确完成注册 基本步骤(下面有详细实现: 前端controller 前端service 使用到web-user(war).se ...

  3. Vue项目中实现消息提示/报警/未读消息(铃铛加小圆点闪烁效果)

    在项目开发过程中,可能需要实现以下场景:未读消息提示.报警信息.消息通知等,这些功能往往是在页面的右上角设置一个铃铛,在铃铛或者图标的右上角显示消息数并做呼吸灯效果显示 下面分享一下这类效果的实现方法 ...

  4. vue 工作项目中 实现消息列表的 全选,反选,删除功能

    template HTML 结构 radio 我是用的vux 中的checker 组件:(这个可以改成原生radio :也可以绑定v-model) <div class="list&q ...

  5. json txt格式转换器_SpringBoot项目中如何定制HTTP消息转换器

    本文首发于个人网站:Spring Boot项目中如何定制HTTP消息转换器,如需转载,请注明来源 在构建RESTful数据服务过程中,我们定义了controller.repositories,并用一些 ...

  6. Unity最简单的消息中心

    using UnityEngine; using System.Collections; using System.Collections.Generic;public class MessageCe ...

  7. 仿微博消息中心的系统设计与实现

    最近在实现一个类似于微博.网易云的消息中心模块.主要实现的功能是,将系统中的点赞.评论.@等消息做汇合.今天跟大家分享下,我们的设计和实现思路. 首先说明,我们目前是微服务的架构.所以本篇文章中对于消 ...

  8. 消息中心(系统消息)实现

    需求 用户能即时的收到来自系统或者其他用户发来的消息,在web界面右下角弹窗提醒,用户还能标记消息是否已阅状态. 即时通讯 概念:即时通讯(实时通信,Instant Messaging,简称IM)是一 ...

  9. 聊聊消息中心的设计与实现逻辑

    厌烦被消息打扰,又怕突然间的安静: 一.业务背景 微服务的架构体系中,会存在很多基础服务,提供一些大部分服务都可能需要的能力,比如文件管理.MQ队列.缓存机制.消息中心等等,这些服务需要提供各种可以复 ...

最新文章

  1. 鸿蒙霸榜GitHub,从最初的Plan B到“取代Android”?
  2. JVM:StringTable
  3. php mysqli参数,PHP5 mysqli 绑定参数
  4. python_day2基本数据类型
  5. iOS 获取本地图片URL
  6. Python 中的 import 与 from import 区别
  7. scanf_s 发送访问冲突_程序员如何解决并发冲突的难题?
  8. HDOJ(HDU) 2502 月之数(进制)
  9. 被面试官问的Android问题难倒了,系列篇
  10. mysql临时关闭索引功能_MYSQL中常用的强制性操作(例如强制索引)
  11. 此 sqltransaction 已完成;它再也无法使用_win10笔记本自带office报错无法激活的解决方法...
  12. HRESULT是什么,应该如何理解
  13. Matlab中数组的常见用法
  14. 8926平台boot过程分析
  15. 取消改写模式(python)
  16. java swing 毛玻璃_实时、动态的毛玻璃(aero)效果,javaSwing 实现的,用的是高斯模糊算法...
  17. 闲置台式机+文件服务器,闲置电脑打造NAS:安装群晖NAS系统
  18. Redis【2022最新面试题】
  19. 【12.3】call_soon、call_at、call_later、call_soon_threadsafe
  20. MyBatisPlus--多数据源

热门文章

  1. mysql锁表查询和解锁操作
  2. 【MySQL】MySQL中的表锁
  3. 基恩士KV7500,基恩士触摸屏,搭载KV-SH04PL四轴运动控制模块,KV-C32XDT.
  4. 单片机C语言数据存储原理,学习单片机C语言,必知的数据存储与程序编写知识!...
  5. 研究生招生信息网服务器异常,2012研究生网上报名常见问题汇总
  6. python实时显示图片_任何显示来自Cam的实时图像的快速Python GUI
  7. AWVS14.1安装
  8. Numpy之数据归一化
  9. 服务器被一堆系统登录_饥荒联机云服务器开档
  10. Java API常用package介绍