IM系统第二章 -- 搜索好友和添加好友

IM系统第二章 – 搜索好友和添加好友

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

首先,我们得知道该功能的实现流程。

当客户端A 从窗体打开搜索栏时 — 》开始搜索 — 》搜索好友 — 》搜索完成 — 》处理结果 — 》用户点击添加好友 — 》添加操作 — 》执行添加 — 》双向添加好友 — 》处理结果 — 》显示

上面的流程用图概括就是(图片参照 小傅哥

img

实现流程图中的主要功能涉及到的操作为:

  1. 自定义协议
  2. 客户端实现搜索好友的处理
  3. 服务端实现搜索好友的处理
  4. 客户端实现添加好友的处理
  5. 服务端实现添加好友的处理

自定义协议:(协议是用来交流的基本,双方都需要遵循这个协议才能进行数据传送)

需要实现四个协议:搜索好友的请求协议、添加好友的请求协议、搜索好友请求响应的协议、添加好友请求响应的协议

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

四个协议都作为单独的类来实现:

// 搜索好友请求 协议
public class SearchFriendRequest extends Packet{
	private String userId; // 用户Id
    private String searchKey; // 搜索字段 
    get()/set()...
}

// 搜索好友请求应答 协议
public class SearchFriendResponse extends Packet {
    // 存储用户 数据传输对象 的集合
    private List<UserDto> list;
}

// 添加好友请求协议
public class AddFriendRequest extends Packet {
    private String userId; // 自己的Id
    private String friendId; // 好友的Id
    get()/set()...
}

// 添加好友请求应答的协议
public class AddFriendResponse extends Packet{
    private String friendId; // 好友的Id
    private String friendNickName; // 好友的昵称
    private String friendHead; // 好友的头像
    get()/set()...
}

再来看看 传输数据对象 (DTO):也就是说客户端和服务端之间 真正传送的数据对象是这些。

// 用户 数据传输对象
public class UserDto {
    private String userId; // 用户Id
    private String userNickName; // 用户昵称
    private String userHead; // 用户头像
    private Integer status; // 状态:0添加、1【保留】、2已添加
    构造函数...
	get()/set()...
}

// 用户 模糊对象
public class LuckUserInfo{
    private String userId;       //用户ID
    private String userNickName; //用户昵称
    private String userHead;     //用户头像
    private Integer status;      // 状态;0添加、1[保留]、2已添加
    构造函数...
	get()/set()...
}

// 用户好友
public class UserFriend {
    private Long id; // 自增ID
    private String userId; // 用户ID
    private String userFriendId; // 好友用户ID
    private Date createTime; // 创建时间
    private Date updateTime; // 更新时间
    构造函数...
	get()/set()...
}

自定义完协议后,开始实现 客户端和UI界面的搜索好友的 逻辑(这段简略说说就好)

搜索好友 客户端:

// 搜索好友 处理器
public class SearchFriendHandler extends SimpleChannelInboundHandler<SearchFriendResponse> {

    private UIService uiService;

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

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, SearchFriendResponse msg) throws Exception {
        List<UserDto> list = msg.getList();
        if(null == list || list.isEmpty()) return;
        IChatMethod chat = uiService.getChat();
        Platform.runLater(() -> {
            for (UserDto user : list) {
                // 界面出现好友 “添加好友”的字样(类似于你搜索好友后,你要点击是否添加)
                chat.addLuckFriend(user.getUserId(), user.getUserNickName(), user.getUserHead(), user.getStatus());
            }
        });
    }
}

刚开始学的时候我有个疑问?就是为什么继承这个SimpleChannelInboundHandler 泛型的类型是请求应答 的协议 — 》 应该是客户端需要和UI界面进行对接,所以需要将请求应答返回的数据 传给UI进行处理。(而请求 协议本就没有带很多对象的集合信息,只是单个对象的信息)

搜索好友 服务端:

/*
注释:
这里的MyBizHandler也是一个抽象类,该类继承了SimpleChannelInboundHandler<T>类,该类还自己创建了channelRead()抽象方法由继承MyBizHandler的子类去实现
下面中的UserService是操作数据库的一个接口类
*/
public class SearchFriendHandler extends MyBizHandler<SearchFriendRequest> {
	@Override
    public void channelRead(Channel channel, SearchFriendRequest msg) {
    	logger.info("搜索好友请求的结果:{}",JSON.toJSONString(msg));
        // 创建 存储用户数据传输对象 的集合
        List<UserDto> userDtoList = new ArrayList<>();
        // 通过Id、Key获取到模糊用户信息的集合
        List<LuckUserInfo> luckUserInfoList  = userService.queryFuzzyUserInfoList(msg.getUserId(), msg.getSearchKey());
            UserDto userDto = new UserDto();
            userDto.setUserId(userInfo.getUserId());
            userDto.setUserNickName(userInfo.getUserNickName());
            userDto.setUserHead(userInfo.getUserHead());
            userDto.setStatus(userInfo.getStatus());
            userDtoList.add(userDto);
    }
        SearchFriendResponse response = new SearchFriendResponse();
        response.setList(userDtoList);
        channel.writeAndFlush(response);
    }
}

添加好友 客户端:

AddFriendResponse协议中获取到的 friendId、friendNickName、FriendHead 传送给 UI界面进行处理。

public class AddFriendHandler extends MyBizHandler<AddFriendResponse> {

    public AddFriendHandler(UIService uiService) {
        super(uiService);
    }

    @Override
    public void channelRead(Channel channel, AddFriendResponse msg) {
        IChatMethod chat = uiService.getChat();
        Platform.runLater(() -> {
            chat.addFriendUser(true, msg.getFriendId(), msg.getFriendNickName(), msg.getFriendHead());
        });
    }
}

添加好友 服务端:

通过 添加好友请求协议的 userId(自己Id)和friendId(好友Id)来创建 “彼此的好友” 然后来添加到userFriendList;然后通过friendId 在数据库查询到好友用户信息,将查询到的用户属性包装在AddFriendResponse协议上在自己的channel管道传输;同理,通过 userId 在数据库中查询到自己的用户信息,将查询到的用户信息属性包装在 AddFriendResponse协议上在属于好友的channel管道传输。

public class AddFriendHandler extends MyBizHandler<AddFriendRequest> {
    @Override
    public void channelRead(Channel channel, AddFriendRequest msg) {
        // 1.添加好友到数据库 A->B  B->A
        List<UserFriend> userFriendList = new ArrayList<>();
        userFriendList.add(new UserFriend(msg.getUserId(),msg.getFriendId()));
        userFriendList.add(new UserFriend(msg.getFriendId(),msg.getUserId()));
        // 从数据库中查询 好友信息
        UserInfo userInfo = userService.queryUserInfo(msg.getFriendId());
        channel.writeAndFlush(new AddFriendResponse(userInfo.getUserId(),userInfo.getUserNickName(), userInfo.getUserHead()));
        
        Channel friendChannel = socketChannelUtil.getChannel(msg.getFriendId());
        if(friendChannel == null) return;
        // 从数据库中查询 自己信息
        UserInfo friendInfo = userService.queryUserInfo(msg.getUserId());
        friendChannel.writeAndFlush(new AddFriendResponse(friendInfo.getUserId(), friendInfo.getUserNickName(), friendInfo.getUserHead()));
    }
}

总结:

这个 添加和搜索好友的功能步骤也是先通过自定义协议后,然后再去创建所需要的数据传输对象(DTO)和需要的model对象后才进行客户端和服务端的操作的;在客户端和服务端的操作中,主要是服务端需要写入具体的实现逻辑(比如,如何根据 搜索好友 协议下的信息去处理,如何根据 添加好友 协议下的信息去处理 等等。。)客户端的操作主要是收到 服务端将 请求应答的 协议包装好的信息后,与UI模块的信息进行处理(这部分就略微知道就好了)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值