ASP.NET SignalR 与LayIM配合,轻松实现网站客服聊天室(五) 补充:历史记录 和 消息提醒
有开发者提问怎么做历史记录功能和即使不打开聊天窗口有消息提醒功能。简单抽时间写了点代码。不过只是基本思路,具体细节没有实现。
正如前几篇博客中提到的,读取历史记录什么时候读取呢?按照常理,应该是打开聊天窗口的时候加载历史记录,当然也可以选择异步加载好,然后打开哪个窗口就加载哪部分的记录。当然我们并不知道用户会打开哪个窗口,所以,我还是建议,当用户选择人聊天的时候就读取历史记录。那么之前的功能已经做好了。我们需要充分利用 ctoc 方法。ctoc是什么?不明白的就看看本系列前几篇文章吧。
现在我们找到ctoc 后台方法,可以看到我添加了GetHistoryMessage方法,参数为发送人id和接收人id,那么这个GetHistoryMessage方法就是做了读取历史记录的操作,不管你从哪里读取的,是缓存还是数据库(前提是你发的消息已经保存了~~)
/// <summary> /// 人对人聊天 连接服务器 /// </summary> /// <param name="sendid">发送人</param> /// <param name="receiveid">接收人</param> /// <returns></returns> public Task ClientToClient(string sendid, string receiveid) { if (sendid == null || receiveid == null) { throw new ArgumentNullException("sendid or receiveid can't be null"); } //获取组名 string groupName = MessageUtils.GetGroupName(sendid, receiveid); //将当前用户添加到此组织内 Groups.Add(CurrentUserConnectionId, groupName); //构建系统连接成功消息 //读取历史记录 --- 2016-3-7 修改 var historyMsg = MessageUtils.GetHistoryMessage(sendid, receiveid); var msg = MessageUtils.GetSystemMessage(groupName, MessageConfig.ClientToClientConnectedSucceed, new { t = MessageConfig.ClientTypeCTC, currentid = sendid, receiveid = receiveid,history = historyMsg }); //将消息推送到当前组 (A和B聊天的组) 同样调用receiveMessage方法 return Clients.Caller.receiveMessage(msg); }
我们再来看看获取历史记录的方法都做了什么,首先他返回的消息格式一定要符合我们设计的标准。以方便兼容单条消息发送和接收
public static List<CSChatMessage> GetHistoryMessage(string sendid,string receiveid) { string groupName = GetGroupName(sendid, receiveid); List<CSChatMessage> historys = new List<CSChatMessage>(); //这里历史记录作为demo使用,可以从数据库或者缓存读取 historys.Add(new CSChatMessage { fromuser = new CSUser(groupName, null) { photo = "/photos/000.jpg", userid = int.Parse(sendid), username = "发送方的名字" }, msg = "这一条是历史记录", msgtype = CSMessageType.Custom, touser = new CSUser(groupName, null) { photo = "/photos/001.jpg", userid = int.Parse(receiveid), username = "接收方的名字" }, other = new { t = MessageConfig.ClientTypeCTC }//这里不要忘了加t参数 }); historys.Add(new CSChatMessage { touser = new CSUser(groupName, null) { photo = "/photos/000.jpg", userid = int.Parse(sendid), username = "发送方的名字" }, msg = "这一条是历史记录", msgtype = CSMessageType.Custom, fromuser = new CSUser(groupName, null) { photo = "/photos/001.jpg", userid = int.Parse(receiveid), username = "接收方的名字" }, other = new { t = MessageConfig.ClientTypeCTC }//这里不要忘了加t参数 }); historys.Add(new CSChatMessage { fromuser = new CSUser(groupName, null) { photo = "/photos/000.jpg", userid = int.Parse(sendid), username = "发送方的名字" }, msg = "这一条是历史记录", msgtype = CSMessageType.Custom, touser = new CSUser(groupName, null) { photo = "/photos/001.jpg", userid = int.Parse(receiveid), username = "接收方的名字" }, other = new { t = MessageConfig.ClientTypeCTC }//这里不要忘了加t参数 }); return historys; }
其实就加了这么一个读取历史记录的操作,我们来看看,连接成功之后,消息返回JSON。
历史记录有了,我们剩下的要做的就很简单了。修改前端处理 system 类型的消息函数。(代码在client.hub.js /chat.handleSystemMsg)
handleSystemMsg: function (result) { if (result.other.t == 'one') { this.cache[result.other.receiveid] = "ok";//代表我已经和当前聊天人已经连接上了,下次点击没必要再次连接 } else { this.cacheGroup[result.other.receiveid] = "ok"; } //然后在这里处理历史记录 2016-3-7 if (result.other.history && result.other.history.length) { $(result.other.history).each(function (i,item) { //追加消息 console.log(item); chat.handleCustomMsg(item);//每一个item就是一条消息,这里格式是通用的,所以,直接调用 handleCustomMsg方法就可以了。 }); } },
我们看一下效果:
是不是如此简单就实现了历史记录的功能,当然实际项目中,如果把滚动条上拉可以看更多的历史记录,这里就不需要signalR了,我们用一个ajax请求就可以了。
下面介绍一下,消息通知。其实消息通知的原理就是进入页面的时候需要用户连接服务器,每当有用户消息的时候就会提示。因为之前的设计思路是当用户点击某个人要聊天的时候才会连接,所以,即使用户登录了网页,也不会收到其他人给他发送的消息。所以我们要做的就是先让用户连接到服务器。我这里模拟了一下连接,就是打开窗口,然后在关闭。(此时用户处于连接状态,能够接收到消息,只不过不会在窗口显示)添加如下代码:(代码路径:client.hub.js/chat.handleCustomMsg)
if (!log.imarea.length) { //这里只有在连接过一次之后,并且关闭消息框才会提示 if (result.touser.userid == hubConfig.currentUser.id) { alert("您收到消息啦..."); } }
当对方在给我发送消息的时候就会提示啦:(PS:这里只是一个思路,具体并没有实现任何人发送消息就会提示。alert框是不是很难看,那么让你们的美工给优化一下吧。)
github 代码已经更新:https://github.com/fanpan26/LayIM/