官方提供的服务器端代码是用nodejs写的(地址https://github.com/sealtalk/sealtalk-server),我需要改成用spring-boot实现。
也是费了好大的功夫。
源码我分享到https://gitee.com/why_su/erongcloud 了,可以参考下,改了一些东西,例如我觉得userId命名不规范,改成了userAccount。
最近才发现融云官方提供了java demo,地址是https://github.com/rongcloud/server-sdk-java ,我弄的时候还没有来着。
融云【单聊】的机制在于,只要知道 两个人的 id,就能互相发送消息,不管是不是好友,所以就需要 我们自己写的后台 来 限制下:不是好友就不能互相聊天。
注意:如果用户 A 把 B 给删了,但在B 的app上还有对话窗口存在的话,此时按照融云的机制, B 还是可以和 A聊天的,这个时候 就需要使用【融云API】把 B 添加到 A 的【黑名单】里面,这样二者就无法通信了。
这里得废话一句:进入融云后台,右上角找到【我的控制台】点击进去,
左下角找到【API调用】,先再这里面调试程序,能起到事半功倍的效果!!
一、数据库表e_rong_cloud_friendship
-- 创建融云-好友关联关系表
CREATE TABLE `e_rong_cloud_friendship` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`user_account` varchar(25) NOT NULL COMMENT '当前用户账号',
`friend_account` varchar(25) NOT NULL COMMENT '好友账号',
`display_name` varchar(32) DEFAULT '' COMMENT 'user对friend设置的备注名',
`message` varchar(64) COMMENT 'user添加friend为好友时的请求信息',
`status` int(10) unsigned COMMENT '10: 请求, 11: 被请求, 20: 同意, 21: 忽略, 30: 被删除',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `friendship_account` (`user_account`,`friend_account`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
二、status定义
好友之间的关系
status值 |
字段 |
说明 |
10 |
REQUESTING |
请求 |
11 |
REQUESTED |
被请求 |
20 |
AGREED |
同意 |
21 |
IGNORED |
忽略 |
30 |
DELETED |
被删除 |
从以下这张截图可以看出:目前数据库一共有维护着4个人的关联关系:
其中 156*** 已接受 187*** 的好友请求, 187***也已接受156***的请求,所以现在156***和187***已经是好友了。
180*** 正在请求 添加184*** 为好友, 184*** 收到了 180*** 发来的添加好友申请,并且看到好友申请消息是【我是xxx】
三、返回格式定义:
public class Response {
/***响应码**/
private Integer code;
/**消息**/
private String msg;
/**消息体**/
private T result;
/**此处是getter和setter*/
}
引入maven:
cn.rongcloud.im
server-sdk-java
3.0.1
四、自定义参数,放在了application.yml中
# 自定义参数
erongcloud:
# 融云appKey
appKey:
# 融云appSecret
appSecret:
# 文件上传根目录
fileRoot:
# 用户默认头像
defaultImage:
# 群组默认头像
defaultGroupImage:
因为需要使用static,所以使用set的方式注入:
@Component
public class ConfigConstant {
/**
* 融云应用AppKey
*/
public static String appKey;
@Value("${erongcloud.appSecret}")
public void setAppSecret(String APP_SECRET) {
appSecret = APP_SECRET;
}
/**
* 融云应用AppSecret
*/
public static String appSecret;
/**
* 融云申请的key
*/
@Value("${erongcloud.appKey}")
public void setAppKey(String APP_KEY) {
appKey = APP_KEY;
}
/**
* 默认空头像URL(用户)
*/
public static String defaultImage;
@Value("${erongcloud.defaultImage}")
public void setDefaultImage(String DEFAULT_IMAGE) {
defaultImage = DEFAULT_IMAGE;
}
/**
* 默认空头像URL(群组)
*/
public static String defaultGroupImage;
@Value("${erongcloud.defaultGroupImage}")
public void setDefaultGroupImage(String DEFAULT_GROUP_IMAGE) {
defaultGroupImage = DEFAULT_GROUP_IMAGE;
}
}
常量类:
public class RongCloudConstant {
/**10: 请求*/
public static final int REQUESTING = 10;
/**11: 被请求*/
public static final int REQUESTED = 11;
/**20: 同意*/
public static final int AGREED = 20;
/**21: 忽略*/
public static final int IGNORED = 21;
/**30: 被删除*/
public static final int DELETED = 30;
/**同意请求*/
public static final String CONTACT_OPERATION_ACCEPT_RESPONSE = "AcceptResponse";
/**请求*/
public static final String CONTACT_OPERATION_REQUEST = "Request";
/**
* 响应码
*/
public static final class Code {
/**
* 成功
*/
public static final int SUCCESS = 200;
}
/**
* 群组相关
*/
public static final class Groups {
/**最大成员数*/
public static final int MAX_MEMBER_COUNT = 500;
public static final String GROUP_OPERATION_CREATE = "Create";
public static final String GROUP_OPERATION_ADD = "Add";
public static final String GROUP_OPERATION_QUIT = "Quit";
public static final String GROUP_OPERATION_DISMISS = "Dismiss";
public static final String GROUP_OPERATION_KICKED = "Kicked";
public static final String GROUP_OPERATION_RENAME = "Rename";
public static final String GROUP_OPERATION_BULLETIN = "Bulletin";
public static final String GROUP_OPERATION_TRANSFER = "Transfer";
/**
* 角色
*/
public static final class Role {
/**
* 群主
*/
public static final int OWNER = 0;
/**
* 普通成员
*/
public static final int NORMAL = 1;
}
}
}
五、发送融云系统消息,单聊消息(这里主要是小灰条),封装成工具类
public class RongCloudUtil {
private static RongCloud rongCloud = RongCloud.getInstance(ConfigConstant.appKey, ConfigConstant.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();
}
}
/**
* 发送群组消息
* @param fromUserId 注意当前用户id不会接收到该消息
* @param toGroupId 群id
*/
public static void sendGroupMessage(String fromUserId, String toGroupId, BaseMessage baseMessage, String pushContent, String pushData){
GroupMessage groupMessage = new GroupMessage()
.setSenderId(fromUserId)
.setTargetId(new String[]{toGroupId})
.setObjectName(baseMessage.getType())
.setContent(baseMessage)
.setPushContent(pushContent)
.setPushData(pushData)
.setIsPersisted(0)
.setIsCounted(0)
.setIsIncludeSender(0)
.setContentAvailable(0);
try {
ResponseResult groupResult = rongCloud.message.group.send(groupMessage);
} 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 friendShipInviteDTO 请求参数
* @return 响应结果
* @author @2021-03-15 18:35
*/
public Response wholeInvite(FriendShipInviteDTO requestDTO) {
// 当前用户账号
String userAccount = requestDTO.getUserAccount();
// 好友账号
String friendAccount = requestDTO.getFriendAccount();
// 添加好友的验证信息
String message = StringUtils.isBlank(requestDTO.getMessage())
? "我是 " + userAccount : requestDTO.getMessage();
// 推送标题
String pushContent = requestDTO.getPushContent();
// 推送内容
String pushData = requestDTO.getPushData();
// 获取当前账号的昵称
RongCloudUserPO rongCloudUserPO = rongCloudUserDao.selectByAccount(userAccount);
if (rongCloudUserPO == null || StringUtils.isBlank(rongCloudUserPO.getNickname())) {
throw new BusinessException(CodeConstant.RongCloud.ACCOUNT_NOT_EXIST, "账号\"" + userAccount + "\"未注册!");
}
String nickName = rongCloudUserPO.getNickname();
// 请求者
RongCloudFriendShipPO requester = rongCloudFriendshipDao.selectByAccount(userAccount, friendAccount);
// 被请求者
RongCloudFriendShipPO friend = rongCloudFriendshipDao.selectByAccount(friendAccount, userAccount);
int requesterStatus, friendStatus;
String action = "Added";
String resultMessage = "无需对方确认,已成功添加好友";
// 通过融云发送好友请求
String extra = "{sourceUserNickname:" + nickName + ",version:123456}";
if (requester != null && friend != null) {
if (requester.getStatus() == RongCloudConstant.AGREED && friend.getStatus() == RongCloudConstant.AGREED) {
return msg(CodeConstant.RongCloud.ALREADY_FRIEND, "你们已经是好友了", null);
}
if (friend.getStatus() == RongCloudConstant.AGREED || friend.getStatus() == RongCloudConstant.REQUESTING) {
requesterStatus = RongCloudConstant.REQUESTING;
friendStatus = RongCloudConstant.REQUESTED;
action = "Sent";
resultMessage = "请求已发送";
} else if ((requester.getStatus() == RongCloudConstant.DELETED && friend.getStatus() == RongCloudConstant.DELETED)
|| (requester.getStatus() == RongCloudConstant.AGREED && friend.getStatus() == RongCloudConstant.DELETED)
|| (requester.getStatus() == RongCloudConstant.REQUESTING && friend.getStatus() == RongCloudConstant.IGNORED)
|| (requester.getStatus() == RongCloudConstant.REQUESTING && friend.getStatus() == RongCloudConstant.REQUESTED)) {
requesterStatus = RongCloudConstant.REQUESTING;
friendStatus = RongCloudConstant.REQUESTED;
action = "Sent";
resultMessage = "请求已发送";
} else {
// 什么都不做
return msg(RongCloudConstant.Code.SUCCESS, "什么都不做.", "None");
}
//更新状态
requester.setStatus(requesterStatus);
friend.setStatus(friendStatus);
requester.setMessage("");
friend.setMessage(message);
requester.setUpdateTime(new Date());
friend.setUpdateTime(new Date());
rongCloudFriendshipDao.update(requester);
rongCloudFriendshipDao.update(friend);
// 通过融云发送好友请求
if (friend.getStatus() == RongCloudConstant.REQUESTED) {
sendContactMessage(RongCloudConstant.CONTACT_OPERATION_REQUEST, userAccount, friendAccount, message, pushContent, pushData, extra);
}
} else {
// 之前没有加过好友
if (userAccount.equals(friendAccount)) {
// 自己加自己无条件通过
saveFriendShip(userAccount, friendAccount, message, RongCloudConstant.AGREED);
} else {
// 请求者的 status为 requesting
saveFriendShip(userAccount, friendAccount, "", RongCloudConstant.REQUESTING);
// 被请求者的 status 为 requested
saveFriendShip(friendAccount, userAccount, message, RongCloudConstant.REQUESTED);
// 通过融云发送好友请求
sendContactMessage(RongCloudConstant.CONTACT_OPERATION_REQUEST, userAccount, friendAccount, message, pushContent, pushData, extra);
}
}
return msg(CodeConstant.Http.SUCCESS, resultMessage, action);
}
六、/agree 同意好友请求
主要在于小灰条,可查看 融云控制台里面的 API调用
public Response wholeAgree(@RequestBody @Validated FriendShipAccountDTO requestDTO) {
// 当前用户id (被请求者)
String userAccount = requestDTO.getUserAccount();
// 请求者
String requestAccount = requestDTO.getFriendAccount();
// 查询账号是否存在
RongCloudUserPO userPO = rongCloudUserDao.selectByAccount(userAccount);
if (userPO == null) {
throw new BusinessException(CodeConstant.RongCloud.ACCOUNT_NOT_EXIST, "账号不存在!");
}
RongCloudUserPO friendUserPO = rongCloudUserDao.selectByAccount(requestAccount);
if (friendUserPO == null) {
throw new BusinessException(CodeConstant.RongCloud.ACCOUNT_NOT_EXIST, "好友账号不存在!");
}
// 更新双方的 status为AGREE
RongCloudFriendShipPO fd = rongCloudFriendshipDao.selectByAccount(userAccount, requestAccount);
RongCloudFriendShipPO fg = rongCloudFriendshipDao.selectByAccount(requestAccount, userAccount);
if (fg != null && fg.getStatus() != RongCloudConstant.REQUESTING
&& fg.getStatus() != RongCloudConstant.AGREED
&& fg.getStatus() != RongCloudConstant.REQUESTED) {
return ResponseUtil.getResponse(CodeConstant.RongCloud.UNKNOW_FRIEND, "无效的好友请求,或者未知好友", null);
}
// 将双方的状态都置为同意
rongCloudFriendshipDao.updateStatus(userAccount, requestAccount, RongCloudConstant.AGREED, new Date(), "");
rongCloudFriendshipDao.updateStatus(requestAccount, userAccount, RongCloudConstant.AGREED, new Date(), "");
// 给请求者 发一条消息说,我同意你的请求了
String extra = "{sourceUserNickname:" + userPO.getNickname() + ",version:123456}";
sendContactMessage(RongCloudConstant.CONTACT_OPERATION_ACCEPT_RESPONSE, userAccount, requestAccount,
"我是" + userAccount + ",我已经同意你的好友请求了", "", "", extra);
// 小灰条通知
RongCloudUtil.sendPrivateMsg(userAccount, requestAccount,
new InformationNtfMessage("你已添加了" + friendUserPO.getNickname() + ",现在可以开始聊天了。", ""));
// 文本消息
RongCloudUtil.sendPrivateMsg(userAccount, requestAccount,
new TxtMessage("我通过了你的朋友验证请求,现在我们可以开始聊天了", ""));
RongCloudUtil.sendPrivateMsg(requestAccount, userAccount,
new TxtMessage(fd.getMessage(), ""));
// 移除黑名单
RongCloudUtil.removeBlackList(userAccount, requestAccount);
RongCloudUtil.removeBlackList(requestAccount, userAccount);
return ResponseUtil.getSuccessResponse();
}
例如: 【十月】请求添加【实话实说】为好友,发送的验证请求内容是“我是十月,通过下”。
【实话实说】同意请求。 此时,【十月】会给【实话实说】发一条 TxtMsg文本消息 (发送的内容就是 它请求的验证消息)
【实话实说】也会发一条消息给【十月】来通知对方我同意了请求(这里有小灰条)
七、/delete 删除好友
注意 只需要 将一方的 status 改为 30 就可以了,并且需要加入融云提供的黑名单,两人才不能通信(不然只要聊天界面还在,两人还是可以聊天的)!
/**
* 逻辑删除好友(将status置为 {@link RongCloudConstant#DELETED})
*
* @param friendShipAccountDTO 请求参数
*/
public void delete(FriendShipAccountDTO requestDTO) {
RongCloudFriendShipPO fg = rongCloudFriendshipDao.selectByAccount(requestDTO.getUserAccount(), requestDTO.getFriendAccount());
if (fg == null || fg.getStatus() != RongCloudConstant.AGREED) {
throw new BusinessException(CodeConstant.RongCloud.REJECT_OPERATION, "你们不是好友关系,不能执行相关操作");
}
fg.setDisplayName("");
fg.setMessage("");
fg.setStatus(RongCloudConstant.DELETED);
fg.setUpdateTime(new Date());
rongCloudFriendshipDao.update(fg);
//添加到黑名单
RongCloudUtil.addBlackList(requestDTO.getUserAccount(), requestDTO.getFriendAccount());
RongCloudUtil.addBlackList(requestDTO.getFriendAccount(), requestDTO.getUserAccount());
}
其它方法不贴了,主要的难点在于,发送融云提供的系统消息,通知对方我要加你为好友了,以及小灰条~
具体代码我已经分享到https://gitee.com/why_su/erongcloud了,可以参考下。