IM系统第五章 -- 用户与群组通信

文章描述了如何在IM系统中实现用户与群组的通信功能。关键步骤包括使用自定义的MsgGroupRequest和MsgGroupResponse协议,处理UI事件,以及在服务器端管理ChannelGroup来广播消息。服务端获取群组管道,异步存储消息到数据库,并通过ChannelGroup将消息分发给群内所有用户。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

IM系统第五章 – 用户与群组通信

你是如何完成这个功能的?

实现该功能的流程是:

用户与群组的好友聊天,前提也是,你已经点开了相应的对话框(上两节已经实现了);这个群组的设置是一登陆就有的,也就说是默认的。实现逻辑就是:将群里的用户的channel管道全部放到ChannelGroup中进行群发消息,只要在这个通信管道里的用户都能收到消息。

上述描述转换为逻辑图如下(参照 小傅哥

img

实现功能所需的处理:

  1. 自定义协议;
  2. UI事件实现;
  3. 服务端与群组通信功能处理;
  4. 客户端与群组通信功能处理;

自定义通信协议:MsgGroupRequestMsgGroupResponse

// 群组消息请求 协议
public class MsgGroupRequest extends Packet {
    private String userId;   // 群员ID
    private String talkId;   // 对话框ID
    private String msgText;  // 消息内容
    private Integer msgType; // 消息类型
    private Date msgDate;    // 消息时间
    构造函数...
    get()/set()...
}

// 群组消息请求应答 协议
public class MsgGroupResponse extends Packet {
    private String talkId;      // 对话框ID
    private String userId;      // 群员ID
    private String userNickName;// 群员用户昵称
    private String userHead;    // 群员用户头像
    private String msgText;     // 消息内容
    private Date msgDate;       // 消息时间
    private Integer msgType;    // 消息类型 表情包/文字内容
    构造函数...
    get()/set()...
}

自定义协议完成后,接下来还是和好友通信一样,完成UI事件的定义

public class ChatEvent implements IChatEvent {
    /**
     * 消息发送
     *
     * @param userId   用户Id
     * @param talkId   对话Id(好友ID/群组ID)
     * @param talkType 对话框类型;0好友、1群组
     * @param msg      发送消息内容
     * @param msgType  消息类型;0文字消息、1固定表情
     * @param msgDate  发送消息时间
     */
    @Override
    public void doSendMsg(String userId, String talkId, Integer talkType, String msg, Integer msgType, Date msgDate) {
        Channel channel = BeanUtil.getBean("channle", Channel.class);
        if(talkType == 0) {
            channel.writeAndFlush(new MsgRequest(userId, talkId, msg, msgType, msgDate));
        }
        if(talkType == 1) {
            channel.writeAndFlush(new MsgGroupRequest(userId, talkId, msg, msgType, msgDate));
        }
    }
}

接下来是客户端的处理 消息请求应答 协议的内容,调用UI事件的接口来完成处理;

public class MsgGroupHandler extends MyBizHandler<MsgGroupResponse> {
    @Override
    public void channelRead(Channel channel, MsgGroupResponse msg) {
        IChatMethod chat = uiService.getChat();
        Platform.runLater(() -> {
            /**
            填充对话框消息 - 群组[别人发来的消息]
            * @param talkId       对话框ID[群组ID]
    		* @param userId       用户ID[群员]
     		* @param userNickName 用户昵称
     		* @param userHead     用户头像
     		* @param msg          消息
     		* @param msgType      消息类型;0文字消息、1固定表情
     		* @param msgDate      时间
     		* @param idxFirst     是否设置首位
     		* @param selected     是否选中
     		* @param isRemind     是否提醒
            */
            chat.addTalkMsgGroupLeft(msg.getTalkId(), msg.getUserId(), msg.getUserNickName(), msg.getUserHead(), msg.getMsg(), msg.getMsgType(), msg.getMsgDate(), true, false, true);
        });
    }
}

接下来就是服务端处理 消息请求 协议的内容了,服务端负责的内容是:因为前面讲到,需要将群组的用户的channel 收集起来放在channelGroup中,所以首先获取群组管道;然后开始异步存储消息(上一节说过了),然后将信息发在channelGroup中,由channelGroup分发给各个用户的channel即可;代码如下:

// 消息群组处理器(服务端)
public class MsgGroupHandler extends MyBizHandler<MsgGroupRequest> {
    @Override
    public void channelRead(Channel channel, MsgGroupRequest msg) {
        // 获取群组消息通信管道
        ChannelGroup channelGroup = SocketChannelUtil.getChannelGroup(msg.getTalkId());
        if (null == channelGroup) { // 如果管道为空
            // 添加 群组管道 在缓存中
            SocketChannelUtil.addChannelGroup(msg.getTalkId(), channel);
            // 通过 请求协议中的对话框类型 在缓存中获取到群组管道
            channelGroup = SocketChannelUtil.getChannelGroup(msg.getTalkId());
        }
        // 将消息利用多线程的方式异步落库
        userService.asyncAppendChatRecord(new ChatRecordInfo(msg.getUserId(), msg.getTalkId(), msg.getMsgText(), msg.getMsgType(), msg.getMsgDate(), Constants.TalkType.Group.getCode()));
        // 根据消息协议的用户id获取每个用户传输对象
        UserInfo userInfo = userService.queryUserInfo(msg.getUserId());
        MsgGroupResponse msgGroupResponse = new MsgGroupResponse();
        msgGroupResponse.setTalkId(msg.getTalkId());
        msgGroupResponse.setUserId(msg.getUserId());
        msgGroupResponse.setUserNickName(userInfo.getUserNickName());
        msgGroupResponse.setUserHead(userInfo.getUserHead());
        msgGroupResponse.setMsg(msg.getMsgText());
        msgGroupResponse.setMsgType(msg.getMsgType());
        msgGroupResponse.setMsgDate(msg.getMsgDate());

        channelGroup.writeAndFlush(msgGroupResponse);
    }
}

到了这个之后和 用户与好友通信部分就没什么不一样了(且将消息异步落库也是和前一章的内容相同);也是操作mybatis的将数据放入到数据库的过程。。。

总结

这里只需要提出一点即可:

用户与好友通信一节最大的不同是:在服务端的处理上,需要将群组管道channelGroup获取到,然后将 群组消息请求应答 协议(MsgGroupResponse)的内容包装传给channelGroup,让其分发给每个用户的channel即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值