实际项目中的消息中心
前一篇文章讲到我们项目的工作流,这一篇我们扒一扒项目中的消息中心,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比较简单,配置起来也不太麻烦。但是一开始调用的时候自己也摸不清头脑,不过一旦自己静下心来反而就看懂了,怕的就是自己浮躁。
实际项目中的消息中心相关推荐
- 智能家居DIY连载教程(2)——在实际项目中运用消息队列与邮箱
前言 千呼万唤始出来,智能家居 DIY 教程连载第二篇终于登场了!本文将重点给大家介绍如何将消息队列与邮箱运用到实际项目中去.一起来看看吧~ DIY 回顾上期: 1.智能家居DIY连载教程(1)--如 ...
- 短信验证码整合项目中 含消息服务器(分布式项目、activeMQ
分析 黑线:短信发送验证码的实现 红线:用户填写用户信息以及验证验证码是否正确完成注册 基本步骤(下面有详细实现: 前端controller 前端service 使用到web-user(war).se ...
- Vue项目中实现消息提示/报警/未读消息(铃铛加小圆点闪烁效果)
在项目开发过程中,可能需要实现以下场景:未读消息提示.报警信息.消息通知等,这些功能往往是在页面的右上角设置一个铃铛,在铃铛或者图标的右上角显示消息数并做呼吸灯效果显示 下面分享一下这类效果的实现方法 ...
- vue 工作项目中 实现消息列表的 全选,反选,删除功能
template HTML 结构 radio 我是用的vux 中的checker 组件:(这个可以改成原生radio :也可以绑定v-model) <div class="list&q ...
- json txt格式转换器_SpringBoot项目中如何定制HTTP消息转换器
本文首发于个人网站:Spring Boot项目中如何定制HTTP消息转换器,如需转载,请注明来源 在构建RESTful数据服务过程中,我们定义了controller.repositories,并用一些 ...
- Unity最简单的消息中心
using UnityEngine; using System.Collections; using System.Collections.Generic;public class MessageCe ...
- 仿微博消息中心的系统设计与实现
最近在实现一个类似于微博.网易云的消息中心模块.主要实现的功能是,将系统中的点赞.评论.@等消息做汇合.今天跟大家分享下,我们的设计和实现思路. 首先说明,我们目前是微服务的架构.所以本篇文章中对于消 ...
- 消息中心(系统消息)实现
需求 用户能即时的收到来自系统或者其他用户发来的消息,在web界面右下角弹窗提醒,用户还能标记消息是否已阅状态. 即时通讯 概念:即时通讯(实时通信,Instant Messaging,简称IM)是一 ...
- 聊聊消息中心的设计与实现逻辑
厌烦被消息打扰,又怕突然间的安静: 一.业务背景 微服务的架构体系中,会存在很多基础服务,提供一些大部分服务都可能需要的能力,比如文件管理.MQ队列.缓存机制.消息中心等等,这些服务需要提供各种可以复 ...
最新文章
- 鸿蒙霸榜GitHub,从最初的Plan B到“取代Android”?
- JVM:StringTable
- php mysqli参数,PHP5 mysqli 绑定参数
- python_day2基本数据类型
- iOS 获取本地图片URL
- Python 中的 import 与 from import 区别
- scanf_s 发送访问冲突_程序员如何解决并发冲突的难题?
- HDOJ(HDU) 2502 月之数(进制)
- 被面试官问的Android问题难倒了,系列篇
- mysql临时关闭索引功能_MYSQL中常用的强制性操作(例如强制索引)
- 此 sqltransaction 已完成;它再也无法使用_win10笔记本自带office报错无法激活的解决方法...
- HRESULT是什么,应该如何理解
- Matlab中数组的常见用法
- 8926平台boot过程分析
- 取消改写模式(python)
- java swing 毛玻璃_实时、动态的毛玻璃(aero)效果,javaSwing 实现的,用的是高斯模糊算法...
- 闲置台式机+文件服务器,闲置电脑打造NAS:安装群晖NAS系统
- Redis【2022最新面试题】
- 【12.3】call_soon、call_at、call_later、call_soon_threadsafe
- MyBatisPlus--多数据源
热门文章
- mysql锁表查询和解锁操作
- 【MySQL】MySQL中的表锁
- 基恩士KV7500,基恩士触摸屏,搭载KV-SH04PL四轴运动控制模块,KV-C32XDT.
- 单片机C语言数据存储原理,学习单片机C语言,必知的数据存储与程序编写知识!...
- 研究生招生信息网服务器异常,2012研究生网上报名常见问题汇总
- python实时显示图片_任何显示来自Cam的实时图像的快速Python GUI
- AWVS14.1安装
- Numpy之数据归一化
- 服务器被一堆系统登录_饥荒联机云服务器开档
- Java API常用package介绍