看起来挺简单,细节还是很多的,好,接上一篇,我们已经成功连接singalR服务器了,那么剩下的内容呢,就是一步一步实现聊天功能。

  我们先看看缺什么东西

  1. 点击好友弹框之后,要给服务器发消息,进入组Group.Group原理在上一篇已经介绍了,这里不再赘述。
  2. 点击发送消息到后台,后台在传送回来
  3. 将htmlappend到相应元素上,demo已经实现了,我们把代码拿过来用就可以了
  4. 模拟用户登录,点击发送聊天

  在做上述工作之前,还是要做许多准备工作的。我们分析一下界面元素

  

  好的,可以看到,一个消息里面有消息发送时间(addtime),用户名(username),用户头像(userphoto),用户消息体(msgcontent),除此之外还需要用户id,聊天id,以及组名(groupname).以此我先在后台建立模型。

  

namespace LayIM.Model
{public enum CSMessageType{System = 1,//系统消息,出错,参数错误等消息Custom = 2 //普通消息,对话,或者群组消息
    }
}

namespace LayIM.Model
{public class CSChatMessage{public CSChatMessage() {addtime = DateTime.Now.ToString("HH:mm:ss");}/// <summary>/// 消息来源/// </summary>public CSUser fromuser { get; set; }public CSUser touser { get; set; }/// <summary>/// 消息内容/// </summary>public string msg { get; set; }/// <summary>/// 消息发送时间/// </summary>public string addtime { get; set; }/// <summary>/// 消息类型/// </summary>public CSMessageType msgtype { get; set; }public object other { get; set; }}
}

namespace LayIM.Model
{public class SingalRUser{protected string _groupName { get; set; }private string _connectionId { get; set; }/// <summary>/// 用户当前所在组/// </summary>public string groupname{get{return this._groupName;}}/// <summary>/// 用户当前所在connectionid/// </summary>public string connectionid{get{return this._connectionId;}}public SingalRUser(string groupName, string connectionId){_groupName = groupName;_connectionId = connectionId;}public SingalRUser() { }}/// <summary>/// 用户Model/// </summary>public class CSUser : SingalRUser{public CSUser(string groupName, string connectionId) :base(groupName, connectionId){}/// <summary>/// 用户id/// </summary>public int userid { get; set; }/// <summary>/// 用户昵称/// </summary>public string username { get; set; }/// <summary>/// 用户头像/// </summary>public string photo { get; set; }}
}

  ok,很简单的几个model,CSUser为用户,CSChatMessage为消息体。那么,如果想让两个用户联通,我们需要得到他们所在的组,即经常说到的 userID1+userID2,生成组名代码如下:(主要保证两个用户的组名唯一性就可,方法随意)

    /// <summary>/// 根据两个用户ID得到对应的组织名称/// </summary>/// <param name="sendid">发送人(主动联系人)</param>/// <param name="receiveid">接收人(被动联系人)</param>/// <returns></returns>public static string GetGroupName(string sendid, string receiveid){/*排序的目的就是为了保证,无论谁连接服务器,都能得到正确的组织ID*/int compareResult = string.Compare(sendid, receiveid);if (compareResult > 0) {//重新排序 如果sendid>receiveidreturn string.Format("G{0}{1}", receiveid, sendid);}return string.Format("G{0}{1}", sendid, receiveid);}

现在groupName也有了,我们回到 CustomServiceHub 类中来。添加用户加入组的方法,这个方法什么时候调用呢,就是当你点击某个用户头像弹出聊天框的时候调用。

/// <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);//构建系统连接成功消息var msg = MessageUtils.GetSystemMessage(groupName, MessageConfig.ClientToClientConnectedSucceed, new { currentid = sendid, receiveid = receiveid });//将消息推送到当前组 (A和B聊天的组) 同样调用receiveMessage方法return Clients.Caller.receiveMessage(msg);}

  里面有些代码是我封装的,大体看清思路就可以了。下面去读一下layim.js里的源代码,找到弹出用户窗口那一段。

 //弹出聊天窗config.chatings = 0;node.list.on('click', '.xxim_childnode', function () {var othis = $(this);//当前登录用户idvar currentid = config.user.id;//取得被点击的用户idvar receiveid = othis.data('id');//调用signalR封装的方法,连接服务器,将发送人id,接收人id传给后台,当前用户加入组
            csClient.server.ctoc(currentid, receiveid);xxim.popchatbox(othis);});

  在看一下csClient到底做了什么

 ctoc: function (sid, rid) {//调用hub的clientToClient方法if (!chat.isConnected(rid)) {//如果没有连接过,进行连接console.log("用户 " + rid + "没有连接过...");_this.proxy.proxyCS.server.clientToClient(sid, rid);} else {console.log("用户 " + rid + "已经连接过了,不需要连接了...");}},

  这里呢,我另外加了个js对象缓存,防止每次点击都要重复连接数据库,当然,页面刷新之后缓存消失,需要重新 连。到这里我们点击一下,看看效果。

  好,从上图可以看到,服务器返回了成功的消息,并且,groupname也是按照顺序生成的。这个消息有什么用呢,其实对于客户端是没有什么效果的,如果想要提示用户连接成功或者提示对方是否在线可以用到,这里我不在扩展,只是为了打印看是否连接成功,当连接成功之后呢,用户就会存在组 G1000010003中了,这时候你发消息如果对面没有连接的话,他是看不见的。连接成功之后,就要做发消息功能了。继续回到 CustomServiceHub 类,添加发送消息方法:

/// <summary>/// 发送消息 ,服务器接收的是CSChatMessage实体,他包含发送人,接收人,消息内容等信息/// </summary>/// <param name="msg"></param>/// <returns></returns>
        public Task ClientSendMsgToClient(CSChatMessage msg){var groupName = MessageUtils.GetGroupName(msg.fromuser.userid.ToString(), msg.touser.userid.ToString());/*中间处理一下消息直接转发给(A,B所在组织,即聊天窗口)*/msg.msgtype = CSMessageType.Custom;//消息类型为普通消息return Clients.Group(groupName).receiveMessage(msg);}

  可以看到,同样是用到了receiveMessage方法,不过这里呢,调用的Clients.Group(groupName)也就是说,发送的这条消息职能在这个组内的人才能看到,那么组里就两个人,是不是就实现了1对1 聊天呢,离线留言也支持哦。消息发送成功之后,其实不管对方在不在线,我们都可以做一下本地处理,为了演示消息发送效果,我们不用本地js在发送的时候直接拼接到页面上,而是client端接收到消息体之后再处理,这样会看出消息延时效果。(扩展:假如发送的消息很慢的话,就可以在消息体旁边加一个等待的小菊花,提示发送成功,失败等。)好,我直接将layim里模拟消息处理的代码拿出来了,我们看详细代码。

   handleCustomMsg: function (result) {var log = {};//接收人var keys = 'one' + result.touser.userid;//发送人var keys1 = 'one' + result.fromuser.userid;//这里一定要注意,这个keys是会变的,也就是说,如果只取一个的话,会造成 log.imarea[0]为undefined的情况,至于为什么会变,看看代码好好思考一下吧log.imarea = $('#layim_area' + keys);//layim_areaone0if (!log.imarea.length) {log.imarea = $('#layim_area' + keys1);//layim_areaone0
            }//拼接html模板log.html = function (param, type) {return '<li class="' + (type === 'me' ? 'layim_chateme' : '') + '">'+ '<div class="layim_chatuser">'+ function () {if (type === 'me') {return '<span class="layim_chattime">' + param.time + '</span>'+ '<span class="layim_chatname">' + param.name + '</span>'+ '<img src="' + param.face + '" >';} else {return '<img src="' + param.face + '" >'+ '<span class="layim_chatname">' + param.name + '</span>'+ '<span class="layim_chattime">' + param.time + '</span>';}}()+ '</div>'+ '<div class="layim_chatsay">' + param.content + '<em class="layim_zero"></em></div>'+ '</li>';};//上述代码还是layim里的代码,只不过拼接html的时候,参数采用signalR返回的参数var type = result.fromuser.userid == currentUser.id ? "me" : "";//如果发送人的id==当前用户的id,那么这条消息类型为me//拼接html 直接调用layim里的代码
            log.imarea.append(log.html({time: result.addtime,name: result.fromuser.username,face: result.fromuser.photo,content: result.msg}, type));//滚动条处理log.imarea.scrollTop(log.imarea[0].scrollHeight);},

  好了, 代码也都处理完了,这里呢有个小插曲,我们怎么确定当前用户是谁呢?由于我写的是死数据,所以我就采用随机生成的方法,然后将用户保存到 localStorage里面了,这样当用户再次打开页面,还是会取到第一次的用户,这里呢不多做介绍了。

 /*获取随机一个用户当用户第一次登陆就获取,然后存到本地localStorage中模拟用户,之后再登录就直接从缓存里面取*/function getRandomUser() {var userKey = "SIGNALR_USER";var user = local.get(userKey);if (user) { return JSON.parse(user);}var userids = [];var usernames = ["痴玉", "书筠", "诗冬", "飞枫", "盼玉", "靖菡", "宛雁", "之卉", "凡晴", "书枫", "沛梦"];var userphotos = [];//添加id,用户头像数组for (var i = 0; i < 9; i++) {userids.push(10000 + i);userphotos.push("/photos/00" + i.toString() + ".jpg");}//取一个random值,自动生成当前用户var random = Math.random().toString().substr(3, 1);if (random > 8) { random = 8; }var user = {name: usernames[random],photo: userphotos[random],id:userids[random]};local.set(userKey, JSON.stringify(user));return user;}/*本地存储*/var local = {get: function (key) {return localStorage.getItem(key);},set: function (key, value) {localStorage.setItem(key, value);}}

  当然里面有好多需要注意的细节没有给大家讲,具体的可以看详细代码,思路基本已经出来了。我在重复一遍吧:第一,点击用户,连接服务器,当前用户加入对应的组。第二,发送消息,调用server端的方法,将消息发送出去后,在推送到组里面去,第三,客户端接收到消息之后,加到html页面上,就这么简单。还有一个细节,注意消息在左边还是右边。

  演示一下吧:模拟第一个用户登录。(谷歌浏览器)

  好,很好听的名字:飞枫,id为10003,下面第二个用户登录,(QQ浏览器)

  id为10001,名字为 书筠。那么我们先用第一个用户点击  书筠 头像 打开聊天窗口,然后在用第二个用户点击 飞枫头像打开聊天窗口(由于没有做历史记录,所以离线留言功能暂时不支持,只支持在线)

  打开之后,唉,单身的我只能模拟两个人聊天玩了。。

到此为止呢,1v1聊天就到一段落,仅支持。。。文本,还不知道输入script有没有处理。。另外还有一个bug,就是窗口多开的话,应该 信息可能会乱,不是因为 发送乱了,而是,里面有可能有重复的ID导致信息赋html错误,我没测,但是我猜测是这样的。非常感谢“贤心”大神的web前端通讯框架。本篇到此结束,喜欢的同学点个赞吧。多多转发哦。下篇预告:最终章-修改1v1聊天bug,添加图片表情,附件传送功能。群聊功能实现。

GitHub地址:

https://github.com/fanpan26/LayIM/tree/master

转载于:https://www.cnblogs.com/panzi/p/5146573.html

ASP.NET SignalR 与LayIM配合,轻松实现网站客服聊天室(三) 激动人心的时刻到啦,实现1v1聊天...相关推荐

  1. 转载 ASP.NET SignalR 与LayIM配合,轻松实现网站客服聊天室(三) 激动人心的时刻到啦,实现1v1聊天...

    ASP.NET SignalR 与LayIM配合,轻松实现网站客服聊天室(三) 激动人心的时刻到啦,实现1v1聊天 看起来挺简单,细节还是很多的,好,接上一篇,我们已经成功连接singalR服务器了, ...

  2. ASP.NET SignalR 与LayIM配合,轻松实现网站客服聊天室(四) 添加表情、群聊功能...

    休息了两天,还是决定把这个尾巴给收了.本篇是最后一篇,也算是草草收尾吧.今天要加上表情功能和群聊.基本上就差不多了,其他功能,读者可以自行扩展或者优化.至于我写的代码方面,自己也没去重构.好的,我们开 ...

  3. 微信轻松接入QQ客服

    一直以来,大家都苦恼怎么实现微信公众帐号可以接入客服,也因此很多第三方接口平台也开发客服系统CRM系统,不过不是操作复杂就是成本太高.今天分享一个低成本又简便的方法,让你的公众帐号接入QQ客服.下面介 ...

  4. SignalR聊天室

    SignalR聊天室 源码地址:https://github.com/LiKely2021/LayIM_SignalR_Chat-Deprecated 丶Pz 2016-08-05 17:08 阅读: ...

  5. LayIM 3.9.1与ASP.NET SignalR实现Web聊天室快速入门(五)之使用RabbitMQ缓存消息

    前言 本系列文章特点:使用ASP.NET SignalR和LayIM快速入门对接,实现一对一聊天,群聊,添加聊天群组,查找聊天记录等功能.源代码不包含LayIM的源代码,因为官方并没开源属于收费资源, ...

  6. LayIM 3.9.1与ASP.NET SignalR实现Web聊天室快速入门(七)之LayIM与MVC数据交互实现单聊和群聊

    前言 本系列文章特点:使用ASP.NET SignalR和LayIM快速入门对接,实现一对一聊天,群聊,添加聊天群组,查找聊天记录等功能.源代码不包含LayIM的源代码,因为官方并没开源属于收费资源, ...

  7. LayIM 3.9.1与ASP.NET SignalR实现Web聊天室快速入门(四)之ASP.NET SignalR核心功能介绍

    前言 本系列文章特点:使用ASP.NET SignalR和LayIM快速入门对接,实现一对一聊天,群聊,添加聊天群组,查找聊天记录等功能.源代码不包含LayIM的源代码,因为官方并没开源属于收费资源, ...

  8. c聊天室系统asp ajax,利用AJAX和ASP.NET实现简单聊天室

    利用AJAX和ASP.NET实现简单聊天室 我的第一个简单的Chatroom是用ASP3.0写成的.那无外乎有二个TextBox,他们发送消息 给程序变量然后显示在一个每秒刷新的页面上.在那个时代,一 ...

  9. 分享88个ASP聊天室,总有一款适合您

    分享88个asp聊天室,总有一款适合您 88个asp聊天室下载链接:https://pan.baidu.com/s/1h0LAvsPUwCDCqE0SfEj0aA?pwd=1a2a  提取码:1a2a ...

  10. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(一) 之 基层数据搭建,让数据活起来(数据获取)...

    大家好,本篇是接上一篇 ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(零) 前言  ASP.NET SignalR WebIM系列第二篇.本篇会带领大家将 LayIM ...

最新文章

  1. ***K近邻Survey-Distance总结
  2. Android 中基本图像绘制
  3. 将MSRA-TD500标签转换成逆时针输出标签+labeleme json格式转四个点的txt
  4. 与计算机交朋友优秀教案,《与计算机交朋友》教学设计-20210608120218.pdf-原创力文档...
  5. 容器编排技术 -- Kubernetes kubectl create secret generic 命令详解
  6. 【我的物联网成长记12】当物联网遇上边缘计算
  7. powershell自动化操作AD域、Exchange邮箱系列(5)——AD模块加载与命令一览
  8. Ubuntu12.04增加屏幕分辨率选项
  9. 设计模式之组合模式——Java语言描述
  10. 跳槽的5个误区,冷静一下
  11. matlab没有曲线,有个程序,运行后只有坐标没有曲线,是怎么回事呢 望大神们解答...
  12. DeepRacer 根据路线计算Action Space RaceLine_Speed_ActionSpace
  13. 可编程串行通信接口芯片8251A
  14. java电信计费项目_基于jsp的电信计费-JavaEE实现电信计费 - java项目源码
  15. 技术债务管理_管理技术债务
  16. 机器学习(三):线性模型
  17. 【优化求解】基于matlab禁忌搜索算法求解函数极值问题【含Matlab源码 1204期】
  18. 使用Java编写《拳皇97》,致敬经典,还原八神庵大战草稚京
  19. 小米校招编程题:数组乘积、异形数、朋友圈
  20. Win10下永久性关闭自动更新(可恢复更新)最简单有效的方法《亲测有效》

热门文章

  1. matlab解微分方程例子,MATLAB解微分方程 [轉] | 學步園
  2. java获取本地磁盘文件_java如何读取本地磁盘目录下的所有文件或者文件夹
  3. 为什么要进行傅立叶变换?傅立叶变换究竟有何意义?
  4. Python拉勾网爬虫实现
  5. Java面试题汇总与解答
  6. VS2019 后面有“::”的名称一定是类名或命名空间名 解决办法汇总
  7. 【错误解决】System.NotSupportedException:“LINQ to Entities does not recognize the method
  8. 易中天品汉代风云人物06:韩信身世之谜
  9. python tokenize_model_如何将关键字放入NLTK tokenize中?
  10. 视频在线播放,边下边播的一些问题记录