官方提供的服务器端代码是用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();
}
其它方法不贴了,主要的难点在于,发送融云提供的系统消息,通知对方我要加你为好友了,以及小灰条~