一步一步写简易版飞鸽传书(三)

实现公聊

一、前言

我们首先来回顾一下到目前为止我们已经完成的工作。我们已经完成登录窗口、好友列表窗口和聊天窗口以及一个通信类。当我们打开登录窗口,填好用户名选好头像之后,点登录按钮就会弹出一个好友列表窗口,当双击某个好友之后就会打开一个与他聊天的窗口。这里我们发现了一个问题,我们没有做控制。每次双击某个好友都会弹出一个新的聊天窗口。

这当然是不合适的,和谁聊天,我们都应该只打开一个窗口才对。改起来也比较简单,在用户类User中加一个ChatFrame 的实例,表明这个用户对应的聊天窗口。

   //该用户对应的聊天窗口private ChatFrame chatFrame;public ChatFrame getChatFrame() {return chatFrame;}public void setChatFrame(ChatFrame chatFrame) {this.chatFrame = chatFrame;}FriendListFrame 中ShowChatFrameListener 修改如下://实现JList上的鼠标双击事件的监听器class ShowChatFrameListener extends MouseAdapter{public void mouseClicked(MouseEvent e){//双击if(e.getClickCount() >= 2){User user = friendList.getSelectedValue();if(user.getChatFrame() == null){user.setChatFrame(new ChatFrame(user));			}//如果该用户的聊天窗口没有显示,则让该用户的聊天窗口显示出来if (!user.getChatFrame().isShowing()){user.getChatFrame().setVisible(true);}}}}

这样就OK了。

二、处理用户上线、下线和公聊

接下来还有一个问题需要解决,那就是及时更新好友列表的问题。当有新用户上线时,我们要把他加入到好友列表中,当他下线时我们要将他从好友列表中剔除。实现的思路就是用户登录后就定时广播一条特殊的消息——在线消息,而用户关闭所有窗口退出后,显然就不会再广播这条消息了。关键的部分代码在这里再简单解释下,大部分都是直接拷贝自《疯狂java讲义》。

 

首先,用户类User中新增了两个属性,SocketAddress address 和 int lost。address 用来唯一地标识一个用户,lost标识该用户失去联系的次数,当失联次数大于2时就让他下线。

 

//该用户所在的IP和端口private SocketAddress address;//该用户失去联系的次数private int lost;//使用address作为该用户的标识,所以根据address作为//重写hashCode()和equals方法的标准public int hashCode(){return address.hashCode();}public boolean equals(Object obj){if(obj != null && obj instanceof User){User target = (User) obj;if(address != null){return address.equals(target.getAddress());}}return false;}

在登录按钮的事件中,我们构造一条特殊的广播消息——用户上线消息,然后定义一个定时器。登录按钮的事件代码如下:

  @Overridepublic void actionPerformed(ActionEvent e) {// TODO Auto-generated method stub//显示好友列表窗口friendListFrame = new FriendListFrame();loginFrame.setVisible(false);//实例化通信工具类comUtil = new ComUtil();//构造用户上线消息String userOnlineMsg = MyProtocol.PRESENCE+userNameField.getText()+MyProtocol.SPLITTER+iconList.getSelectedIndex()+".jpg"+MyProtocol.PRESENCE;comUtil.broadMsg(userOnlineMsg);// 启动定时器每3秒广播一次在线消息Timer timer= new Timer(1000 * 3, new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {// TODO 自动生成的方法存根comUtil.broadMsg(userOnlineMsg);}});timer.start();}

另外,我们定义了一个消息处理类MsgProcessor ,用它来处理消息。在其中,暂时提供一个处理公聊消息的方法,根据消息是普通公聊消息还是用户上线消息,分别做了相应的处理。代码如下:

package com.myipmsg.util;import java.io.UnsupportedEncodingException;
import java.net.DatagramPacket;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.List;import com.myipmsg.bean.User;
import com.myipmsg.comutil.ComUtil;
import com.myipmsg.frame.ChatFrame;
import com.myipmsg.frame.FriendListFrame;/*** 消息处理工具类* @author ThinkPad**/
public class MsgProcessor {/*** 处理公聊消息* @param msg*/public void processBroadMsg(DatagramPacket broaInPacket, FriendListFrame friendListFrame){try {String msg = new String(broaInPacket.getData(), 0, broaInPacket.getLength(),ComUtil.CHARSET);if(msg.startsWith(MyProtocol.PRESENCE) && msg.endsWith(MyProtocol.PRESENCE)){//说明是用户上线消息String userMsg = msg.substring(2, msg.length() - 2);String[] userInfo = userMsg.split(MyProtocol.SPLITTER);User user = new User(userInfo[0], userInfo[1], broaInPacket.getSocketAddress(),0);//表明该用户是否是刚刚上线,是否需要添加到好友列表中boolean needAdd = true; //保存需要被删除的用户下标List toBeRemoveList = new ArrayList<>();for(int i=1;i 2){toBeRemoveList.add(i);}}// 删除toBeRemoveList中的所有索引对应的用户for (int i = 0; i < toBeRemoveList.size() ; i++){friendListFrame.removeUser(toBeRemoveList.get(i));}//加入新上线的用户if(needAdd){friendListFrame.addUser(user);}}else{//说明是普通的公聊消息,那么打开公聊窗口,显示消息//第1个用户是所有人ChatFrame publicChatFrame = null;if(friendListFrame.getUser(0).getChatFrame() == null){publicChatFrame = new ChatFrame(friendListFrame.getUser(0)); friendListFrame.getUser(0).setChatFrame(publicChatFrame);}else{publicChatFrame = friendListFrame.getUser(0).getChatFrame();}if(!publicChatFrame.isShowing()){publicChatFrame.setVisible(true);}SocketAddress address = broaInPacket.getSocketAddress();publicChatFrame.addMsg(friendListFrame.findUserByAddress(address).getName()+" : "+msg);}} catch (UnsupportedEncodingException e) {// TODO 自动生成的 catch 块e.printStackTrace();}}public static void main(String[] args) {// TODO 自动生成的方法存根}}

注意:本篇为了实现公聊功能,很多类都有修改。这里不一一赘述,详细的代码请看附件。

所有代码可在此处下载: http://download.csdn.net/detail/zhutulang/9207885



本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部