您好,登錄后才能下訂單哦!
小編給大家分享一下SpringBoot+LayIM+t-io如何實現好友申請通知,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
簡介
加好友,大家用過QQ都知道,無非是發起好友申請,對方收到消息通知,然后處理。不過,本篇只講前半部分,消息通知的處理留到下一篇去講。因為內容有點多,怕是一時半會消化不了。在介紹主體流程之前,先給大家介紹一下準備工作。
準備工作
首先,為了讓數據更貼近實戰,所以我用了比較“真實”的用戶數據。結合fly模板,完善了用戶中心頭部的用戶信息的數據綁定。數據綁定部分判斷了是否已經是好友,來決定是否出現“加為好友”的按鈕。示例如下,當用戶自己看到自己的主頁時,是這樣的:
看到非好友的用戶主頁,是這樣的:
綁定數據部分,簡單給大家介紹一下,就是用thymleaf模板綁定。后臺訪問頁面的時候,將 Model 賦值即可。
/** * 屬性賦值 * */ private void setModel(User user,Model model){ long currentUserId = getUserId(); long visitUserId = user.getId(); //是否是自己 boolean isSelf = currentUserId == visitUserId; //兩個用戶是否已經是好友 boolean isFriend = groupService.isFriend(currentUserId,visitUserId); Map<String,Object> userMap = new HashMap<>(8); userMap.put("avatar",user.getAvatar()); userMap.put("name",user.getUserName()); userMap.put("addtime", TimeUtil.formatDate(user.getCreateAt())+" 加入"); if(user.getSign()==null ||user.getSign().length()==0) { userMap.put("sign", ""); }else { userMap.put("sign", "(" + user.getSign() + ")"); } userMap.put("uid",user.getId()); userMap.put("self",isSelf || isFriend); model.addAttribute("user",userMap); }
然后頁面上,將model中的數據取出來。
<div class="fly-home" > <input type="hidden" th:value="${user.uid}" id="visitUid"/> <img src="" th:src="${user.avatar}" th:alt="${user.name}"/> <h2> <p th:text="${user.name}"></p> <i class="iconfont icon-nan"></i> </h2> <p class="fly-home-info"> <!--<i class="iconfont icon-zuichun" title="飛吻"></i><span >67206飛吻</span>--> <i class="iconfont icon-shijian"></i><span th:text="${user.addtime}"></span> <!--<i class="iconfont icon-chengshi"></i><span>來自杭州</span>--> <i class="iconfont icon-qq" th:if="${user.self==false}"></i><a lay-event="addFriend" href="#" rel="external nofollow" title="添加TA為好友" th:if="${user.self==false}">加為好友</a> </p> <p class="fly-home-sign" th:text="${user.sign}"></p> </div>
ok,以上就是簡單的準備工作。想了解詳情代碼的可以去文末的github地址去搜尋。
發起好友申請
我們先根據layim的業務分析。首先,要知道我們要加誰(toId)為好友。然后在加上一個備注(remark)。這些東西交給后臺就OK了。為了避免連表查詢,對于系統消息的存儲我做了用戶名和用戶頭像的冗余。表主要包含字段:用戶ID,用戶頭像,用戶名,被申請用戶ID,申請時間,申請類型,備注,已讀等其他屬性。
所以,發起好友申請就很簡單了。就是一個添加功能,前端傳的就是被申請人用戶ID和申請備注,后端組織數據插入到數據庫,代碼如下:
/** * 提交好友申請 * */ public JsonResult saveFriendApply(long toId,String remark){ remark = HtmlUtils.htmlEscape(remark); ContextUser user = ShiroUtil.getCurrentUser(); long userId = Long.parseLong(user.getUserid()); int record = applyRepository.countByToidAndUidAndTypeAndResult(toId,userId,ApplyType.friend,0); if(record > 0){ return JsonResult.fail("已經申請過"); } Apply apply = new Apply(); apply.setType(ApplyType.friend); apply.setToid(toId); apply.setRemark(remark); apply.setUid(userId); apply.setAvatar(user.getAvatar()); apply.setName(user.getUsername()); apply.setRead(false); apply.setResult(0); return saveApply(apply); }
OK,申請完了,下面我們要做啥?沒錯,通知對方,喂,我向你發送了申請,快快處理。在這里呢我遇到了一個問題。由于springboot程序占用端口 8080,而t-io占用端口8888,也就是說,如果我想在8080端口的業務中主動調用8888的服務推送,我不知道如何獲取相應的channelContext。不過經過詢問作者之后,一句話解決了我的問題。
拿到 ServerGroupContext ,問題迎刃而解。
在之前的程序啟動的時候注冊了 LayimWebsocketStarter 這個bean。所以,在8080業務端如果能拿到它的話就沒問題了。
得到 LayimWebsocketStarter ,就能得到 ServerGroupContext, 然后就能在服務端做主動推送了。
當然可能沒有開發過這個東西,對于上文中的問題不是很理解,沒關系,其實我就想說明,如果從服務端主動向客戶端推送消息的話,使用ServerGroupContext即可。
服務端主動推送
以下代碼在 com.fyp.layim.im.common.util.PushUtil 中
OK,接上文,我們按照步驟來。
第一步,獲取 LayimWebsocketStarter 。
/** * 獲取starter */ private static LayimWebsocketStarter getStarter(){ return (LayimWebsocketStarter)SpringUtil.getBean("layimWebsocketStarter"); }
第二步,獲取 ServerGroupContext
private static ServerGroupContext getServerGroupContext(){ return getStarter().getServerGroupContext(); }
第三步,獲取 ChannelContext。
/** * 獲取channelContext * */ private static ChannelContext getChannelContext(String toId) { ServerGroupContext context = getServerGroupContext(); //找到用戶 ChannelContext channelContext = context.users.find(context, toId); return channelContext; }
第四步,發射,這里的代碼就和聊天中的那部分代碼差不多了。核心部分就是,獲取ChannelContext,然后給他發送消息。如果不在線就不用管。
/** * 服務端主動推送消息 * */ public static void pushApplyMessage(String toId) { logger.info("執行到了發送方法:pushApplyMessage"); LayimToClientNoticeMsgBody body = new LayimToClientNoticeMsgBody(); ChannelContext channelContext = getChannelContext(toId); //先判斷是否在線,再去查詢數據庫,減少查詢次數 if (channelContext != null && !channelContext.isClosed()) { int count = getApplyService().getUnreadMsgCount(Long.parseLong(toId)); body.setCount(count); push(channelContext, body); } } /** * 服務端主動推送消息 * */ private static void push(ChannelContext channelContext,Object msg) { try { WsResponse response = BodyConvert.getInstance().convertToTextResponse(msg); Aio.send(channelContext, response); }catch (IOException ex){ } }
現在推送已經搞定了,那么什么時候推送呢?由于這個系統消息的推送可以不用那么即時,于是我看了下,springboot里面有類似的事件機制,于是乎 ApplyEvent 就誕生了。
public class ApplyEvent extends ApplicationEvent { public ApplyEvent(Object source) { super(source); } private long toid; public long getToId(){ return toid; } public ApplyEvent(Object source, long toId) { super(source); this.toid = toId; } }
在創建一個Listener,監聽事件。
public class ApplyListener implements ApplicationListener<ApplyEvent> { private Logger logger = LoggerFactory.getLogger(ApplyListener.class); @Override public void onApplicationEvent(ApplyEvent applyEvent) { new Thread(){ public void run(){ Long toId = applyEvent.getToId(); //這里就要調用上文中的推送了 PushUtil.pushApplyMessage(toId.toString()); } }.start(); } }
不過我有個疑問,發現listener中執行的時候是同步的。后來加了@Async 和@EnableAsync 也沒用,于是我就用了new Thread().start()實現異步,確保不影響主要申請流程。(這是個疑問,自己沒搞明白的地方)
最后,別忘了在Application啟動的時候把listener加上。
public static void main(String[] args) { SpringApplication springApplication = new SpringApplication(LayimApplication.class); /** * 這里監聽增加listener,listener才會觸發 * ApplyListener 是監聽好友申請的事件 * */ springApplication.addListeners(new ApplyListener()); springApplication.run(args); }
功能拼接
馬上就要成功了,我們在把事件串起來,在好友申請成功之后,發布事件。
/** * 好友申請 * */ @PostMapping(value = "/apply-friend") public JsonResult apply(@RequestParam("toid") Long toId,@RequestParam("remark") String remark){ JsonResult result = applyService.saveFriendApply(toId, remark); //申請成功,發布申請事件,通知 toId處理消息,如果不在線,不會進行處理 if(result.isSuccess()){ applicationContext.publishEvent(new ApplyEvent("apply",toId)); } return result; }
功能演示
講了那么多,給大家看一下成品效果。(用戶場景:安小鳥加皇上為好友,皇上接收消息并查看)
皇上收到消息,系統彈出左下角的小數字4。(調用 layim.msgbox(msgCount) 方法)
皇上點開消息盒子:
以上是“SpringBoot+LayIM+t-io如何實現好友申請通知”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。