IM系统第三章 -- 对话通知和应答

IM系统第三章 – 对话通知和应答

问题:你是如何实现该功能的?

功能的流程图:

如图:(参照 小傅哥

img

实现功能所需的处理:

  1. 自定义协议;
  2. UI事件实现;
  3. 客户端添加对话功能处理;
  4. 服务端添加对话功能处理;
  5. 服务端删除对话功能处理;

整体的流程来看,在用户发起好友、群组通信的时候,触发一个事件行为,接下来就是客户端向服务端发送与 好友和群组 的对话请求了。

注意:如果是好友的对话,那么需要保存 当前用户与好友的通信信息到我的对话框中,同时通知好友,要开始通信(即双方建立起连接);然后 你在自己的对话框中,将我加入进去。

如果是群组通信,是不需要这样通知的,因为不可能把还没有上线的所有群组用户全部通知(有的还没登录),所以这部分只需要在用户上线后收到信息后,创建出对话框到列表即可。

自定义协议:(两台机器想要进行通信,就需要协议,也就是说两台机器是通过以下的自定义通信协议来达到相应的结果

实现该功能需要实现三个协议:对话框通知请求协议、对话框通知请求应答 协议、删除对话框协议

// 抽象协议类
public abstract class Packet {
	private final static Map<Byte, Class<? extends Packet>> packetType = new ConcurrentHashMap<>();
    static{
        packetType.put(Command.TalkNoticeRequest, TalkNoticeRequest.class);
        packetType.put(Command.TalkNoticeResponse, TalkNoticeResponse.class);
        packetType.put(Command.DelTalkRequest,DelTalkRequest.class)
    }
}

接下来就是三个协议类:

// 对话框通知请求协议
public class TalkNoticeRequest extends Packet{
    private String userId; // 用户Id(自己的)
    private String friendUserId; // 好友Id
    private Integer talkType; // 对话框类型[0好友 1群组]
    构造函数...
    get()/set()...
}

// 对话框通知请求应答 协议
public class TalkNoticeResponse extends Packet{
    private String talkId; // 对话框Id[0好友 1群组]
    private String talkName; // 对话框名称[好友名称、群名称]
    private String talkHead; // 对话框头像[好友头像、群头像]
    private String talkSketch; // 消息简讯
    private Date talkDate; // 消息时间
    get()/set() ...
}

// 删除对话框协议
public class DelTalkRequest extends Packet{
    private String userId; // 用户Id
    private String talkId; // 对话框Id
    构造函数...
    get()/set()
}

因为用户发起 好友或者群组聊天 时,会触发”发送消息“事件,所以需要在客户端的 event包下定义事件了。

// ChatEvent类中
public class ChatEvent implements IChatEvent {
    /**
     * 添加与用户的对话框
     * @param userId       用户ID
     * @param userFriendId 好友ID
     */
    @Override
    public void doEventAddTalkUser(String userId, String userFriendId) {
    	Channel channel = BeanUtil.getBean("channel",Channel.class);
        channel.writeAndFlush(new TalkNoticeRequest(userId,userFriendId,0));
    }

    /**
     * 添加与群组的对话框
     * @param userId  用户ID
     * @param groupId 群组ID
     */
    @Override
    public void doEventAddTalkGroup(String userId, String groupId) {
        Channel channel = BeanUtil.getBean("channel", Channel.class);
        channel.writeAndFlush(new TalkNoticeRequest(userId, groupId, 1));
    }

    /**
     * 删除与用户的对话框
     * @param userId 用户ID
     * @param talkId 对话框ID
     */
    @Override
    public void doEventDelTalkUser(String userId, String talkId) {
        Channel channel = BeanUtil.getBean("channel", Channel.class);
        channel.writeAndFlush(new DelTalkRequest(userId, talkId));
    }
}

接下来就是客户端 对话请求的处理 了:

public class TalkNoticeHandler extends SimpleChannelInboundHandler<TalkNoticeResponse> {

    private UIService uiService;

    public TalkNoticeHandler(UIService uiService) {
        this.uiService = uiService;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TalkNoticeResponse msg) throws Exception {
        IChatMethod chat = uiService.getChat();
        Platform.runLater(() -> {
            /**
             * UI界面 其中
             * talkIdx 默认为-1 首位为0
             * talkType好友为0 群组为1
             * msg.getTalkId() 1v1聊天Id、1vn聊天Id
             * 对话框名称
             * 对话框头像
             * 对话框通信简介(聊天内容最后一组消息)
             * 对话框时间
             * 是否选中当前对话框
             */
            chat.addTalkBox(-1, 0, msg.getTalkId(),
                    msg.getTalkName(), msg.getTalkHead(), msg.getTalkSketch(), msg.getTalkDate(), false);
        });
    }
}

服务端对 对话请求 处理:

由这个流程图我们也得知,服务端需要处理 好友之间的对话连接,对话框消息的落库、和好友之间的对话通知以及群聊的对话。

既然有好友和群组的对话区别,而且种类不多(msg.getTalkType() 就两个),我们完全可以用switch分支来进行分别的处理。其中,单人的对话框建立是重点,是需要双方都需要建立对话通知的,而群组只需要单方面建立通知即可(因为不可能所有人都在线)

/*
注释:
这里的MyBizHandler也是一个抽象类,该类继承了SimpleChannelInboundHandler<T>类,该类还自己创建了channelRead()抽象方法由继承MyBizHandler的子类去实现
下面中的UserService是操作数据库的一个接口类
*/
public class TalkNoticeHandler extends MyBizHandler<TalkNoticeRequest>{
    @Override
    public void channelRead(Channel channel, TalkNoticeRequest msg) {
        logger.info("对话通知应答处理:{}", JSON.toJSONString(msg));
        switch(msg.getTalkType()){
           case 0:  // 好友
               // 1.对话框的数据落库(创建对话框到消息列表)
               userService.addTalkBoxInfo(msg.getUserId(),msg.getFriendUserId(),0);
               userService.addTalkBoxInfo(msg.getFriendUserId(),msg.getUserId(),0);
                
               // 2.查询对话框信息[自己 发送给好友的对话框]
                UserInfo userInfo = userService.queryUserInfo(msg.getUserId());
                // 3.发送对话框消息给好友
                TalkNoticeResponse response = new TalkNoticeResponse();
                response.setTalkId(userInfo.getUserId());
                response.setTalkName(userInfo.getUserNickName());
                response.setTalkHead(userInfo.getUserHead());
                response.setTalkSketch(null);
                response.setTalkDate(new Date());
                
                // 获取好友通道
                Channel friendChannel = SocketChannelUtil.getChannel(msg.getFriendId());
                if (null == friendChannel) {
                    logger.info("用户id:{}未登录!", msg.getFriendUserId());
                    return;
                }
                friendChannel.writeAndFlush(response);
                break;
            case 1: // 群组
                userService.addTalkBoxInfo(msg.getUserId(), msg.getFriendUserId(), 1);
                break;
            default:
                break; 
        }
    }
}

删除对话框通知 服务端:

当用户点击 删除对话框时 就会触发一个删除对话框事件,当然上面已经写了,就不复述了。服务端需要对这个删除操作进行处理:根据userIdTalkId直接操作数据库删除对话框即可。

public class DelTalkHandler extends MyBizHandler<DelTalkRequest> {
    @Override
    public void channelRead(Channel channel, DelTalkRequest msg) {
        userService.deleteUserTalk(msg.getUserId(), msg.getTalkId());
    }
}

总结

对话通知和应答 这个功能也不是很复杂,实现的步骤也是从自定义协议开始,这里比上一章多了事件的行为。因为需要点击 ”发送消息“ 才会显示对话框出来的;铺垫完这些后,客户端就 利用 TalkNoticeResponse 协议的属性 与UI模块的接口进行处理(这块简略即可),客户端的工作到此为止;服务端的工作就是 也是进行对话的处理(利用 TalkNoticeRequest 协议),但是除了这些还需要和好友之间进行对话框的落库,好友对话框的通知建立、以及群组的对话框通知建立(但是这里只需要自己通知就好,不需要与群的每个人都建立对话框通知)和最后的删除对话框的处理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值