最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot+LayIM+t-io 實(shí)現(xiàn)好友申請(qǐng)通知流程

 更新時(shí)間:2017年12月11日 09:28:31   作者:丶Pz  
這篇文章主要介紹了 SpringBoot+LayIM+t-io 實(shí)現(xiàn)好友申請(qǐng)通知流程,本文圖文并茂給大家介紹的非常詳細(xì),需要的朋友可以參考下

前言

在上一篇 Spring boot + LayIM + t-io 文件上傳、 監(jiān)聽(tīng)用戶狀態(tài)的實(shí)現(xiàn) 中,已經(jīng)介紹了兩個(gè)小細(xì)節(jié):用戶的在離線狀態(tài)和群人數(shù)的狀態(tài)變化。今天的主要內(nèi)容就是用戶加好友的實(shí)現(xiàn)。

簡(jiǎn)介

加好友,大家用過(guò)QQ都知道,無(wú)非是發(fā)起好友申請(qǐng),對(duì)方收到消息通知,然后處理。不過(guò),本篇只講前半部分,消息通知的處理留到下一篇去講。因?yàn)閮?nèi)容有點(diǎn)多,怕是一時(shí)半會(huì)消化不了。在介紹主體流程之前,先給大家介紹一下準(zhǔn)備工作。

準(zhǔn)備工作

首先,為了讓數(shù)據(jù)更貼近實(shí)戰(zhàn),所以我用了比較“真實(shí)”的用戶數(shù)據(jù)。結(jié)合fly模板,完善了用戶中心頭部的用戶信息的數(shù)據(jù)綁定。數(shù)據(jù)綁定部分判斷了是否已經(jīng)是好友,來(lái)決定是否出現(xiàn)“加為好友”的按鈕。示例如下,當(dāng)用戶自己看到自己的主頁(yè)時(shí),是這樣的:

 

看到非好友的用戶主頁(yè),是這樣的:

 

綁定數(shù)據(jù)部分,簡(jiǎn)單給大家介紹一下,就是用thymleaf模板綁定。后臺(tái)訪問(wèn)頁(yè)面的時(shí)候,將 Model 賦值即可。

/**
 * 屬性賦值
 * */
 private void setModel(User user,Model model){
 long currentUserId = getUserId();
 long visitUserId = user.getId();
 //是否是自己
 boolean isSelf = currentUserId == visitUserId;
 //兩個(gè)用戶是否已經(jīng)是好友
 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);
 }

然后頁(yè)面上,將model中的數(shù)據(jù)取出來(lái)。

<div class="fly-home" style="background-image: url();">
 <input type="hidden" th:value="${user.uid}" id="visitUid"/>
 <img src="" th:src="${user.avatar}" th:alt="${user.name}"/>
 <h1>
  <p th:text="${user.name}"></p>
  <i class="iconfont icon-nan"></i>
 </h1>
 <p class="fly-home-info">
  <!--<i class="iconfont icon-zuichun" title="飛吻"></i><span style="color: #FF7200;">67206飛吻</span>-->
  <i class="iconfont icon-shijian"></i><span th:text="${user.addtime}"></span>
  <!--<i class="iconfont icon-chengshi"></i><span>來(lái)自杭州</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,以上就是簡(jiǎn)單的準(zhǔn)備工作。想了解詳情代碼的可以去文末的github地址去搜尋。

發(fā)起好友申請(qǐng)

我們先根據(jù)layim的業(yè)務(wù)分析。首先,要知道我們要加誰(shuí)(toId)為好友。然后在加上一個(gè)備注(remark)。這些東西交給后臺(tái)就OK了。為了避免連表查詢,對(duì)于系統(tǒng)消息的存儲(chǔ)我做了用戶名和用戶頭像的冗余。表主要包含字段:用戶ID,用戶頭像,用戶名,被申請(qǐng)用戶ID,申請(qǐng)時(shí)間,申請(qǐng)類型,備注,已讀等其他屬性。

所以,發(fā)起好友申請(qǐng)就很簡(jiǎn)單了。就是一個(gè)添加功能,前端傳的就是被申請(qǐng)人用戶ID和申請(qǐng)備注,后端組織數(shù)據(jù)插入到數(shù)據(jù)庫(kù),代碼如下:

/**
 * 提交好友申請(qǐng)
 * */
 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("已經(jīng)申請(qǐng)過(guò)");
 }
 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,申請(qǐng)完了,下面我們要做啥?沒(méi)錯(cuò),通知對(duì)方,喂,我向你發(fā)送了申請(qǐng),快快處理。在這里呢我遇到了一個(gè)問(wèn)題。由于springboot程序占用端口 8080,而t-io占用端口8888,也就是說(shuō),如果我想在8080端口的業(yè)務(wù)中主動(dòng)調(diào)用8888的服務(wù)推送,我不知道如何獲取相應(yīng)的channelContext。不過(guò)經(jīng)過(guò)詢問(wèn)作者之后,一句話解決了我的問(wèn)題。

拿到 ServerGroupContext ,問(wèn)題迎刃而解。

在之前的程序啟動(dòng)的時(shí)候注冊(cè)了 LayimWebsocketStarter 這個(gè)bean。所以,在8080業(yè)務(wù)端如果能拿到它的話就沒(méi)問(wèn)題了。

得到 LayimWebsocketStarter ,就能得到  ServerGroupContext, 然后就能在服務(wù)端做主動(dòng)推送了。

當(dāng)然可能沒(méi)有開(kāi)發(fā)過(guò)這個(gè)東西,對(duì)于上文中的問(wèn)題不是很理解,沒(méi)關(guān)系,其實(shí)我就想說(shuō)明,如果從服務(wù)端主動(dòng)向客戶端推送消息的話,使用ServerGroupContext即可。

服務(wù)端主動(dòng)推送

以下代碼在  com.fyp.layim.im.common.util.PushUtil 中

OK,接上文,我們按照步驟來(lái)。

第一步,獲取 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;
 }

第四步,發(fā)射,這里的代碼就和聊天中的那部分代碼差不多了。核心部分就是,獲取ChannelContext,然后給他發(fā)送消息。如果不在線就不用管。

/**
 * 服務(wù)端主動(dòng)推送消息
 * */
 public static void pushApplyMessage(String toId) {
 logger.info("執(zhí)行到了發(fā)送方法:pushApplyMessage");
 LayimToClientNoticeMsgBody body = new LayimToClientNoticeMsgBody();
 ChannelContext channelContext = getChannelContext(toId);
 //先判斷是否在線,再去查詢數(shù)據(jù)庫(kù),減少查詢次數(shù)
 if (channelContext != null && !channelContext.isClosed()) {
  int count = getApplyService().getUnreadMsgCount(Long.parseLong(toId));
  body.setCount(count);
  push(channelContext, body);
 }
 } 
/**
 * 服務(wù)端主動(dòng)推送消息
 * */
 private static void push(ChannelContext channelContext,Object msg) {
 try {
  WsResponse response = BodyConvert.getInstance().convertToTextResponse(msg);
  Aio.send(channelContext, response);
 }catch (IOException ex){
 }
 }

現(xiàn)在推送已經(jīng)搞定了,那么什么時(shí)候推送呢?由于這個(gè)系統(tǒng)消息的推送可以不用那么即時(shí),于是我看了下,springboot里面有類似的事件機(jī)制,于是乎 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;
 }
}

在創(chuàng)建一個(gè)Listener,監(jiān)聽(tīng)事件。

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();
  //這里就要調(diào)用上文中的推送了
  PushUtil.pushApplyMessage(toId.toString());
  }
 }.start();
 }
}

不過(guò)我有個(gè)疑問(wèn),發(fā)現(xiàn)listener中執(zhí)行的時(shí)候是同步的。后來(lái)加了@Async 和@EnableAsync 也沒(méi)用,于是我就用了new Thread().start()實(shí)現(xiàn)異步,確保不影響主要申請(qǐng)流程。(這是個(gè)疑問(wèn),自己沒(méi)搞明白的地方)

最后,別忘了在Application啟動(dòng)的時(shí)候把listener加上。

public static void main(String[] args) {
 SpringApplication springApplication = new SpringApplication(LayimApplication.class);
 /**
  * 這里監(jiān)聽(tīng)增加listener,listener才會(huì)觸發(fā)
  * ApplyListener 是監(jiān)聽(tīng)好友申請(qǐng)的事件
  * */
 springApplication.addListeners(new ApplyListener());
 springApplication.run(args);
 }

功能拼接

馬上就要成功了,我們?cè)诎咽录饋?lái),在好友申請(qǐng)成功之后,發(fā)布事件。

/**
 * 好友申請(qǐng)
 * */
 @PostMapping(value = "/apply-friend")
 public JsonResult apply(@RequestParam("toid") Long toId,@RequestParam("remark") String remark){
 JsonResult result = applyService.saveFriendApply(toId, remark);
 //申請(qǐng)成功,發(fā)布申請(qǐng)事件,通知 toId處理消息,如果不在線,不會(huì)進(jìn)行處理
 if(result.isSuccess()){
  applicationContext.publishEvent(new ApplyEvent("apply",toId));
 }
 return result;
 }

功能演示

講了那么多,給大家看一下成品效果。(用戶場(chǎng)景:安小鳥(niǎo)加皇上為好友,皇上接收消息并查看)

 

皇上收到消息,系統(tǒng)彈出左下角的小數(shù)字4。(調(diào)用 layim.msgbox(msgCount) 方法)

 

皇上點(diǎn)開(kāi)消息盒子:

 

皇上收到了四位愛(ài)妃的申請(qǐng),寢食難安,他會(huì)怎么處理呢?欲知后事如何,且聽(tīng)下回分解~~~

總結(jié)

本篇主要介紹了一個(gè)加好友的流程的實(shí)現(xiàn)。

  1. 好友申請(qǐng)按鈕出不出現(xiàn)取決于用戶是否為自己,是否已經(jīng)是好友。(后端也要做驗(yàn)證)
  2. t-io的服務(wù)端主動(dòng)推送,如何調(diào)用。關(guān)鍵詞: ServerGroupContext
  3. event的使用,除了applicationEvent,還可以拓展其他類型,如消息隊(duì)列,eventbus等。
  4. 各種細(xì)節(jié)處理,比如先判斷對(duì)方是否在線,在去查詢數(shù)據(jù)庫(kù)?;蛘呓Y(jié)合緩存等
  5. 由于是自己摸索,難免有代碼繁雜混亂之處,

文中代碼地址: https://github.com/fanpan26/SpringBootLayIM

                           http://xiazai.jb51.net/201712/yuanma/SpringBootLayIM-master.rar

以上所述是小編給大家介紹的SpringBoot+LayIM+t-io 實(shí)現(xiàn)好友申請(qǐng)通知流程,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • JAVA關(guān)鍵字及作用詳解

    JAVA關(guān)鍵字及作用詳解

    本文主要介紹了Java關(guān)鍵字及作用,具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-02-02
  • JVM調(diào)優(yōu)實(shí)戰(zhàn)

    JVM調(diào)優(yōu)實(shí)戰(zhàn)

    本文主要介紹了JVM調(diào)優(yōu)實(shí)戰(zhàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • 第一次編寫(xiě)Java流布局圖形界面

    第一次編寫(xiě)Java流布局圖形界面

    這篇文章主要為大家詳細(xì)介紹了第一次編寫(xiě)Java流布局圖形界面的相關(guān)代碼,感興趣的小伙伴們可以參考一下
    2016-08-08
  • 為什么阿里要慎重使用ArrayList中的subList方法

    為什么阿里要慎重使用ArrayList中的subList方法

    這篇文章主要介紹了為什么要慎重使用ArrayList中的subList方法,subList是List接口中定義的一個(gè)方法,該方法主要用于返回一個(gè)集合中的一段、可以理解為截取一個(gè)集合中的部分元素,他的返回值也是一個(gè)List。,需要的朋友可以參考下
    2019-06-06
  • Mybatis 條件查詢 批量增刪改查功能

    Mybatis 條件查詢 批量增刪改查功能

    這篇文章主要介紹了mybatis 腳本處理語(yǔ)句之條件查詢 批量增刪改查功能,需要的的朋友參考下吧
    2017-06-06
  • 使用MyBatis返回其它類對(duì)象的字段處理

    使用MyBatis返回其它類對(duì)象的字段處理

    這篇文章主要介紹了使用MyBatis返回其它類對(duì)象的字段處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java多線程的臨界資源問(wèn)題解決方案

    Java多線程的臨界資源問(wèn)題解決方案

    這篇文章主要介紹了Java多線程的臨界資源問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Java編程使用箱式布局管理器示例【基于swing組件】

    Java編程使用箱式布局管理器示例【基于swing組件】

    這篇文章主要介紹了Java編程使用箱式布局管理器,結(jié)合實(shí)例形式分析了基于swing組件的箱式布局管理器定義與使用技巧,需要的朋友可以參考下
    2018-01-01
  • IDEA個(gè)性化設(shè)置注釋模板詳細(xì)講解版

    IDEA個(gè)性化設(shè)置注釋模板詳細(xì)講解版

    IDEA自帶的注釋模板不是太好用,我本人到網(wǎng)上搜集了很多資料系統(tǒng)的整理了一下制作了一份比較完整的模板來(lái)分享給大家,下面這篇文章主要給大家介紹了IDEA個(gè)性化設(shè)置注釋模板的相關(guān)資料,需要的朋友可以參考下
    2024-01-01
  • 淺談JDK14性能管理工具之jmap和jhat

    淺談JDK14性能管理工具之jmap和jhat

    我們?cè)趯?xiě)代碼的過(guò)程中,經(jīng)常會(huì)遇到內(nèi)存泄露的問(wèn)題,比如某個(gè)集合中的對(duì)象沒(méi)有被回收,或者內(nèi)存出現(xiàn)不明原因的增長(zhǎng)。這些都是需要我們來(lái)定位的問(wèn)題,我們可以使用jmap和jhat來(lái)對(duì)java程序中的內(nèi)存對(duì)象進(jìn)行分析。
    2021-06-06

最新評(píng)論

岐山县| 海城市| 南华县| 新巴尔虎右旗| 阳江市| 永济市| 昆明市| 花垣县| 青海省| 家居| 二连浩特市| 迭部县| 嵊州市| 莲花县| 宣恩县| 巴东县| 阿巴嘎旗| 南靖县| 龙海市| 迁西县| 勐海县| 将乐县| 泰来县| 兰西县| 乌拉特后旗| 贡觉县| 陆川县| 青阳县| 康定县| 新沂市| 卓资县| 石城县| 西藏| 中牟县| 丽水市| 亚东县| 夏邑县| 明星| 汕尾市| 金湖县| 庐江县|