async-excel整合站内信通知用户体验感满满
前面的文章我们讲过消息中心站内信的实现 【消息中心】
那么本章我们来说说异步导入导出完成后,如何使用消息中心站内信的功能进行通知用户业务处理完成了
在async-excel中异步逻辑处理完成后会调用一个callback方法进行回调,所以我们可以再对async-excel的handler接口再做一层封装,让所有的handler继承自我们封装的这个类
此处我就讲一个导出示例
public abstract class AbstractNoticeExportHandler<T> implements ExportHandler<T> {private static final int COMPLETE = 2;private static final int FAIL = 3;@Overridepublic void callBack(ExcelContext ctx, DataParam param) {callBack0(ctx, param);Notice.NoticeBuilder noticeBuilder = Notice.builder().toUserCode(ctx.getTask().getCreateUserCode());//导出成功if (ctx.getTask().getStatus() == COMPLETE) {//导出成功if (StringUtils.isNotEmpty(ctx.getTask().getFileUrl())) {noticeBuilder.contentType(NoticeContentType.DOWNLOAD.type).title("文件导出任务已完成,任务id="+ctx.getTask().getId()).content(ctx.getTask().getFileUrl());} else {//导出成功,但是没有url代表是导出了0条的情况noticeBuilder.contentType(NoticeContentType.TEXT.type).title("文件导出任务已完成,任务id="+ctx.getTask().getId()).content(String.format("导出%s条", ctx.getSuccessCount()));}} else if (ctx.getTask().getStatus() == FAIL) {//导出失败noticeBuilder.contentType(NoticeContentType.TEXT.type).title("文件导出任务失败,任务id="+ctx.getTask().getId()).content(ctx.getTask().getFailedMessage());}NoticeHelper.send(noticeBuilder.build());}public void callBack0(ExcelContext ctx, DataParam param) {}
}
然后编写业务导出处理类继承自我们自定义的回调处理
@ExcelHandle
public class UserExportHandler implements AbstractNoticeExportHandler<UserExportModel> {@AutowiredIUserService userService;@Overridepublic void init(ExcelContext ctx, DataParam param) {ExportContext context = (ExportContext) ctx;//此处的sheetNo会被覆盖,为了兼容一个文件多sheet导出WriteSheet sheet = EasyExcel.writerSheet(0, "第一个sheet").head(UserExportModel.class).build();context.setWriteSheet(sheet);}@Overridepublic ExportPage<UserExportModel> exportData(int startPage, int limit, DataExportParam dataExportParam) {IPage<User> iPage = new Page<>(startPage, limit);IPage page = userService.page(iPage);List<UserExportModel> list = ExportListUtil.transform(page.getRecords(), UserExportModel.class);ExportPage<UserExportModel> result = new ExportPage<>();result.setTotal(page.getTotal());result.setCurrent(page.getCurrent());result.setSize(page.getSize());result.setRecords(list);return result;}
}
业务处理类还是该怎么写怎么写,所以我们来讲讲callback中做了什么事情,首先我们判断导出结果是成功还是失败,有没有异常,根据不同的类型我们包装不同的消息内容类型,如果出现异常了我们包装一个纯文本消息,如果导出正常并且有链接我们包装一个下载链接的消息最后通过消息工具类发送广播消息给mq。这个工具类有就如我们在消息中心的文章中写的那样,我们在发送前先保存下这条消息,并且异步操作,即使失败也不关业务什么事情。
public class NoticeHelper {/*** 同步日志** @param notice*/public static void send(Notice notice) {Assert.notNull(notice.getToUserCode(), "接收人不能为空");Assert.notNull(notice.getTitle(), "消息标题不能为空");Assert.notNull(notice.getContent(), "消息内容不能为空");Assert.notNull(NoticeContentType.fromValue(notice.getContentType()), "内容类型不正确");notice.setCode(BusinessCodeGenerator.getCode(BusinessCodeEnums.AUTO));notice.setHasRead(0);notice.setType(0);if (StringUtils.isEmpty(notice.getFromUserCode())) {notice.setFromUserCode("system");notice.setFromUserName("system");}doSend(notice);}private static void doSend(Notice notice) {Map<String, String> contextMap = SystemContext.getContextMap();MqSenderPool.senderExecutor.execute(()->{try {SystemContext.setContextMap(contextMap);NoticeSender sender = SpringContextUtil.getBean(NoticeSender.class);sender.send(notice);}finally {SystemContext.clearAll();}});}
}
public class NoticeSender {private final static Logger log = LoggerFactory.getLogger(NoticeSender.class);@AutowiredRabbitTemplate rabbitTemplate;@Autowired(required = false)NoticeProxy noticeProxy;public void send(Notice notice) {//发送之前保存数据异步处理try {if (noticeProxy != null) {JsonResult<Void> result = noticeProxy.saveMessage(notice);if (result.isSuccess()) {rabbitTemplate.convertAndSend(QueueConst.NOTICE_FANOUT_EXCHANGE,QueueConst.NOTICE_FANOUT_BIND_KEY, JSONUtil.toJsonStr(notice));} else {log.error("通知保存失败:{}", JSONUtil.toJsonStr(notice));//throw new BizException("消息保存失败");}}} catch (Exception e) {log.error("发送通知异常:{}", JSONUtil.toJsonStr(notice));}}
}
NoticeProxy 不多说就是通过rest调用下服务接口保存下消息
在回到之前下消息中心我们写了个消费者,监听广播消息,我消费者可能部署多个节点,所以客户端可能连接在不同的节点上,所以消费者在收到消息的时候判断下目标客户端有没有连接在当前节点,如果不存在消息直接丢弃,如果存在则发送出去。
@Component
@Slf4j
public class NoticeReceiver {private static ObjectMapper MAPPER = new ObjectMapper();@RabbitListener(queues = QueueConst.NOTICE_FANOUT_QUEUE)@RabbitHandlerpublic void receiveTopic(Message message) throws Exception {try {String receiveMsg = new String(message.getBody());Notice notice = JSONUtil.toBean(receiveMsg, Notice.class);List<Channel> channels = UserChannelContext.get(notice.getToUserCode());if (channels != null && channels.size() > 0) {for (Channel channel : channels) {if (channel != null) {channel.writeAndFlush(new TextWebSocketFrame(MAPPER.writeValueAsString(notice)));}}}} catch (Exception e) {log.error("notice接收处理错误:{}",e.getMessage());}// 补充:如果用户不在线则直接放弃;// 补充:无论如何消息消费后需要返回ack,所以此处直接catch起来}
最后的效果如下弹窗消息,并附带下载按钮
消息下拉框,圆点气泡需要联动推送的弹窗,当接收到消息时弹个窗红点数字加1,前端部分的代码也是相当简单,我就不多说了。UI用的是ant-design,前端根据不同的消息类型进行不同的展示,我们把消息分为
- 纯文本消息
- 路由消息
- 链接跳转消息
- 下载消息等等
当然下拉框的功能是通过调用单独接口实现,后端直接通知给前端的功能是触发上面那个弹窗,而下拉框是可以前端通过点击事件触发的。
消息中心站内信模块是个核心功能,后续可以依据这个功能还可以做什么呢?
- 工作台的功能实现
- 审批流的消息处理
- 程序的强制更新
- 任务的下发
- 简易的IM及时通讯
有了这个核心,系统的功能就能充满无限的遐想,并且用户体验感满满。
async-excel整合站内信通知用户体验感满满相关推荐
- 百万级用户量的站内信设计
1. 方案描述 该方案用于系统站内信功能模块在百万级用户量情况下的效率问题,只是后台管理员给前台用户发送站内信,用户与用户之间的发送不在讨论内. 2. 方案详情 假设系统的用户量达到了200W,活跃用 ...
- tp框架实现一对多单发站内信功能。
站内信功能 前言: 公司项目需要一个站内信功能,但我没做过,所以做个记录,根据需求,需要后台发送站内信,前台用户接受,默认状态保持为未读,当用户点击查看时,更改状态为已读状态,并且站内信可回复. 后台 ...
- 站内信(系统消息) 发送给所有用户
打算做一个站内信 又不想做成那种 查询所有用户 每一个用户发送一条消息 就建立了 两个数据表 进行了一下简单的优化 也不是很完善 大家 有好的方案 请多指教 CREATE TABLE `system_ ...
- 基于workerman实现的web消息推送站内信功能
流程说明 使用 web-msg-sender 作为 服务器监听程序. 客户端(浏览器)通过websocket连接 服务器监听程序. 服务器应用程序(后端) 通过curl访问 服务器监听程序,将需要推送 ...
- 单系统站内信数据库设计思路
第一版设计 需求 :单用户之间通信(融合了用户反馈需求) 数据库设计:Message内容和收发者存在一张表中 message表: 这里一条Message存两次,类似邮件服务. status:已读.未读 ...
- 基于百万级别的站内信设计
基本上现在的网站都会有站内信功能,主要分为少量(10-999用户),中量(1000-99999用户),大量(100W用户)不同的站内信架构,消耗存储空间,和效率也是不同的.这次要设计的是基于百万级别的 ...
- 站内信(我的消息)业务在我司的实践
文章目录 0.需求分析和设计 1.设计消息模板 2.设置消息跳转参数 3.保存消息至redis和数据库 4.客户端查询消息列表 0.需求分析和设计 现在的需求是需要保存用户的消息,比如老师给学生布置了 ...
- ASP.NET 实现站内信功能(点对点发送,管理员群发)
正好这段时间在研究这个功能,还是得感谢这位大神,没有他的引路,我就不可能把站内信做出来. http://www.cnblogs.com/grenet/archive/2010/03/08/168065 ...
- 开源 免费 java CMS - FreeCMS2.1 会员站内信
项目地址:http://www.freeteam.cn/ 站内信 1.1.1 写信 从左側管理菜单点击写信进入. 输入收信人.标题.内容后点击发送button. 1.1.2 收件箱 从左側管理菜单点击 ...
最新文章
- Flask入门学习---Hello,Flask!
- linux设备驱动归纳总结
- 监听门后德美恢复网监合作
- [系统安全] 二十四.逆向分析之OllyDbg调试INT3断点、反调试、硬件断点与内存断点
- mysql系列问答题_(2)MySQL运维基础知识面试问答题
- var a = b = 5 and use strict mode
- 当使用easyui时,jquery的设置disabled属性方法失效
- (C语言)二维整型数组的“最大点”(驻点)
- 简析面向对象中的继承,原型链,闭包之继承
- 一个简单的线程池设计方案
- python求解LeetCode问题之trapping rain water
- IIS DirectoryEntry
- CentOS 7安装MinDoc文档系统
- 外汇EA网格交易策略
- Myeclipse10怎么找到 Servers
- matlab中imag什么意思,Matlab基本函数-imag函数
- 蒜头君的藏书(映射)
- 微服务电商项目技术全解析
- QT中获取选中的radioButton的两种方法
- 3、计算圆形面积(蓝桥杯入门题)
热门文章
- 解决myeclipse破解运行后出现的security alert:integrity check error
- 一文告诉你数据安全平台(DSP)能做什么
- freeswitch
- Java基础练习——读心术(扑克牌魔术——21张扑克牌)
- 上海东方广播电台 动感101.7(FM101.7)在线收听
- cad角度命令怎么输入_CAD教程 | CAD大佬也是这样过来的,制图命令的输入方法及操步骤...
- Vue中使用tailwindcss
- soc验证 c语言,一种Soc芯片验证方法与流程
- win7家庭版怎么把计算机显示桌面,Win7怎样显示桌面
- MySQL语法学习笔记