有很多天没有写了,这些天跟着视频教程,学着做了一个非常简单的聊天程序,当然是仿QQ的,代码也不是我原创的,不过我觉得这些代码写出来以后还是很有帮助的,对面向对象思想的理解,甚至说是以后忘记哪行代码了,过来查查看也是好的
代码略多,我会顺便把整个工程结构的图粘在下面的:
客户端:
package com.Common;
//定义一个接口 用来表示包的种类
public interface MessageType {
String message_login_successd = "1"; //表示登陆成功
String message_login_failed = "2"; //表示登陆失败
String message_communicate_content = "3"; //聊天信息
String message_get_onlinefriendlist = "4"; //向服务器请求在线好友列表
String message_onlinefriendlist = "5"; //服务器返回的在线好友列表
}
package com.Common;
//这个类用于定义与服务器交互的信息类型
//因为交互信息过多 分类更好管理
public class Message implements java.io.Serializable{
private String mesType;
private String getter;
private String sender;
private String time;
private String content;
public String getMesType() {
return mesType;
}
public void setMesType(String mesType) {
this.mesType = mesType;
}
public String getGetter() {
return getter;
}
public void setGetter(String getter) {
this.getter = getter;
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
package com.Common;
//用于封装UserName 和 password
public class User implements java.io.Serializable{
private String userName;
private String password;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
package com.QqClient.Management;
//用来管理用户的聊天窗口
import java.util.*;
import com.QqClient.View.QqChat;
public class ManageChat {
private static HashMap hm = new HashMap<String,QqChat>();
public static void addChat(String ownerAndChater,QqChat chat){
hm.put(ownerAndChater, chat);
}
public static QqChat getChat(String ownerAndChater){
return (QqChat)hm.get(ownerAndChater);
}
}
package com.QqClient.Management;
import java.util.*;
//用来管理客户端的线程
import com.QqClient.Model.QqClientConServerThread;
public class ManageClientThread {
//一台计算机只需要维护一个hashmap即可 因此将hm设置为静态的全局变量
private static HashMap hm = new HashMap<String,QqClientConServerThread>();
public static void addClientConServerThread(String clientID,QqClientConServerThread thread){
//将得到的信息放入到hashmap中
hm.put(clientID, thread);
}
public static QqClientConServerThread getClientConServerThread(String clientID){
//得到的是object
return (QqClientConServerThread) hm.get(clientID);
}
}
package com.QqClient.Management;
//用来管理好友列表
import java.util.*;
import com.QqClient.View.QqFriendList;
public class ManageFriendList {
private static HashMap hm = new HashMap<String,QqFriendList>();
public static void addQqFriendList(String listowner,QqFriendList friendList){
hm.put(listowner, friendList);
}
public static QqFriendList getQqFriendList(String listowner){
return (QqFriendList)hm.get(listowner);
}
}
package com.QqClient.Model;
//跟服务器直接连接 用于后台信息交互
import java.io.*;
import java.net.*;
import com.Common.*;
import com.QqClient.Management.ManageClientThread;
public class QqClientConServer {
//如果将这里设置成全局变量 会出现问题 当在窗口调用socket读取数据时 会出现两个窗口争夺一个socket的错误
public Socket s;
public static int i = 1;
//发送登陆信息给服务器 进行验证
public boolean sendLoginInfoToSever(Object object){
boolean b = false;
try {
s = new Socket("127.0.0.1",9999);
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
oos.writeObject(object);
System.out.println("已将登陆信息发送给服务器进行验证");
ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
Message mes = (Message)ois.readObject();
System.out.println(mes.getMesType());
if(mes.getMesType().equals("1")){
b=true;
//验证成功,连接已经建立 此时为客户端生成一个进程 并将该进程添加到
QqClientConServerThread conThread = new QqClientConServerThread(s);
conThread.start();
ManageClientThread.addClientConServerThread(((User)object).getUserName(), conThread);
}
//s.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("b="+b);
return b;
}
}
package com.QqClient.Model;
//这是一个用来控制客户端接受信息的线程
import java.net.*;
import java.io.*;
import com.Common.*;
import com.QqClient.Management.ManageChat;
import com.QqClient.View.QqFriendList;
import com.Common.*;
import com.QqClient.Management.*;
public class QqClientConServerThread extends Thread{
//首先得到对应的socket
private Socket socket;
public QqClientConServerThread(Socket s){
this.socket = s;
}
public void run(){
while(true){
//不停的读
try {
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Message mes = (Message)ois.readObject();
//System.out.println("我是"+mes.getGetter()+" 我收到来的"+mes.getSender()+" 的消息: "+mes.getContent());
//如果是聊天信息 则显示
if(mes.getMesType().equals(MessageType.message_communicate_content)){
//在对应的聊天窗口显示
ManageChat.getChat(mes.getGetter()+mes.getSender()).showMessage(mes);
}else if(mes.getMesType().equals(MessageType.message_onlinefriendlist)){
//将好友名单取出来 并刷新好友列表
//以空格在间隔进行拆分
String con = mes.getContent();
String friends[] = con.split(" ");
//得到对应的好友列表
QqFriendList friendList = ManageFriendList.getQqFriendList(mes.getGetter());
System.out.println(mes.getGetter()+"得到了好友在线列表");
//更新好友列表的在线情况 这里可能在第一次上线时 socket建立后 服务器发来信息的时间早于friendlist的创建时间 因此要判断一下
if(friendList!=null){
friendList.updateFriendList(friends);
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public Socket getSocket() {
return socket;
}
public void setSocket(Socket socket) {
this.socket = socket;
}
}
package com.QqClient.Model;
import java.net.*;
import com.Common.*;
//后台用于调用连接服务器的各个函数
public class QqClientUser implements java.io.Serializable{
//检查用户名和密码
public boolean CheckUser(User user){
QqClientConServer qccs = new QqClientConServer();
return qccs.sendLoginInfoToSever(user);
}
}
package com.QqClient.View;
import javax.swing.*;
import com.Common.*;
import com.QqClient.Management.ManageClientThread;
import com.QqClient.Model.QqClientConServer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
//为了让用户聊天窗口能一直处于监听状态 需要将其做成线程
public class QqChat extends JFrame implements ActionListener{
JTextArea chatHistory;
JTextField chatWord;
JButton sendButton;
JPanel southPanel;
String sender;
String getter;
//绘制一个山寨QQ的聊天界面
public QqChat(String sender,String getter){
this.sender = sender;
this.getter = getter;
chatHistory = new JTextArea();
chatHistory.setEditable(false);
sendButton = new JButton("发送");
sendButton.addActionListener(this);
chatWord = new JTextField(15);
southPanel = new JPanel();
southPanel.add(chatWord);
southPanel.add(sendButton);
this.add(chatHistory);
this.add(southPanel,BorderLayout.SOUTH);
this.setLocation(420,200);
this.setSize(400, 300);
this.setIconImage(new ImageIcon("image/QQ.png").getImage());
//this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle(sender+"正在和"+getter+"聊天ing");
this.setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//QqChat qc = new QqChat();
}
//定义一个方法用来显示信息
public void showMessage(Message mes){
String info = mes.getSender()+"对你说:"+mes.getContent()+"\n";
chatHistory.append(info);
}
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
//封装mes信息
Message mes = new Message();
mes.setSender(sender);
mes.setGetter(getter);
mes.setContent(chatWord.getText());
mes.setTime(new java.util.Date().toString());
mes.setMesType(MessageType.message_communicate_content);
//发送给服务器(先用不好的方法直接获取Scoket 待修改)
try {
Socket s = ManageClientThread.getClientConServerThread(sender).getSocket();
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
oos.writeObject(mes);
//显示一下
String info = "你对"+mes.getGetter()+"说: "+mes.getContent()+"\n";
chatHistory.append(info);
chatWord.setText("");
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
//用线程进行读取 这段代码要求socket是静态的才能获取 而这会导致两个窗口争夺一个socket的现象出现
// public void run() {
// // TODO Auto-generated method stub
// //监听接口
// while(true){
// //读取
// try {
// ObjectInputStream ois = new ObjectInputStream(QqClientConServer.s.getInputStream());
// System.out.println(QqClientConServer.i+1);
// Message mes = (Message)ois.readObject();
//
// //显示
// String info = mes.getSender()+"对你说:"+mes.getContent()+"\n";
// chatHistory.append(info);
// chatWord.setText("");
//
// } catch (Exception e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// }
//
//
// }
}
package com.QqClient.View;
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import javax.swing.*;
import com.Common.*;
import com.QqClient.Management.*;
import com.QqClient.Model.*;
//我登陆两次时 因为是在两个程序进程中 因此 获得的s不会相同 但是一个进程的两个窗口s是相同的
//因此 也需要调用线程来进行管理
public class QqClientLogin extends JFrame implements ActionListener{
//绘制一个山寨QQ登陆窗口
//定义组件
JLabel northLogo;
JLabel userName,passWord;
JTextField userNameField;
JPasswordField passWordField;
JLabel forgetPassword;
JLabel applyQQ;
JPanel southPanel;
JButton loginButton;
JCheckBox rememberPassword;
JCheckBox invisibleLogin;
JLabel applyProtect;
//框架
JPanel qqNumberLoginPanel;
JPanel phoneNumberLoginPanel;
JPanel emailLoginPanel;
JTabbedPane tabPane;
//在构造函数中对组件进行初始化
public QqClientLogin(){
//登陆窗口北部
northLogo = new JLabel(new ImageIcon("image/beijing1.jpg"));
//登陆窗口南部
southPanel = new JPanel();
loginButton = new JButton(new ImageIcon("image/denglu.png"));
loginButton.setPreferredSize(new Dimension(148,29)); //改变按钮大小时使用setPreferredSize
loginButton.addActionListener(this);
//loginButton.setSize(148, 29);
southPanel.add(loginButton);
//登陆窗口中间
userName = new JLabel("QQ号码",JLabel.CENTER);
passWord = new JLabel("QQ密码",JLabel.CENTER);
userNameField = new JTextField();
passWordField = new JPasswordField();
forgetPassword = new JLabel("忘记密码",JLabel.CENTER);
forgetPassword.setForeground(Color.red);
applyQQ = new JLabel("申请QQ",JLabel.CENTER);
applyProtect = new JLabel("申请密码保护");
rememberPassword = new JCheckBox("记住密码");
invisibleLogin = new JCheckBox("隐身登陆");
qqNumberLoginPanel = new JPanel();
qqNumberLoginPanel.setLayout(new GridLayout(3,3));
qqNumberLoginPanel.add(userName);
qqNumberLoginPanel.add(userNameField);
qqNumberLoginPanel.add(applyQQ);
qqNumberLoginPanel.add(passWord);
qqNumberLoginPanel.add(passWordField);
qqNumberLoginPanel.add(forgetPassword);
qqNumberLoginPanel.add(rememberPassword);
qqNumberLoginPanel.add(invisibleLogin);
qqNumberLoginPanel.add(applyProtect);
phoneNumberLoginPanel = new JPanel();
emailLoginPanel = new JPanel();
//用tab窗口
tabPane = new JTabbedPane();
tabPane.addTab("QQ号码", qqNumberLoginPanel);
tabPane.addTab("手机号码", phoneNumberLoginPanel);
tabPane.addTab("电子邮件", emailLoginPanel);
this.add(northLogo,BorderLayout.NORTH);
this.add(southPanel,BorderLayout.SOUTH);
this.add(tabPane,BorderLayout.CENTER);
this.setIconImage(new ImageIcon("image/QQ.png").getImage());
this.setTitle("QQ登陆");
this.setSize(280, 300);
this.setLocation(300, 150);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
QqClientLogin qcl = new QqClientLogin();
}
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
System.out.println("用户登录");
QqClientUser qcu = new QqClientUser();
User user = new User();
user.setUserName(userNameField.getText());
user.setPassword(new String(passWordField.getPassword()));
System.out.println(user.getUserName()+user.getPassword());
boolean b = qcu.CheckUser(user);
if(b==true){
QqFriendList qfl = new QqFriendList(user.getUserName());
ManageFriendList.addQqFriendList(user.getUserName(), qfl);
//向服务器发送一个请求在线好友列表的包
Socket s = ManageClientThread.getClientConServerThread(user.getUserName()).getSocket();
try {
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
Message mes= new Message();
mes.setMesType(MessageType.message_get_onlinefriendlist);
//要设定sender 不然服务器不会知道是谁的请求
mes.setSender(user.getUserName());
oos.writeObject(mes);
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
qfl.setVisible(true);
this.dispose();
}else{
JOptionPane.showMessageDialog(this, "QQ号或密码错误");
}
}
}
package com.QqClient.View;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.QqClient.Management.ManageChat;
import com.QqClient.Model.*;
public class QqFriendList extends JFrame implements ActionListener,MouseListener{
//绘制一个简单的好友列表
//定义需要的组件
JButton friendListButton1,friendListButton2,friendListButton3;
JButton strangerListButton1,strangerListButton2,strangerListButton3;
JButton hateListButton1,hateListButton2,hateListButton3;
//注意好友列表 黑名单 陌生人三个卡片中的控件要设置成三个 不然调用会出现问题
JLabel[] labelList1,labelList2,labelList3;
JScrollPane list;
JPanel friendListPanel;
JPanel strangerListPanel;
JPanel hateListPanel;
JPanel panel1;
JPanel panel2;
JPanel panel3;
JPanel buttonPanel1,buttonPanel2,buttonPanel3;
String ownerID;
//定义卡片布局
CardLayout cardLayout;
//定义一个方法用来更新好友的在线列表
public void updateFriendList(String[] onlinFriendList){
for(int i=0;i<onlinFriendList.length;i++){
labelList1[Integer.parseInt(onlinFriendList[i])-1].setEnabled(true);
System.out.println(Integer.parseInt(onlinFriendList[i])+"已被设置成在线");
}
}
public QqFriendList(String ownerID){
this.ownerID = ownerID;
//第一面
friendListButton1 = new JButton("好友列表");
friendListButton1.addActionListener(this);
strangerListButton1 = new JButton("陌生人");
strangerListButton1.addActionListener(this);
hateListButton1 = new JButton("黑名单");
hateListButton1.addActionListener(this);
labelList1 = new JLabel[50];
friendListPanel = new JPanel(new GridLayout(labelList1.length,1,4,4));
for(int i=0;i<labelList1.length;i++){
labelList1[i] = new JLabel(i+1+"", new ImageIcon("image/QQtouxiang.png"), JLabel.LEFT);
labelList1[i].addMouseListener(this);
labelList1[i].setEnabled(false);
if(labelList1[i].getText().equals(ownerID)){
//只让用户自己显示在线
labelList1[i].setEnabled(true);
}
friendListPanel.add(labelList1[i]);
}
System.out.println("所有图标已被设置成不在线");
list = new JScrollPane(friendListPanel);
buttonPanel1 = new JPanel(new GridLayout(2,1));
buttonPanel1.add(strangerListButton1);
buttonPanel1.add(hateListButton1);
panel1 = new JPanel();
panel1.setLayout(new BorderLayout());
panel1.add(friendListButton1,BorderLayout.NORTH);
panel1.add(list,BorderLayout.CENTER);
panel1.add(buttonPanel1,BorderLayout.SOUTH);
//第二面
friendListButton2 = new JButton("好友列表");
friendListButton2.addActionListener(this);
strangerListButton2 = new JButton("陌生人");
strangerListButton2.addActionListener(this);
hateListButton2 = new JButton("黑名单");
hateListButton2.addActionListener(this);
labelList2 = new JLabel[20];
strangerListPanel = new JPanel(new GridLayout(labelList2.length,1,4,4));
for(int i=0;i<labelList2.length;i++){
labelList2[i] = new JLabel("坏人"+i+1+"", new ImageIcon("image/QQtouxiang.png"), JLabel.LEFT);
labelList2[i].addMouseListener(this);
strangerListPanel.add(labelList2[i]);
}
strangerListPanel.addMouseListener(this);
list = new JScrollPane(strangerListPanel);
buttonPanel2 = new JPanel(new GridLayout(2,1));
buttonPanel2.add(friendListButton2);
buttonPanel2.add(strangerListButton2);
panel2 = new JPanel();
panel2.setLayout(new BorderLayout());
panel2.add(buttonPanel2,BorderLayout.NORTH);
panel2.add(list,BorderLayout.CENTER);
panel2.add(hateListButton2,BorderLayout.SOUTH);
//第三面
friendListButton3 = new JButton("好友列表");
friendListButton3.addActionListener(this);
strangerListButton3 = new JButton("陌生人");
strangerListButton3.addActionListener(this);
hateListButton3 = new JButton("黑名单");
hateListButton3.addActionListener(this);
labelList3 = new JLabel[20];
hateListPanel = new JPanel(new GridLayout(labelList3.length,1,4,4));
for(int i=0;i<labelList3.length;i++){
labelList3[i] = new JLabel("黑名"+i+1+"", new ImageIcon("image/QQtouxiang.png"), JLabel.LEFT);
labelList3[i].addMouseListener(this);
hateListPanel.add(labelList3[i]);
}
hateListPanel.addMouseListener(this);
list = new JScrollPane(hateListPanel);
buttonPanel3 = new JPanel(new GridLayout(3,1));
buttonPanel3.add(friendListButton3);
buttonPanel3.add(strangerListButton3);
buttonPanel3.add(hateListButton3);
panel3 = new JPanel();
panel3.setLayout(new BorderLayout());
panel3.add(buttonPanel3,BorderLayout.NORTH);
panel3.add(list,BorderLayout.CENTER);
//运用卡片布局
cardLayout = new CardLayout();
this.setLayout(cardLayout);
this.add(panel1,"1");
this.add(panel2,"2");
this.add(panel3,"3");
//定义窗体属性
this.setSize(260, 600);
this.setTitle(ownerID);
this.setIconImage(new ImageIcon("image/QQ.png").getImage());
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//this.setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//QqFriendList qfl = new QqFriendList();
}
//对按下button换card进行处理
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
//点击陌生人的时候显示卡片2
if(e.getSource()==strangerListButton1
||e.getSource()==strangerListButton2
||e.getSource()==strangerListButton3){
//不允许JFrame直接刷 所以不能直接写this
cardLayout.show(this.getContentPane(), "2");
}
//点击黑名单显示卡片3
else if(e.getSource()==hateListButton1
||e.getSource()==hateListButton2
||e.getSource()==hateListButton3){
cardLayout.show(this.getContentPane(), "3");
}//点击我的好友的时候显示卡片1
else if(e.getSource()==friendListButton1
||e.getSource()==friendListButton2
||e.getSource()==friendListButton3){
cardLayout.show(this.getContentPane(), "1");
}
}
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
if(e.getClickCount()==2){
String name = ((JLabel)e.getSource()).getText();
QqChat chat = new QqChat(this.ownerID,name);
//将Chat放入到对应的方法中
ManageChat.addChat(this.ownerID+name, chat);
// //线程的另一种方法
// Thread thread = new Thread(chat);
// thread.start();
}
}
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
JLabel label = (JLabel)e.getSource();
label.setForeground(Color.red);
}
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
JLabel label = (JLabel)e.getSource();
label.setForeground(Color.black);
}
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
}
服务器端:
package com.QqServer.Model;
import java.util.*;
public class ManageServerConThread {
//将hashmap做成静态的 这样系统只需要维护一个hashmap即可
public static HashMap<String,QqServerConClientThread> hm = new HashMap<String,QqServerConClientThread>();
//将函数编写为静态的 这样方便直接调用
public static void addClientThread(String getter,QqServerConClientThread clientThread){
//向hashmap中添加线程
hm.put(getter, clientThread);
}
public static QqServerConClientThread getServerConClientThread(String getter){
//返回的是object
return (QqServerConClientThread)hm.get(getter);
}
//返回在线人列表
public static String getOlineFriends(){
//使用迭代器来完成hm的遍历
String friendList = "";
Iterator it = hm.keySet().iterator();
while(it.hasNext()){
friendList += it.next().toString()+" ";
}
return friendList;
}
}
package com.QqServer.Model;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.*;
import com.Common.Message;
import com.Common.User;
public class QqServer {
public QqServer(){
try {
//这里代表QQ服务器在9999端口监听 等待QQ客户端的连接
ServerSocket ss = new ServerSocket(9999);
//阻塞 等待
System.out.println("服务器已打开,在端口9999监听");
while(true){
Socket s = ss.accept();
System.out.println("连接成功");
ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
User user = (User)ois.readObject();
Message mes = new Message();
//这里只做简单判断 因为连接数据库过于繁琐
System.out.println(user.getPassword());
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
if(user.getPassword().equals("123456")){
mes.setMesType("1");
System.out.println(mes.getMesType());
oos.writeObject(mes);
//连接成功以后,需要在服务器端建立线程来控制与客户端的链接 以防止因客户端过多造成服务器混乱
QqServerConClientThread qscct = new QqServerConClientThread(s);
//将连接成功的客户端的socket保存在hashmap中 方便返回信息
ManageServerConThread.addClientThread(user.getUserName(),qscct);
//线程创建后 通知其他在线的人他上线了
qscct.notifyOthers(user.getUserName());
//启动和用户通讯的线程
qscct.start();
}else{
mes.setMesType("2");
oos.writeObject(mes);
s.close();
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally{
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
package com.QqServer.Model;
import java.net.*;
import java.io.*;
import com.Common.*;
//这是一个用来维护与客户端通讯的线程
public class QqServerConClientThread extends Thread{
Socket socket;
public QqServerConClientThread(Socket socket){
//首先要接受并保存此线程对应客户端的Socket
this.socket = socket;
}
//定义一个函数用来通知其他在线用户此线程的拥有者已经上线
public void notifyOthers(String owner){
//得到在线人的id
String friendlist = ManageServerConThread.getOlineFriends();
String friends[] = friendlist.split(" ");
Message mes = new Message();
mes.setSender(owner);
mes.setMesType(MessageType.message_onlinefriendlist);
mes.setContent(owner);
for(int i=0;i<friends.length;i++){
mes.setGetter(friends[i]);
System.out.println("我是"+owner+" 我要告诉"+friends[i]+" 我上线了");
try {
ObjectOutputStream oos = new ObjectOutputStream(ManageServerConThread.getServerConClientThread(friends[i]).socket.getOutputStream());
oos.writeObject(mes);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void run(){
//这里在线程启动后便可接受来自对应客户端的信息
while(true){
try {
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Message mes = (Message)ois.readObject();
//读取mes内的相关信息
//System.out.println(mes.getSender()+" 对 "+mes.getGetter()+"说: "+mes.getContent());
//对来自客户端的信息类型进行验证 以便进行相应的处理
if(mes.getMesType().equals(MessageType.message_communicate_content)){
//回复时要得到对应客户端的Socket 因此 应该将接受到的socket存储在一个hashmap中 便于管理和查找
//根据得到的getter 从hashmap中得到对应的socket
Socket getterSocket = ManageServerConThread.getServerConClientThread(mes.getGetter()).socket;
ObjectOutputStream oos = new ObjectOutputStream(getterSocket.getOutputStream());
oos.writeObject(mes);
}else if(mes.getMesType().equals(MessageType.message_get_onlinefriendlist)){
//返回对应的好友列表
//从管理线程的地方得到所有在线信息
String friendList = ManageServerConThread.getOlineFriends();
Message returnMes = new Message();
returnMes.setContent(friendList);
returnMes.setMesType(MessageType.message_onlinefriendlist);
returnMes.setGetter(mes.getSender());
//得到的发送者的Socket 把好友列表返回给他
Socket s = ManageServerConThread.getServerConClientThread(mes.getSender()).socket;
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
oos.writeObject(returnMes);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
package com.QqServer.View;
import javax.swing.*;
import com.QqServer.Model.QqServer;
import java.awt.*;
import java.awt.event.*;
public class QqServerFrame extends JFrame implements ActionListener{
JButton startButton;
JButton stopButton;
JPanel northPanel;
public QqServerFrame(){
startButton = new JButton("启动服务器");
startButton.addActionListener(this);
stopButton = new JButton("关闭服务器");
northPanel = new JPanel();
northPanel.add(startButton);
northPanel.add(stopButton);
this.add(northPanel,BorderLayout.NORTH);
this.setSize(400, 300);
this.setLocation(550, 150);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
QqServerFrame qsf = new QqServerFrame();
}
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(e.getSource()==startButton){
System.out.println("准备启动服务器");
QqServer qs =new QqServer();
}
}
}
c
com.Common包中的类是一样的,用来描述客户端在相互聊天时以及与服务器交互的规则,因此我只在客户端粘贴了对应的代码,不过两个工程文件中都要有,服务器的开始类是QqServerFrame 客户端的开始类是 QqClientLogin 注意一定要先开启服务器再运行客户端
只完成了一些非常简单的功能 希望大神们不要笑话
效果图: