1. 程式人生 > >融雲java伺服器端--好友關係

融雲java伺服器端--好友關係

官方提供的伺服器端程式碼是用nodejs寫的(地址https://github.com/sealtalk/sealtalk-server),我需要改成用spring-boot實現。

也是費了好大的功夫。

融雲【單聊】的機制在於,只要知道 兩個人的 id,就能互相傳送訊息,不管是不是好友,所以就需要 我們自己寫的後臺 來 限制下:不是好友就不能互相聊天。 

注意:如果使用者 A  把 B 給刪了,但在B 的app上還有對話視窗存在的話,此時按照融雲的機制, B 還是可以和 A聊天的,這個時候 就需要使用【融雲API】把 B 新增到 A 的【黑名單】裡面,這樣二者就無法通訊了。

這裡得廢話一句:進入融雲後臺,右上角找到【我的控制檯】點選進去

左下角找到【API呼叫】,先再這裡面除錯程式,能起到事半功倍的效果!!

一、資料庫表rongcloud_friendship

CREATE TABLE `rongcloud_friendship` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` varchar(25) NOT NULL COMMENT '當前使用者id',
  `friend_id` varchar(25) NOT NULL COMMENT '好友id',
  `display_name` varchar(32) DEFAULT '' COMMENT '備註名',
  `message` varchar(64) DEFAULT NULL COMMENT '加好友時的“請求資訊”',
  `status` int(10) unsigned DEFAULT NULL COMMENT '10: 請求, 11: 被請求, 20: 同意, 21: 忽略, 30: 被刪除',
  `create_time` datetime DEFAULT NULL COMMENT '建立時間',
  `update_time` datetime DEFAULT NULL COMMENT '更新時間',
  PRIMARY KEY (`id`),
  UNIQUE KEY `friendship_user_id_friend_id` (`user_id`,`friend_id`)
) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8;

二、status定義

好友之間的關係

status

欄位

說明

10

REQUESTING

請求

11

REQUESTED

被請求 

20

AGREED

同意

21

IGNORED

忽略

30

DELETED

被刪除

一張圖瞭解:

三、返回格式定義:

public class RongCloudResultDataObject<T> {
    /***錯誤程式碼**/
    private Integer code;
    /**訊息**/
    private String msg;
    /**訊息體**/
    private T result;
     
    /**此處是getter和setter*/
}

public class RongCloudResultUtil {
    public static RongCloudResultDataObject success(int code, String msg, Object object){
        RongCloudResultDataObject resultObject = new RongCloudResultDataObject();
        resultObject.setCode(code);
        resultObject.setMsg(msg);
        resultObject.setResult(object);
        return resultObject;
    }

    /**
     * 定義錯誤返回格式
     * @param code
     * @param msg
     * @return
     */
    public static RongCloudResultDataObject error(Integer code , String msg){
        RongCloudResultDataObject resultObject = new RongCloudResultDataObject();
        resultObject.setCode(code);
        resultObject.setMsg(msg);
        return resultObject;
    }
}

引入maven:

<dependency>
    <groupId>cn.rongcloud.im</groupId>
    <artifactId>server-sdk-java</artifactId>
    <version>3.0.1</version>
</dependency>

四、傳送融雲系統訊息,單聊訊息(這裡主要是小灰條),封裝成工具類

public class CommonUtil {
    /**你的key和secret*/
    public static final String appKey = "";
    public static final String appSecret = "";
    
    //預設空頭像(使用者)
    public static final String DEFAULT_IMAGE = "112.jpg";
    private static RongCloud rongCloud = RongCloud.getInstance(appKey,appSecret);
    /**
     * 通過融雲傳送系統資訊,詳見https://www.rongcloud.cn/docs/message_architecture.html#group_notification_message
     * @param senderId 傳送人
     * @param targetIds 接收人(陣列)
     * @param baseMessage 訊息內容
     * @param pushContent 推送內容
     * @param pushData 推送資料
     */
    public static void sendSystemMessage(String senderId, String[] targetIds, BaseMessage baseMessage, String pushContent, String pushData){
        SystemMessage systemMessage = new SystemMessage()
                .setSenderId(senderId)
                .setTargetId(targetIds)
                .setObjectName(baseMessage.getType())
                .setContent(baseMessage)
                .setPushContent(pushContent)
                .setPushData(pushData)
                .setIsPersisted(0)
                .setIsCounted(0)
                .setContentAvailable(0);
        try {
            rongCloud.message.system.send(systemMessage);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 通過融雲傳送單聊訊息
     */
    public static void sendPrivateMsg(String senderId, String targetId, BaseMessage baseMessage){
        PrivateMessage privateMessage = new PrivateMessage()
                .setSenderId(senderId)
                .setTargetId(new String[]{targetId})
                .setObjectName(baseMessage.getType())
                .setContent(baseMessage)
                .setPushContent("")
                .setPushData("")
                .setCount("")
                .setVerifyBlacklist(0)
                .setIsPersisted(0)
                .setIsCounted(0)
                .setIsIncludeSender(0);
        //傳送單聊方法
        try {
            rongCloud.message.msgPrivate.send(privateMessage);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 移除黑名單
     */
    public static void removeBlackList(String userId,String friendId){
        UserModel user = getUserModel(userId,friendId);
        try {
            rongCloud.user.blackList.remove(user);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 新增黑名單
     */
    public static void addBlackList(String userId,String friendId){
        UserModel user = getUserModel(userId,friendId);
        try {
            rongCloud.user.blackList.add(user);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static UserModel getUserModel(String userId,String friendId){
        UserModel blackUser = new UserModel().setId(userId);
        UserModel[] blacklist = {blackUser};
        UserModel user = new UserModel()
                .setId(friendId)
                .setBlacklist(blacklist);
        return user;
    }
}

五、/invite 發起好友請求:(其實主要就是   判斷 status 的值,再更改status的值 )

/**
 * @param userId 請求者
 * @param friendId 被請求者
 * @param message 請求者發出的“驗證訊息”
 * @param pushContent 推送
 * @param pushData 推送內容
 */
@PostMapping("/invite")
public RongCloudResultDataObject invite(@RequestBody Map<String,Object> map){
      if(map.get("userId") == null || map.get("friendId") == null){
        return RongCloudResultUtil.error(1001,"userId,friendId不能為null");
      }
      String userId = map.get("userId").toString(); //當前使用者id
      String friendId = map.get("friendId").toString(); //要新增的好友id
      if(Objects.equals(userId, "") || Objects.equals(friendId, "")){
          return RongCloudResultUtil.error(1001,"userId,friendId必需有值");
      }

      String message = map.get("message") == null ? "我是 "+ userId : map.get("message").toString();//新增好友的驗證資訊 的預設值
      String pushContent = map.get("pushContent") == null ? "": map.get("pushContent").toString(); //推送
      String pushData = map.get("pushData") == null ? "" : map.get("pushData").toString();  //推送內容

      //該方法執行的sql語句是:select * from rongcloud_friendship where user_id = ?1 and friend_id = ?2
      //資料庫有兩條記錄,檢視這兩個使用者之間的關係
      //請求者
      FriendShip fg = friendShipService.findByUserIdAndFriendId(userId, friendId);
      //被請求者
      FriendShip fd = friendShipService.findByUserIdAndFriendId(friendId,userId);
      
      int fgStatus,fdStatus;
      String action = "Added";
      String resultMessage = "無需對方確認,已成功新增好友";

      //獲得使用者的暱稱
      User user = userService.findByAccount(userId);
      String extra = "{sourceUserNickname:"+ user.getNickname() + ",version:123456}";

      //資料庫沒有這兩條記錄,說明是第一次新增(後面刪掉好友的時候,僅僅是改變status的值)
      if(fg != null && fd != null){
         //status都為20表示已經是好友,無需再申請新增
         if(fg.getStatus() == AGREED && fd.getStatus() == AGREED){
             return RongCloudResultUtil.error(400, "你們已經是好友了");
         }
         if(fd.getStatus() == AGREED ||  fd.getStatus() == REQUESTING){
             fgStatus = REQUESTING;
             fdStatus = REQUESTED;
             action = "Sent";
             resultMessage = "請求已傳送";
         }else if((fg.getStatus() == DELETED && fd.getStatus() == DELETED) || (fg.getStatus() == AGREED && fd.getStatus() == DELETED) || (fg.getStatus() == REQUESTING && fd.getStatus() == IGNORED) || (fg.getStatus() == REQUESTING && fd.getStatus() == REQUESTED)){
             fgStatus = REQUESTING;
             fdStatus = REQUESTED;
             action = "Sent";
             resultMessage = "請求已傳送";
         }else{
             return msg(200, "什麼都不做.","None");
         }
         //更新狀態
         fg.setStatus(fgStatus);
         fd.setStatus(fdStatus);
         fd.setMessage(message);
         fg.setUpdateTime(new Date());
         fd.setUpdateTime(new Date());
         //這裡執行的sql語句就是update語句
         friendShipService.update(fg);
         friendShipService.update(fd);

         //通過融雲傳送系統訊息,提醒對方**請求新增您為好友
         if(fd.getStatus() == REQUESTED){     
         sendContactMessage(CONTACT_OPERATION_REQUEST,userId,friendId,message,pushContent
                     ,pushData,extra);
         }
         return RongCloudUtils.success(resultMessage,action);
      }else{
         //之前沒有加過好友
         //更新請求者的 status為 requesting 10
         saveFriendShip(userId,friendId, "", REQUESTING);
         //更新被請求者的 status 為 requested 11
         saveFriendShip(friendId,userId,message,REQUESTED);
                
         sendContactMessage(CONTACT_OPERATION_REQUEST,userId,friendId,message,pushContent
                      ,pushData,extra);
             return msg(200, "請求已傳送","Sent");
         }
     }
  }

  private void sendContactMessage(String contact,String senderId,String targetId,String message,String pushContent,String pushData,String extra){
        ContactNtfMessage contactNtfMessage = new ContactNtfMessage(contact,extra,senderId,targetId,message);
        CommonUtil.sendSystemMessage(senderId,new String[]{targetId},contactNtfMessage,pushContent,pushData);
    }

六、/agree 同意好友請求

主要在於小灰條,可檢視 融雲控制檯裡面的 API呼叫

    /**
     * 同意好友請求
     * @param userId 同意新增 friendId為好友
     */
    @PostMapping("/agree")
    public RongCloudResultDataObject agree(@RequestBody Map<String,Object> map){
        if(map.get("userId") == null || map.get("friendId") == null){
            return RongCloudResultUtil.error(1001,"userId,friendId不能為null");
        }
        String userId = map.get("userId").toString(); //當前使用者id (被請求者)
        String friendId = map.get("friendId").toString(); //請求者
        if(Objects.equals(userId, "") || Objects.equals(friendId, "")){
            return RongCloudResultUtil.error(1001,"userId,friendId必需有值");
        }

        //更新雙方的 status為  AGREE
        //該方法執行的sql語句是:select * from rongcloud_friendship where user_id = ?1 and friend_id = ?2
        FriendShip fg = friendShipService.findByUserIdAndFriendId(friendId,userId);
        FriendShip fd = friendShipService.findByUserIdAndFriendId(userId,friendId);
        if(fg.getStatus() != REQUESTING && fg.getStatus() != AGREED && fg.getStatus() != REQUESTED){
            return RongCloudResultUtil.error(404,"無效的好友請求,或者未知好友");
        }
        friendShipService.updateStatus(userId,friendId,AGREED,new Date(),"");
        friendShipService.updateStatus(friendId,userId,AGREED,new Date(),"");
        //給請求者 發一條訊息說,我同意你的請求了
        User user = userService.findByAccount(userId);
        User friend = userService.findByAccount(friendId);
        String extra = "{sourceUserNickname:"+ user.getNickname() + ",version:123456}";
        sendContactMessage(CONTACT_OPERATION_ACCEPT_RESPONSE,userId,friendId,"我是"+userId+",我已經同意你的好友請求了","","",extra);
        //小灰條通知
        CommonUtil.sendPrivateMsg(userId,friendId,new InformationNtfMessage("你已添加了"+ friend.getNickname() +",現在可以開始聊天了。",""));
        //傳送文字訊息
        CommonUtil.sendPrivateMsg(userId,friendId,new TxtMessage("我通過了你的朋友驗證請求,現在我們可以開始聊天了",""));
        CommonUtil.sendPrivateMsg(friendId,userId,new TxtMessage(fd.getMessage(),""));

        //移除黑名單
        CommonUtil.removeBlackList(userId,friendId);
        CommonUtil.removeBlackList(friendId,userId);

        return RongCloudResultUtil.success();
    }

例如:  【十月】請求新增【實話實說】為好友,傳送的驗證請求內容是“我是十月,通過下”。

【實話實說】同意請求。 此時,【十月】會給【實話實說】發一條  TxtMsg文字訊息 (傳送的內容就是 它請求的驗證訊息)

【實話實說】也會發一條訊息給【十月】來通知對方我同意了請求(這裡有小灰條)

七、/delete   刪除好友

注意 只需要 將一方的 status 改為  30 就可以了,並且需要加入融雲提供的黑名單,兩人才不能通訊(不然只要聊天介面還在,兩人還是可以聊天的)!

    /**
     * 邏輯刪除(修改status為30)
     * @param map
     * @return
     */
    @PostMapping("/delete")
    public RongCloudResultDataObject delete(@RequestBody Map<String,Object> map){
        if(map.get("userId") == null || map.get("friendId") == null){
            return RongCloudResultUtil.error(1001,"userId,friendId欄位是必需的");
        }
        String userId = map.get("userId").toString(); //當前id
        String friendId = map.get("friendId").toString(); //好友id
        if(Objects.equals(userId, "") || Objects.equals(friendId, "")){
            return RongCloudResultUtil.error(1001,"userId,friendId必需有值");
        }

        FriendShip fg = friendShipService.findByUserIdAndFriendId(userId,friendId);
        if(fg == null || fg.getStatus() != AGREED){
            return RongCloudResultUtil.error(405,"你們不是好友關係,不能執行相關操作");
        }
        //把好友備註給清空下
        fg.setDisplayName("");
        fg.setMessage("");
        fg.setStatus(DELETED);
        fg.setUpdateTime(new Date());
        friendShipService.update(fg);

        //新增到黑名單
        CommonUtil.addBlackList(userId,friendId);
        CommonUtil.addBlackList(friendId,userId);
        return RongCloudResultUtil.success();
    }

其它方法不貼了,主要的難點在於,傳送融雲提供的系統訊息,通知對方我要加你為好友了,以及小灰條~