IM系统第一章 – 登录功能的实现
你是如何完成该功能的?
实现思路:我们可以想象一下微信qq的登录方式(我们预先在表中设置好了用户名单,就不需要注册了),来到一个登录窗口,输入完账号密码后就点击 ”登录“ 事件,然后将登录的请求协议 信息传入给服务端处理;服务端将请求协议的信息 与从数据库中获取到的信息进行查询校验后,将结果返回;若校验正确,还需要将该用户的 数据初始化(比如该用户和好友的通信记录,群组的通信记录等。。)并将这些结果返回给客户端,客户端根据请求应答 协议调用UI事件接口进行处理显示。
上面描述转化为下面的流程图 为:(参考 小傅哥)
依旧是下面几个步骤:
- 自定义协议包;
- UI事件处理;
- 服务端对请求 协议进行处理;
- 客户端对请求应答 协议进行处理;
自定义协议:LoginRequest
(登录请求协议)、LoginResponse
(登录反馈协议)
public class LoginRequest extends Packet {
private String userId;
private String password;
构造函数...
set()/get()...
}
public class LoginResponse extends Packet {
private String userId; // 用户Id
private String userHead;// 用户头像
private String nickName;// 用户昵称
private boolean success;// 校验结果
private List<ChatTalkDto> chatTalkDtoList = new ArrayList<>(); // 聊天对话框数据[success is true]
private List<GroupDto> groupsDtoList = new ArrayList<>(); // 群组列表
private List<UserFriendDto> userFriendDtoList = new ArrayList<>(); // 好友列表
构造函数...
get()/set()...
}
再来看UI事件定义
public class LoginEvent implements ILoginEvent {
// 事件登录校验
@Override
public void doLoginCheck(String userId,String userPassword) {
Channel channel = BeanUtil.getBean("channel",Channel.class);
// 将账号密码通过 登录请求协议一并通过channel送过去
channel.writeAndFlush(new LoginRequest(userId,userPassword));
// 记录当前的用户的用户id(是为了后面断线重连)
CacheUtil.userId = userId;
}
}
服务端:服务端负责的工作在前面 实现该功能的逻辑中 说的很清楚,这里不赘述;
将上面的逻辑转化为代码如下:
/*
注意:代码中涉及到的**Dto 其实都是跟PO相关的,只不过就是如果有些数据不需要加入或者多了某些字段就自行增加 **Dto这个类来替代。。
*/
public class LoginHandler extends MyBizHandler<LoginRequest> {
@Override
public void channelRead(Channel channel, LoginRequest msg) {
// 1.登录失败
boolean auth = userService.checkAuth(msg.getUserId(), msg.getUserPassword());
if(!auth) {
channel.writeAndFlush(new LoginResponse(false));
return;
}
// 2.登录成功绑定Channel
// 2.1 绑定用户id channel
SocketChannelUtil.addChannel(msg.getUserId(),channel);
// 2.2绑定群组 channel
List<String> groupsIdList = userService.queryUserGroupsIdList(msg.getUserId());
for (String groupId : groupsIdList) {
SocketChannelUtil.addChannelGroup(groupId, channel);
}
// 3.反馈消息:用户消息、用户对话框消息、好友列表、群组列表
// 组装消息包
LoginResponse loginResponse = new LoginResponse();
// 3.1 用户消息
UserInfo userInfo = userService.queryService.queryUserInfo(msg.getUserId());
// 3.2对话框消息
List<TalkBoxInfo> talkBoxInfoList = userService.queryTalkBoxInfoList(msg.getUserId());
for (TalkBoxInfo talkBoxInfo : talkBoxInfoList) {
/*
下面就是对LoginResponse消息包中List<ChatTalkDto> chatTalkDtoList(聊天对话框列表)、List<GroupDto> groupsDtoList(群组列表)、List<UserFriendDto> userFriendDtoList(好友列表)进行包装,然后通过channel发 送 (因为代码太多,且容易理解就不发了)
*/
}
// 传输消息
channel.writeAndFlush(loginResponse);
}
客户端接收到 来自服务端发送的 协议(LoginResponse
)后,主要是进行调用UI接口进行信息的展示。(代码不展示了,暂时不是重点)
总结
最后我们回忆一下,实现该登录功能的逻辑:主要是服务端方面,需要对用户的channel
进行绑定、对用户的群组channelGroup
也需要进行绑定(至于为什么不绑定与好友的channel
,我猜是因为只有建立双方通话的时候才需要绑定),就需要将请求应答 协议LoginResponse
的内容进行填充(利用mybatis
操作数据库);然后一并发给客户端处理就可以完成了。大概的流程就是如此;
最后还有就是服务端中配置的问题需要注意