上一篇中简单讲解了用Redis缓存在线用户逻辑。篇幅也比较小,本篇将详细实现用户的上线下线通知、图片效果转换功能。并且,代码和开发思路都会详细介绍。html
目前有三个用户,user1,user2,user3.下图会简单展现用户上线,下线的消息推送效果。前端
图一:用户1登陆,此时好友均不在线。(头像为灰色,谷歌浏览器)git
图二:用户1登陆(打开360浏览器模拟用户1登陆),此时谷歌浏览器用户收到该用户上线通知,图标亮起github
图三:用户2登陆(打开搜狗浏览器模拟用户2登陆),此时谷歌浏览器用户收到该用户上线通知,图标亮起redis
图四:三个用户均在线(三个浏览器截图)数据库
图五:谷歌浏览器用户下线(其余两个用户收到下线消息,头像变黑白)json
不完美的地方:浏览器
1.用户在线或者下线会有不许确性,须要从新刷新页面才能够缓存
2.群内用户图标暂时还未处理并发
3.打开聊天窗口的图标也未做处理(若是用户不在线,图标仍是亮的)
如今进入正题,全部后台的操做均是为了给前端提供数据。那么前端只要作一件事情便可,接收消息,根据用户上下线改变用户头像的状态。个人方法是用了一个第三方的js。官网:https://en.wikipedia.org/wiki/Grayscale,我把js拷贝到本地,而且封装成layui可引用的js。
正如以前所讲的,咱们定义一个gray插件,而且暴漏grayscale对象。小伙伴们不要忘了在首页上配置上该js。
//自定义模块 layui.extend({ signalr: '/scripts/signalr/signalr', autohub: '/scripts/signalr/autohub',//自动生成的 hub: '/Scripts/signalr/hub', gray:'/scripts/gray'//控制图片黑白的js });
而后,咱们要作的就很简单了。想把哪一个图片置灰,就调用相似以下方法,那么图片就会替换为一个base64的灰色图片了,效果在上边的截图中,相信你们已经看到了。
var imgs = $("img[data-status='hide']"); if (imgs.length) {
grayscale(imgs); }
你们都知道,刚进入layim界面的时候,咱们会有好友列表信息。那么上一篇讲到的用Redis存储在线用户列表就能派上用场了。咱们找到base方法(获取用户基础信息,好友信息,群组信息等)
//用户组信息 var rowFriendDetails = ds.Tables[2].Rows.Cast<DataRow>().Select(x => new GroupUserEntity { id = x["uid"].ToInt(), avatar = x["avatar"].ToString(), groupid = x["gid"].ToInt(), remarkname = x["remarkname"].ToString(), username = x["nickname"].ToString(), sign = x["sign"].ToString(), //status以前的字段是为空的,如今咱们把他的在线状态加上,IsOnline方法接收一个userid参数,从Redis缓存中读取该用户是否在线并返回 status = LayIMCache.Instance.IsOnline(x["uid"].ToInt()) ? "online" : "hide" }).OrderByDescending(x => x.status);//这里要根据用户是否在线这个字段排序,保证在线用户都在好友列表最上边
注释的部分就是改动的地方,这样咱们在看一下初始化layim以后返回的json格式信息。
看到画红框的地方了吧,个人两个好友都不在线(hide)。可是呢,图标仍是亮的,怎么办,那就须要等数据加载完以后咱们用上边的处理图标的js处理一下。没错,又要改layim代码了。(PS:官方是不建议改的哈,不然升级很差整合)好多同窗想要改代码无从下手,我简单说一下个人改代码思路。其实不管js要干吗,最终它仍是为html服务,因此,咱们找到用户头像的标签:
上图呢是处理过的图片,不过不要紧,咱们只要关心,这个img标签在哪里就能够了。(注意:data-status是我加的,也就是说,改源代码就是加了这么个东西)而后咱们找到layim代码,从模板里面找就能够了。
红框的地方就是我改动的地方。改完它以后,咱们在看主界面,这样咱们就知道img标签中,哪一个是须要处理成黑白图片的了。而后在ready方法中调用:
initStatus: function () { //循环检测须要置为黑白的头像 //这里用interval的缘由是,图片可能还么加载完致使黑白效果不出的问题 this.userAvatarInterval = setInterval(function () { //获取到带 hide标签的img对象 var imgs = $("img[data-status='hide']"); if (imgs.length) { //设置黑白效果 grayscale(imgs); //中止循环 clearInterval(other.userAvatarInterval); } }, 200); //超过五秒后中止(保险起见) setTimeout(function () { clearInterval(other.userAvatarInterval); }, 5000); },
这样咱们就完成了初始化以后,知道哪一个好友在线,哪一个好友不在线了。如今有什么问题呢,很显然,加入我如今的好友都不在线,那么图标都是黑色的。若是某个好友上线了,我不刷新页面,可是它的图标仍是黑色的对吧。因此,咱们就要用到singalR了,回归消息推送,下面咱们要作的就是当用户上线或者下线以后给本身的好友发送消息推送。由于,已经用上Redis了,因此,干脆每一个人的好友列表我也一样用Redis来保存。不过不一样的是,这个好友列表缓存须要时时更新,好比加好友以后,删好友以后等。这里呢,我没作那么麻烦,我设置了一天的过时时间,这样,每一天事后才更新。看一下获取好友列表代码:
#region 获取某个用户的好友列表 /// <summary> /// 获取某个用户的好友列表 /// </summary> /// <param name="userid">用户ID</param> /// <returns>返回格式以下 ""或者 "10001,10002,10003"</returns> public string GetUserFriends(int userid) { //先读取缓存 var friends = LayIMCache.Instance.GetUserFriendList(userid); //若是缓存中没有 if (friends == "") { //从数据库读取,在保存到缓存中 friends = _dal.GetUserFriends(userid); LayIMCache.Instance.SetUserFriendList(userid, friends); } return friends; } #endregion
因为灰色头像是base64的,若是用户上线,咱们须要把该用户原来的头像传给前端,而后替换该头像。因此,这个缓存我暂时就把头像信息也保存进去了(业务耦合了)。看一下Redis中的值:
如图所示,用户10003的好友为:10004,10005. 值组成格式为:userAvatar + $LAYIM$ + friendids 。一样,咱们在HubServer中增长发送用户上下线消息的方法:
/// <summary> /// 发送用户上下线的消息 /// </summary> public static void SendUserOnOffLineMessage(string userId,bool online=true) { int userid = userId.ToInt(); //1.获取用户的全部好友 var users = LayimUserBLL.Instance.GetUserFriends(userid); //没有好友,不发消息 var friends = users.Split(new string[] { "$LAYIM$" }, StringSplitOptions.RemoveEmptyEntries); if (friends.Length == 2) { var avatar = friends[0]; var notifyUsers = friends[1]; //2.发送用户上下线通知 UserOnOffLineMessage message = new UserOnOffLineMessage { avatar = avatar, online = online, userid = userid }; SendMessage(message, notifyUsers, ChatToClientType.UserOnOffLineToClient, true); } }
这个方法,就是获取缓存里面的用户好友信息和头像信息,而后组成一个新的Message,并发送消息。那么这个方法在哪里调用呢。咱们仍是回到LayIMHub代码中。
/// <summary> /// 创建链接 /// </summary> /// <returns></returns> public override Task OnConnected() { //将当前用户添加到redis在线用户缓存中 LayIMCache.Instance.OperateOnlineUser(CurrentOnlineUser); //发送用户上线消息 HubServer.HubServerHelper.SendUserOnOffLineMessage(CurrentUserId); return Clients.Caller.receiveMessage("链接成功"); } /// <summary> /// 失去链接 /// </summary> /// <param name="stopCalled"></param> /// <returns></returns> public override Task OnDisconnected(bool stopCalled) { //将当前用户从在线用户列表中剔除 LayIMCache.Instance.OperateOnlineUser(CurrentOnlineUser, isDelete: true); //发送用户下线消息 HubServer.HubServerHelper.SendUserOnOffLineMessage(CurrentUserId, online: false); return Clients.Caller.receiveMessage("失去链接"); } /// <summary> /// 从新链接 /// </summary> /// <returns></returns> public override Task OnReconnected() { //将当前用户添加到redis在线用户缓存中 LayIMCache.Instance.OperateOnlineUser(CurrentOnlineUser); //发送用户上线消息 HubServer.HubServerHelper.SendUserOnOffLineMessage(CurrentUserId); return Clients.Caller.receiveMessage("从新链接"); }
哈哈,是否是发现利用OnConnected,OnReconnected,DisConnected方法能作好多事情啊。而后咱们在Index页面增长一个分支就能够了。
咱们先运行一下,看看效果:
咱们把消息定义成统一格式是有好处的,这样咱们能够根据本身的业务进行处理,接受消息就一个接口:receiveMessage。 能够看到msg里面有用户头像,和在线状态,还有用户id。获得了这些信息以后,咱们去处理一下就OK了。
//从新设置用户头像,黑白或者亮 resetUserAvatar: function (obj) { var avatar = obj.avatar, online = obj.online, userid = obj.userid;
//这句代码是定位到该用户下的头像 var imgObj = $('#layim-friend' + userid).find('img'); if (imgObj.length) { if (obj.online) { //若是上线了,将头像换成原来的头像,即非黑白头像 imgObj.attr('src', avatar); } else { //将头像置黑 grayscale(imgObj); } } }
到此为止,功能开发结束。
本篇内容相对来讲比上一篇多一点,涉及内容有,Redis缓存,更新等。图片黑白处理,SignalR消息处理。以及源代码阅读。
总之呢,最重要的部分就是SignalR这个推送若是稳定了,只要消息可以送达客户端,那么任由客户端去处理了。你们还有注意学会自定义消息内容。保证本身的业务可以顺畅。
下篇预告:无(我也不知道写啥,到时候在看吧)
想要学习的小伙伴,能够关注个人博客哦,个人QQ:645857874,Email:fanpan26@126.com
GitHub:https://github.com/fanpan26/LayIM_NetClient/ (无source源代码哦,由于layim是须要受权的,请各位谅解)