前言
在上一篇中已经完成了好友申请的流程。本篇就是对申请处理流程的简单讲解。核心知识点在前几篇中已经介绍过很多次了,所以本篇也算是和推送部分有关的最终篇了。后续就继续踏踏实实学习其他的东西吧。
申请处理
申请的处理流程如下:
同意申请:更新消息状态,新增系统消息,加为好友,推送消息
拒绝申请:更新消息状态,新增系统消息,推送消息
代码实现
首先,在UI上,LayIM已经做的很棒了。点击同意事件已经写好,所以要做的就是对接后台的逻辑。

上图弹层代码:
layim.setFriendGroup({ type: 'friend' , username: user.username , avatar: user.avatar , group: parent.layui.layim.cache().friend //获取好友分组数据 , submit: function (mygroup, index) { req.post('/layim/apply/agree/' + id, { group: mygroup }, function (res) { if (res.code != 0) { return layer.msg(res.msg); }else{ //将好友追加到主面板 parent.layui.layim.addList({ type: 'friend' , avatar: user.avatar //好友头像 , username: user.username //好友昵称 , groupid: mygroup //所在的分组id , id: uid //好友ID , status:res.data.status//好友状态 , sign: user.sign //好友签名 }); parent.layer.close(index); othis.parent().html('已同意'); } }); } });
可以注意到,这里用到了 setFriendGroup方法和addList方法。前者就是加好友的界面,后者就是将用户添加到好友列表中。
加好友逻辑不在赘述,主要是加好友成功之后要做两件事情,第一件,通知对方“xx同意加你为好友”。第二,将当前用户信息动态的加入到对方的好友列表中。这里要注意的是,同意添加之后要返回对方好友的在线状态,以便根据状态对好友头像做置灰处理。
判断是否在线的方法如下:(应该会有其他方法)
/** * 判断一个用户是否在线 * */ public static boolean isOnline(long userId){ ChannelContext channelContext = getServerGroupContext() .users.find(getServerGroupContext(),userId+""); return channelContext!=null && !channelContext.isClosed()&&!channelContext.isRemoved(); }
通过看源码,可以知道根据用户ID获取channelContext,是通过一个map来实现的
private ObjWithLock<DualHashBidiMap<String, ChannelContext>> map = new ObjWithLock<>(new DualHashBidiMap<String, ChannelContext>());
其实本来我的写法是直接调用 map.getObj().containsKey(userId) 方法.后来查看源代码,发现还需要加锁。对锁的研究比较少,所以还是老老实实用了框架提供的find方法,然后对channelContext进行状态的判断。
/** * Find. * * @param userid the userid * @return the channel context */ public ChannelContext find(GroupContext groupContext, String userid) { if (groupContext.isShortConnection()) { return null; } if (StringUtils.isBlank(userid)) { return null; } String key = userid; Lock lock = map.getLock().readLock(); DualHashBidiMap<String, ChannelContext> m = map.getObj(); try { lock.lock(); return m.get(key); } catch (Exception e) { throw e; } finally { lock.unlock(); } }
当调用同意添加好友接口之后,返回结果为:

然后页面调用layim.addList方法,就可以将该用户动态加入到好友列表中

同样我们在示范一遍,重新申请,然后申请人保留在线状态。

大家看出区别了吗?不过目前这里有个小瑕疵,就是没有好友签名。不过无伤大雅,下次登录就可以了。
上下线通知
其实从上文中的截图可以看到,头像有灰色有亮色同QQ一样来表示好友的在线状态。这个要归功于LayIM的好友属性中的 status 属性,它有online和offline两个值。我们可以通过一下方法实现头像的置灰功能。
layim.setFriendStatus(userId, 'offline'); layim.setFriendStatus(userId, 'online');
下面回到我们的LayimMsgHandler当中,在处理handshake事件之后,之前已经介绍过绑定用户和绑定群组,最后呢要给所有在线的好友发送一个上线通知。具体通知方法如下:
/** * 通知该用户的好友上线消息 * */ private void notify(ChannelContext channelContext,boolean online) throws IOException{ long uid = Long.parseLong(channelContext.getUserid()); //获取用户所有的好友ID List<String> allFriendIds = getUserService().getAllFriends(uid); if(allFriendIds.size()==0){ return; } //构建消息体 LayimToClientOnlineStatusMsgBody msgBody = new LayimToClientOnlineStatusMsgBody(uid,online); WsResponse statusPacket = BodyConvert.getInstance().convertToTextResponse(msgBody); //调用sendToAll的方法 Aio.sendToAll(channelContext.getGroupContext(), statusPacket, filterChannelContext -> { //筛选掉已经移除和关闭的连接 if(filterChannelContext.isRemoved()||filterChannelContext.isClosed()) { return false; } //筛选掉非当前用户好友的连接 String channelContextUserid = filterChannelContext.getUserid(); boolean exists = allFriendIds.stream().anyMatch(friendUserId -> friendUserId.equals(channelContextUserid)); return exists; }); }
所以,在handshake成功之后,调用一下 notify(channelContext,true) 方法实现上线消息推送,当触发onClose方法的时候,调用notify(channelContext,false)的方法实现下线消息推送。
@Override public Object onClose(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext) throws Exception { notify(channelContext,false); Aio.remove(channelContext,"onClose"); return null; }
最后呢,初始化好友列表的时候还要做一个事情,就是已经在线的应该是亮色,不在线的是灰色,还要注意在线的排序在前边。排序方法,我们让UserViewModel实现Comparable的compareTo方法。
public void setSort(Integer sort) { this.status = sort==1?"online":"offline"; this.sort = sort; } private int sort; @Override public int compareTo(Object o) { UserViewModel o1 = (UserViewModel) o; return o1.getSort().compareTo(this.getSort()); }
排序效果如下:


功能演示
首先用“皇后”账号添加“皇上”为好友,皇上收到通知,准备处理。

此时皇后的好友列表空空如也。

皇上收到好友请求,打开并同意。

此时,皇上的好友列表中增加了好友“皇后”

而皇后的列表中也增加了皇上,并且收到了一条消息。


至此整个好友申请处理流程结束。皇后看到皇上批准了好友请求,安心的睡去了。下线走人。


总结
写了这么几篇,其实中心点就是一个,实现推送即可。毕竟业务是活的,可以随时变动,但是推送的中心思想不变。本篇没有介绍什么新东西。无非是业务上的完善。不过多看看源代码还是挺有好处的。多看多学多用,继续加油,希望我的博客能给看到的人一些小小的帮助。
支持的小伙伴们给个star吧。虽然代码有点乱,后续肯定是要慢慢重构的啦。
代码地址:https://github.com/fanpan26/SpringBootLayIM