前言

  上一篇中简单讲解了用Redis缓存在线用户逻辑。篇幅也比较小,本篇将详细实现用户的上线下线通知、图片效果转换功能。而且,代码和开发思路都会详细介绍。

效果展示

  目前有三个用户,user1,user2,user3.下图会简单展示用户上线,下线的消息推送效果。

  图一:用户1登录,此时好友均不在线。(头像为灰色,谷歌浏览器)

  

  图二:用户1登录(打开360浏览器模拟用户1登录),此时谷歌浏览器用户收到该用户上线通知,图标亮起

  

  图三:用户2登录(打开搜狗浏览器模拟用户2登录),此时谷歌浏览器用户收到该用户上线通知,图标亮起

  

  图四:三个用户均在线(三个浏览器截图)

  

  图五:谷歌浏览器用户下线(其他两个用户收到下线消息,头像变黑白)

  

实战讲解

  不完美的地方:

  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[].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 == )
{
var avatar = friends[];
var notifyUsers = friends[]; //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是需要授权的,请各位谅解)

ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(九) 之 用 Redis 实现用户在线离线状态消息处理(一)的更多相关文章

  1. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室 实战系列

    ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(零) 前言  http://www.cnblogs.com/panzi/p/5742089.html ASP.NET S ...

  2. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(十二) 代码重构使用反射工厂解耦(一)缓存切换

    前言 上一篇中,我们用了反射工厂来解除BLL和UI层耦合的问题.当然那是最简单的解决方法,再复杂一点的程序可能思路相同,但是在编程细节中需要考虑的就更多了,比如今天我在重构过程中遇到的问题.也是接下来 ...

  3. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(零) 前言

    前端时间听一个技术朋友说 LayIM 2.0 发布了,听到这个消息抓紧去官网看了一下.(http://layim.layui.com/)哎呀呀,还要购买授权[大家支持一下哦],果断买了企业版,喜欢钻研 ...

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

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

  5. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(二) 之 ChatServer搭建,连接服务器,以及注意事项。

    上篇:ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(一) 之 基层数据搭建,让数据活起来(数据获取) 上一篇我们已经完成了初步界面的搭建工作,本篇将介绍IM的核心内容 ...

  6. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(三) 之 实现单聊,群聊,发送图片,文件。

    上篇讲解了如何搭建聊天服务器,以及客户端js怎么和layui的语法配合.服务器已经连接上了,那么聊天还会远吗? 进入正题,正如上一篇提到的我们用 Client.Group(groupId)的方法向客户 ...

  7. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(四) 之 用户搜索(Elasticsearch),加好友流程(1)。

    前面几篇基本已经实现了大部分即时通讯功能:聊天,群聊,发送文件,图片,消息.不过这些业务都是比较粗犷的.下面我们就把业务细化,之前用的是死数据,那我们就从加好友开始吧.加好友,首先你得知道你要加谁.L ...

  8. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(五) 之 加好友,加群流程,消息管理和即时消息提示的实现

    前言 前前一篇留了个小问题,在上一篇中忘了写了,就是关于LayIM已经封装好的上传文件或者图片的问题.对接好接口之后,如果上传速度慢,界面就会出现假死情况,虽然文件正在上传.于是我就简单做了个图标替代 ...

  9. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(六) 之 Layim源码改造右键菜单--好友、组管理功能的实现。

    前言 上一篇中讲解了加好友的流程,本篇将介绍好友管理,群组管理的右键菜单功能.当然由于菜单项目太多,都实现也得花费时间.只讲解一下我是如何从不知道怎么实现右键菜单到会自定义菜单的一个过程.另外呢,针对 ...

  10. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(七) 之 历史记录查询(时间,关键字,图片,文件),关键字高亮显示。

    前言 上一篇讲解了如何自定义右键菜单,都是前端的内容,本篇内容就一个:查询.聊天历史纪录查询,在之前介绍查找好友的那篇博客里已经提到过 Elasticsearch,今天它又要上场了.对于Elastic ...

随机推荐

  1. 数据源和JNDI的关系:

    DataSource对象是由Tomcat提供的,因此不能在程序中采用创建一个实例的方式来生产DataSource对象,而需要采用Java的另一个技术JNDI,来获得DataSource对象的引用. T ...

  2. Java 的printf(转)

    出处:http://blog.csdn.net/swandragon/article/details/4653600 public class TestPrintf{public static voi ...

  3. SSH如何通过公钥连接云服务器

    导读 通常我们连接远程服务器(linux)windows下通过putty或xshell等工具远程连接.linux下可以直接通过ssh命令连接.其实这两者都是一致的,都是通过ssh协议进行传输. 如果我 ...

  4. polymorphic-associations 多态关联实例 ruby on rails

    这次做新项目的时候,把图片都放在了一个表里,其他表中不再存图片信息,通过多态关联建立表之间的关系. (1)新建picture表, component表不需要处理 class CreatePicture ...

  5. Windows系统使用putty远程连接DigitalOcean创建的Linux系统(CentOS6.7为例)

    大部分vps提供网站都会在网站上提供一个控制台界面,方便操作远程vps.但是使用起来特别不方便,尤其在一个神奇的国家,打开国外网站都困难,何况还要在网站上不断的操作.这一教程记录如何在Windows系 ...

  6. [转]Mysql海量数据存储和解决方案之一—分布式DB方案

    1)  分布式DB水平切分中用到的主要关键技术:分库,分表,M-S,集群,负载均衡 2) 需求分析:一个大型互联网应用每天几十亿的PV对DB造成了相当高的负载,对系统的稳定性的扩展性带来极大挑战. 3 ...

  7. discuzX3后台管理插件开发入门

    discuz官方有完整的插件开发文档,详见: http://open.discuz.net/?ac=document&page=dev_plugin 关于discuz前台插件入门可以见这篇文: ...

  8. Java总结(一):封装——Encapsulation

    官方定义:一种将抽象性函式接口的实作细节部份包装.隐藏起来的方法.封装可以被认为是一个保护屏障,防止该类的代码和数 据被外部类定义的代码随机访问. 大白话定义:通过getter和setter方法访问私 ...

  9. 【leetcode】Maximum Subarray

    Maximum Subarray Find the contiguous subarray within an array (containing at least one number) which ...

  10. python程序打包成.exe----pyinstaller工具

    1. 环境 windows 2. 安装 准备文件:PyWin32 or pypiwin32 运行如下安装命令:  pip install pyinstaller==3.0 不要使用3.2版本,编译完成 ...