项目源码:你和我的畅聊时光
一、主要功能
- 注册,成为我们的注册会员用户,你将拥有全网唯一的ID。
- 登录,进入拥有千万好友的畅聊空间。
- 私聊,你可以选择和任意在线用户进行一次亲密对话。
- 群聊,只要你想,没有不可以。你们的团体就是一个小群组。
二、具体实现
1.服务器与客户端的连接
服务器加载所有的配置信息,包括数据库的密码等。服务器根据Socket与客户端连接,服务器根据收到的不同类型信息而进行不同的操作。如1代表用户注册操作。
1.注册:将用户信息存储到服务器。登录后将新上线的用户信息发回给当前已在线的所有用户。
2.私聊:服务器会检测到所有的私聊信息以及发送方和接收方。
3.注册群:群名和群成员信息存储在Map集合中。
4.群聊:服务器会接收到所有的群聊消息,并发送给群聊内的每一个用户。
public class MultiThreadServer {
private static final String IP;
private static final int PORT;
// 缓存当前服务器所有在线的客户端信息
private static Map<String, Socket> clients = new ConcurrentHashMap<>();
// 缓存当前服务器注册的所有群名称以及群好友
private static Map<String,Set<String>> groups = new ConcurrentHashMap<>();
static {
Properties pros = CommUtils.loadProperties("socket.properties");
IP = pros.getProperty("address");
PORT = Integer.parseInt(pros.getProperty("port"));
}
private static class ExecuteClient implements Runnable {
private Socket client;
private Scanner in;
private PrintStream out;
public ExecuteClient(Socket client) {
this.client = client;
try {
this.in = new Scanner(client.getInputStream());
this.out = new PrintStream(client.getOutputStream(),
true,"UTF-8");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true) {
if (in.hasNextLine()) {
String jsonStrFromClient = in.nextLine();
MessageVO msgFromClient =
(MessageVO) CommUtils.json2Object(jsonStrFromClient,
MessageVO.class);
// 新用户注册到服务端
if (msgFromClient.getType().equals("1")) {
String userName = msgFromClient.getContent();
// 将当前在线的所有用户名发回客户端
MessageVO msg2Client = new MessageVO();
msg2Client.setType("1");
msg2Client.setContent(CommUtils.object2Json(
clients.keySet()
));
out.println(CommUtils.object2Json(msg2Client));
// 将新上线的用户信息发回给当前已在线的所有用户
sendUserLogin("newLogin:"+userName);
// 将当前新用户注册到服务端缓存
clients.put(userName,client);
System.out.println(userName+"上线了!");
System.out.println("当前聊天室共有"+
clients.size()+"人");
}
else if (msgFromClient.getType().equals("2")) {
// 用户私聊
// type:2
// Content:myName-msg
// to:friendName
String friendName = msgFromClient.getTo();
Socket clientSocket = clients.get(friendName);
try {
PrintStream out = new PrintStream(clientSocket.getOutputStream(),
true,"UTF-8");
MessageVO msg2Client = new MessageVO();
msg2Client.setType("2");
msg2Client.setContent(msgFromClient.getContent());
System.out.println("收到私聊信息,内容为"+msgFromClient.getContent());
out.println(CommUtils.object2Json(msg2Client));
} catch (IOException e) {
e.printStackTrace();
}
}else if (msgFromClient.getType().equals("3")) {
// 注册群
String groupName = msgFromClient.getContent();
// 该群的所有群成员
Set<String> friends = (Set<String>) CommUtils.json2Object(
msgFromClient.getTo(),Set.class);
groups.put(groupName,friends);
System.out.println("有新的群注册成功,群名称为"+
groupName+",一共有"+groups.size() + "个群");
}else if (msgFromClient.getType().equals("4")) {
// 群聊信息
System.out.println("服务器收到的群聊信息为:"+msgFromClient);
String groupName = msgFromClient.getTo();
Set<String> names = groups.get(groupName);
Iterator<String> iterator = names.iterator();
while (iterator.hasNext()) {
String socketName = iterator.next();
Socket client = clients.get(socketName);
try {
PrintStream out = new PrintStream(client.getOutputStream(),
true,"UTF-8");
MessageVO messageVO = new MessageVO();
messageVO.setType("4");
messageVO.setContent(msgFromClient.getContent());
// 群名-[]
messageVO.setTo(groupName+"-"+CommUtils.object2Json(names));
out.println(CommUtils.object2Json(messageVO));
System.out.println("服务端发送的群聊信息为:"+messageVO);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
/**
* 向所有在线用户发送新用户上线信息
* @param msg
*/
private void sendUserLogin(String msg) {
for (Map.Entry<String,Socket> entry: clients.entrySet()) {
Socket socket = entry.getValue();
try {
PrintStream out = new PrintStream(socket.getOutputStream(),
true,"UTF-8");
out.println(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(PORT);
ExecutorService executors = Executors.
newFixedThreadPool(50);
for (int i = 0; i < 50; i++) {
System.out.println("等待客户端连接...");
Socket client = serverSocket.accept();
System.out.println("有新的连接,端口号为"+client.getPort());
executors.submit(new ExecuteClient(client));
}
}
}
2.注册功能的实现
获取到用户在注册页面输入的所有内容,封装到User类中,存储到数据库中。如果提示注册成功,则返回到登录页面;否则,停留在当前页面。
public UserReg() {
JFrame frame = new JFrame("用户注册");
frame.setContentPane(userRegPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
// 点击注册按钮,将信息持久化到db中,成功弹出提示框
regBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 获取用户输入的注册信息
String userName = userNameText.getText();
String password = String.valueOf
(passwordText.getPassword());
String brief = brifeText.getText();
// 将输入信息包装为User类,保存到数据库中
User user = new User();
user.setUserName(userName);
user.setPassword(password);
user.setBrief(brief);
// 调用dao对象
if (accountDao.userReg(user)) {//将user信息存到数据库中
// 返回登录页面
JOptionPane.showMessageDialog(frame,"注册成功!",
"提示信息",JOptionPane.INFORMATION_MESSAGE);
frame.setVisible(false);
}else {
// 保留当前注册页面
JOptionPane.showMessageDialog(frame,"注册失败!",
"错误信息",JOptionPane.ERROR_MESSAGE);
}
}
});
}
3.登录的实现
构建登录界面,给每个按钮设置点击事件。
1.注册按钮,则弹出注册页面
2.登录按钮,则获取用户输入的用户名、密码。
2.1校验用户信息,在数据中查找是否存在此用户。不存在,提示登录失败,留在登录界面。用户可以选择注册,所有的注册信息存储在服务器的数据库中。
2.2存在,提示登录成功!然后与服务器建立连接,将当前用户的用户名发送到服务器。
2.3读取服务端发回的所有在线用户信息,通知每个在线用户有某用户上线了。
public UserLogin() {
frame = new JFrame("用户登录");
frame.setContentPane(UserLoginPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
// 注册按钮
regButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 弹出注册页面
new UserReg();
}
});
// 登录按钮
loginButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 校验用户信息
String userName = userNameText.getText();
String password = String.valueOf(
passwordText.getPassword());
User user = accountDao.userLogin(userName,password);//在数据库中查看是否有对应的用户名和密码
if (user != null) {
// 成功,加载用户列表
JOptionPane.showMessageDialog(frame,
"登录成功!","提示信息",JOptionPane.INFORMATION_MESSAGE);
frame.setVisible(false);
// 与服务器建立连接,将当前用户的用户名发送到服务端
Connect2Server connect2Server = new Connect2Server();
MessageVO msg2Server = new MessageVO();
msg2Server.setType("1");
msg2Server.setContent(userName);
String json2Server = CommUtils.object2Json(msg2Server);
try {
PrintStream out = new PrintStream(connect2Server.getOut(),
true,"UTF-8");
out.println(json2Server);
// 读取服务端发回的所有在线用户信息
Scanner in = new Scanner(connect2Server.getIn());
if (in.hasNextLine()) {
String msgFromServerStr = in.nextLine();
MessageVO msgFromServer =
(MessageVO) CommUtils.json2Object(msgFromServerStr,
MessageVO.class);
Set<String> users =
(Set<String>) CommUtils.json2Object(msgFromServer.getContent(),
Set.class);
System.out.println("所有在线用户为:"+users);
// 加载用户列表界面
// 将当前用户名、所有在线好友、与服务器建立连接传递到好友列表界面
new FriendsList(userName,users,connect2Server);
}
} catch (UnsupportedEncodingException ex) {
ex.printStackTrace();
}
}else {
// 失败,停留在当前登录页面,提示用户信息错误
JOptionPane.showMessageDialog(frame,
"登录失败!","错误信息",
JOptionPane.ERROR_MESSAGE);
}
}
});
}
4.私聊
1.当用户A在在线好友列表界面双击用户B,即进入私聊界面。
2.用户输入信息,按回车,即将信息发送给服务器。发送到服务器之前,工具类会封装发送方A的用户名、消息内容、聊天类型、接收方B的用户名,将其转为json字符串。
3.服务器对json字符串进行解析,决定进行私聊操作,服务器将信息发送给B。发送到B之前会将json字符串转为Object对象,用户B最终才接收到A发送的消息。
public PrivateChatGUI(String friendName,
String myName,
Connect2Server connect2Server) {
this.friendName = friendName;
this.myName = myName;
this.connect2Server = connect2Server;
try {
this.out = new PrintStream(connect2Server.getOut(),true,
"UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
frame = new JFrame("与"+friendName+"私聊中...");
frame.setContentPane(privateChatPanel);
// 设置窗口关闭的操作,将其设置为隐藏
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
frame.setSize(400,400);
frame.setVisible(true);
// 捕捉输入框的键盘输入
send2Server.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
StringBuilder sb = new StringBuilder();
sb.append(send2Server.getText());
// 1.当捕捉到按下Enter
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
// 2.将当前信息发送到服务端
String msg = sb.toString();
MessageVO messageVO = new MessageVO();
messageVO.setType("2");
messageVO.setContent(myName+"-"+msg);
messageVO.setTo(friendName);
PrivateChatGUI.this.out.println(CommUtils.object2Json(messageVO));
// 3.将自己发送的信息展示到当前私聊界面
readFromServer(myName+"说:"+msg);
send2Server.setText("");
}
}
});
}
5.群聊
(1)创建群:
1.点击创建群,进入创建群界面。所有的在线好友以列表形式展现。
2.选择你想选择的用户,勾选进行多选,已选择的用户会存储在集合中。
3.将自己加入到群聊集合中,存储群名。
4.用工具类将群名、群成员信息、当前类的操作类型3,封装成json字符串,发送给服务器。
5.隐藏创建群界面,然后刷新群列表界面。
public CreateGroupGUI(String myName,
Set<String> friends,
Connect2Server connect2Server,
FriendsList friendsList) {
this.myName = myName;
this.friends = friends;
this.connect2Server = connect2Server;
this.friendsList = friendsList;
JFrame frame = new JFrame("创建群组");
frame.setContentPane(createGroupPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400,300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
// 将在线好友以checkBox展示到界面中
friendLabelPanel.setLayout(new BoxLayout(friendLabelPanel,BoxLayout.Y_AXIS));
Iterator<String> iterator = friends.iterator();
while (iterator.hasNext()) {
String labelName = iterator.next();
JCheckBox checkBox = new JCheckBox(labelName);
friendLabelPanel.add(checkBox);
}
// 点击提交按钮提交信息到服务端
conformBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 1.判断哪些好友选中加入群聊
Set<String> selectedFriends = new HashSet<>();
Component[] comps = friendLabelPanel.getComponents();
for (Component comp : comps) {
JCheckBox checkBox = (JCheckBox) comp;
if (checkBox.isSelected()) {
String labelName = checkBox.getText();
selectedFriends.add(labelName);
}
}
selectedFriends.add(myName);
// 2.获取群名输入框输入的群名称
String groupName = groupNameText.getText();
// 3.将群名+选中好友信息发送到服务端
// type:3
// content:groupName
// to:[user1,user2,user3...]
MessageVO messageVO = new MessageVO();
messageVO.setType("3");
messageVO.setContent(groupName);
messageVO.setTo(CommUtils.object2Json(selectedFriends));
try {
PrintStream out = new PrintStream(connect2Server.getOut(),
true,"UTF-8");
out.println(CommUtils.object2Json(messageVO));
} catch (UnsupportedEncodingException ex) {
ex.printStackTrace();
}
// 4.将当前创建群界面隐藏,刷新好友列表界面的群列表
frame.setVisible(false);
// addGroupInfo
// loadGroup
friendsList.addGroup(groupName,selectedFriends);
friendsList.loadGroupList();
}
});
}
(2)群聊操作:
1.双击一个群,进入群聊。
2.用户A发送信息,将群聊消息、操作类型、和其他群成员信息封装成json字符串发送到服务器。
3.服务器接收到后,将群聊消息发送给所有的群成员。
这里需要注意的是:
a. 只有群主才能发送第一条消息。
b. 创建群时,只有群主的群列表才会刷新,其他群成员并不知道有这个群的存在。
c. 只有当群主发了第一条信息时,其他成员的群列表才会刷新出这个群。
这一点仿照了微信群聊的特点。
send2Server.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
StringBuilder sb = new StringBuilder();
sb.append(send2Server.getText());
// 捕捉回车按键
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
String str2Server = sb.toString();
// type:4
// content:myName-msg
// to:groupName
MessageVO messageVO = new MessageVO();
messageVO.setType("4");
messageVO.setContent(myName+"-"+str2Server);
messageVO.setTo(groupName);
try {
PrintStream out = new PrintStream(connect2Server.getOut(),
true,"UTF-8");
out.println(CommUtils.object2Json(messageVO));
System.out.println("客户端发送的群聊信息为:"+messageVO);
} catch (UnsupportedEncodingException ex) {
ex.printStackTrace();
}
}
}
});
6.加载好友列表
1.用户上线,刷新好友界面
2.创建群,刷新群列表界面
3.缓存所有私聊界面和群聊界面
public class FriendsList {
private String userName;
// 存储所有在线好友
private Set<String> users;
// 存储所有群名称以及群好友
private Map<String,Set<String>> groupList = new ConcurrentHashMap<>();
private Connect2Server connect2Server;
// 缓存所有私聊界面
private Map<String,PrivateChatGUI> privateChatGUIList = new ConcurrentHashMap<>();
// 缓存所有群聊界面
private Map<String,GroupChatGUI> groupChatGUIList = new ConcurrentHashMap<>();
// 好友列表后台任务,不断监听服务器发来的信息
// 好友上线信息、用户私聊、群聊
private class DaemonTask implements Runnable {
private Scanner in = new Scanner(connect2Server.getIn());
@Override
public void run() {
while (true) {
// 收到服务器发来的信息
if (in.hasNextLine()) {
String strFromServer = in.nextLine();
// 此时服务器发来的是一个json字符串
if (strFromServer.startsWith("{")) {
MessageVO messageVO = (MessageVO) CommUtils.json2Object(strFromServer,
MessageVO.class);
if (messageVO.getType().equals("2")) {
// 服务器发来的私聊信息
String friendName = messageVO.getContent().split("-")[0];
String msg = messageVO.getContent().split("-")[1];
// 判断此私聊是否是第一次创建
if (privateChatGUIList.containsKey(friendName)) {
PrivateChatGUI privateChatGUI = privateChatGUIList.get(friendName);
privateChatGUI.getFrame().setVisible(true);
privateChatGUI.readFromServer(friendName+"说:"+msg);
}else {
PrivateChatGUI privateChatGUI = new PrivateChatGUI(friendName,
userName,connect2Server);
privateChatGUIList.put(friendName,privateChatGUI);
privateChatGUI.readFromServer(friendName+"说:"+msg);
}
}
else if (messageVO.getType().equals("4")) {
// 收到服务器发来的群聊信息
// type:4
// content:sender-msg
// to:groupName-[1,2,3,...]
String groupName = messageVO.getTo().split("-")[0];
String senderName = messageVO.getContent().split("-")[0];
String groupMsg = messageVO.getContent().split("-")[1];
// 若此群名称在群聊列表
if (groupList.containsKey(groupName)) {
if (groupChatGUIList.containsKey(groupName)) {
// 群聊界面弹出
GroupChatGUI groupChatGUI = groupChatGUIList.get(groupName);
groupChatGUI.getFrame().setVisible(true);
groupChatGUI.readFromServer(senderName+"说:"+groupMsg);
}else {
Set<String> names = groupList.get(groupName);
GroupChatGUI groupChatGUI = new GroupChatGUI(groupName,
names,userName,connect2Server);
groupChatGUIList.put(groupName,groupChatGUI);
groupChatGUI.readFromServer(senderName+"说:"+groupMsg);
}
}else {
// 若群成员第一次收到群聊信息
// 1.将群名称以及群成员保存到当前客户端群聊列表
Set<String> friends = (Set<String>) CommUtils.json2Object(messageVO.getTo().split("-")[1],
Set.class);
groupList.put(groupName, friends);
loadGroupList();
// 2.弹出群聊界面
GroupChatGUI groupChatGUI = new GroupChatGUI(groupName,
friends,userName,connect2Server);
groupChatGUIList.put(groupName,groupChatGUI);
groupChatGUI.readFromServer(senderName+"说:"+groupMsg);
}
}
}else {
// newLogin:userName
if (strFromServer.startsWith("newLogin:")) {
String newFriendName = strFromServer.split(":")[1];
users.add(newFriendName);
// 弹框提示用户上线
JOptionPane.showMessageDialog(frame,
newFriendName+"上线了!",
"上线提醒",JOptionPane.INFORMATION_MESSAGE);
// 刷新好友列表
loadUsers();
}
}
}
}
}
}
// 私聊点击事件
private class PrivateLabelAction implements MouseListener {
private String labelName;
public PrivateLabelAction(String labelName) {
this.labelName = labelName;
}
// 鼠标点击执行事件
@Override
public void mouseClicked(MouseEvent e) {
// 判断好友列表私聊界面缓存是否已经有指定标签
if (privateChatGUIList.containsKey(labelName)) {
PrivateChatGUI privateChatGUI = privateChatGUIList.get(labelName);
privateChatGUI.getFrame().setVisible(true);
}else {
// 第一次点击,创建私聊界面
PrivateChatGUI privateChatGUI = new PrivateChatGUI(
labelName,userName,connect2Server
);
privateChatGUIList.put(labelName,privateChatGUI);
}
}
// 群聊点击事件
private class GroupLabelAction implements MouseListener {
private String groupName;
public GroupLabelAction(String groupName) {
this.groupName = groupName;
}
@Override
public void mouseClicked(MouseEvent e) {
if (groupChatGUIList.containsKey(groupName)) {
GroupChatGUI groupChatGUI = groupChatGUIList.get(groupName);
groupChatGUI.getFrame().setVisible(true);
}else {
Set<String> names = groupList.get(groupName);
GroupChatGUI groupChatGUI = new GroupChatGUI(
groupName,names,userName,connect2Server
);
groupChatGUIList.put(groupName,groupChatGUI);
}
}
}
public FriendsList(String userName, Set<String> users,
Connect2Server connect2Server) {
this.userName = userName;
this.users = users;
this.connect2Server = connect2Server;
frame = new JFrame(userName);
frame.setContentPane(friendsPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400,300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
loadUsers();
// 启动后台线程不断监听服务器发来的消息
Thread daemonThread = new Thread(new DaemonTask());
daemonThread.setDaemon(true);
daemonThread.start();
// 创建群组
createGroupBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new CreateGroupGUI(userName,users,connect2Server,
FriendsList.this);
}
});
}
// 加载所有在线的用户信息
public void loadUsers() {
JLabel[] userLabels = new JLabel [users.size()];
JPanel friends = new JPanel();
friends.setLayout(new BoxLayout(friends,BoxLayout.Y_AXIS));
// set遍历
Iterator<String> iterator = users.iterator();
int i = 0;
while (iterator.hasNext()) {
String userName = iterator.next();
userLabels[i] = new JLabel(userName);
// 添加标签点击事件
userLabels[i].addMouseListener(new PrivateLabelAction(userName));
friends.add(userLabels[i]);
i++;
}
frinedsList.setViewportView(friends);
// 设置滚动条垂直滚动
frinedsList.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
friends.revalidate();
frinedsList.revalidate();
}
public void loadGroupList() {
// 存储所有群名称标签Jpanel
JPanel groupNamePanel = new JPanel();
groupNamePanel.setLayout(new BoxLayout(groupNamePanel,
BoxLayout.Y_AXIS));
JLabel[] labels = new JLabel[groupList.size()];
// Map遍历
Set<Map.Entry<String,Set<String>>> entries = groupList.entrySet();
Iterator<Map.Entry<String,Set<String>>> iterator =
entries.iterator();
int i = 0;
while (iterator.hasNext()) {
Map.Entry<String,Set<String>> entry = iterator.next();
labels[i] = new JLabel(entry.getKey());
labels[i].addMouseListener(new GroupLabelAction(entry.getKey()));
groupNamePanel.add(labels[i]);
i++;
}
groupListPanel.setViewportView(groupNamePanel);
groupListPanel.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
groupListPanel.revalidate();
}
public void addGroup(String groupName,Set<String> friends) {
groupList.put(groupName,friends);
}
}
三、整体流程
服务器:
负责缓存所有在线好友、群组以及私聊群聊的聊天记录。根据客户端进行不同的操作而缓存不同的数据到服务器上。
客户端:
1.点击注册按钮,触发注册事件。在注册页面,获取用户输入的用户名、密码、简介,将信息封装到User类中,将user的信息保存到数据库中,即进行数据插入操作。注册成功,返回登录界面。
2.输入已注册的用户名、密码,点击登录,触发登录事件。获取用户输入的用户名和密码,在数据库中查找是否有此用户。
3.有,则成功登录。然后与服务器建立连接,将当前用户的用户名发送到服务器,服务器缓存此用户名。服务器给每一个在线好友发送新用户上线了,并刷新好友列表。
刷新好友列表:加载所有在线的用户信息,并给每一个用户标签添加标签点击事件。
4.客户端读取服务器返回的所有在线用户信息,加载主界面。即加载用户列表界面,将当前用户名、所有在线好友、与服务器建立连接传递到好友列表界面。
5.好友列表界面:加载所有在线的用户信息,并给每一个用户标签添加标签点击事件,触发私聊功能。如果是第一次点击,则创建私聊界面;如果之前已经有过聊天的记录,则根据缓存中的指定标签将私聊界面显示出来。
6.创建私聊:根据传递的参数(发送方,接收方,Socket连接),一旦用户按下回车,则将当前的发送方、接收方、消息封装到协议类中,发给服务器,并将自己发送的信息展示到当前私聊界面。最后将当前私聊界面缓存起来。
7.创建群。点击创建群,进入创建群界面。所有的在线好友以列表形式展现。将已选择的用户存储在集合中。将自己加入到群聊集合中,存储群名。服务器缓存群名和群成员信息,将群名称标签存储在缓存中,给每个群名称标签添加鼠标点击事件,最后刷新群列表界面。
8.群聊:群聊界面首次创建会存在缓存中,协议类将群聊的发言人和群名称封装起来,发给服务器。服务器经过解析,将消息发送给在群组中的每一个人。
8.启动后台线程不断监听服务器发来的消息:
(1)服务器发来的是json字符串,我们需要进行解析。
a. 服务器发来的是私聊信息。判断是不是第一次和此用户进行的私聊。第一次私聊,则创建私聊界面,缓存此私聊界面。不是第一次私聊,将缓存中的私聊界面弹出来。
b. 服务器发来的是群聊信息。若群聊名称在群聊列表,弹出群聊界面。如果自己刚刚创建了群聊,则将群聊信息缓存起来。若群成员第一次收到群聊信息,将群名称以及群成员保存到当前客户端群聊列表,然后弹出群聊界面,将群聊界面缓存。
(2)服务器发来字符串:newLogin:userName。则提醒新用户上线,刷新好友列表。