上一篇中簡單講解了用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是須要受權的,請各位諒解)