最近用有點時間,重溫了下java圖形用戶界面,使用socket,簡單的實現了仿QQ的聊天私聊、羣聊功能
現在將部分主要代碼貼下:
服務器端:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileOutputStream;
import javax.swing.*;
//////////*服務器窗口類*///////////////
public class ServerFrame extends JFrame implements ActionListener {
public JList list;
/**
*
*/
private static final long serialVersionUID = -8936397327038098620L;
// 服務器信息面板
JPanel pnlServer, pnlServerInfo;
JLabel lblStatus, lblNumber, lblMax, lblServerName, lblProtocol, lblIP,
lblPort, lblLog;
public JTextField txtStatus, txtNumber, txtMax, txtServerName, txtProtocol, txtIP,
txtPort;
JButton btnStop, btnSaveLog;
public TextArea taLog;
JTabbedPane tpServer;
public TextArea taMessage;
// 用戶信息面板
JPanel pnlUser;
public JLabel lblMessage, lblUser, lblNotice, lblUserCount;
JList lstUser;
JScrollPane spUser;
JTextField txtNotice;
JButton btnSend, btnKick;
public String serverMessage ="";
public ServerFrame() {
// 服務器窗口
super("聊天服務器");
setSize(550, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
Dimension scr = Toolkit.getDefaultToolkit().getScreenSize();// 在屏幕居中顯示
Dimension fra = this.getSize();
if (fra.width > scr.width) {
fra.width = scr.width;
}
if (fra.height > scr.height) {
fra.height = scr.height;
}
this.setLocation((scr.width - fra.width) / 2,
(scr.height - fra.height) / 2);
// ==========服務器信息面板=========================
pnlServer = new JPanel();
pnlServer.setLayout(null);
pnlServer.setBackground(new Color(52, 130, 203));
pnlServerInfo = new JPanel(new GridLayout(14, 1));
pnlServerInfo.setBackground(new Color(52, 130, 203));
pnlServerInfo.setFont(new Font("宋體", 0, 12));
pnlServerInfo.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createTitledBorder(""), BorderFactory
.createEmptyBorder(1, 1, 1, 1)));
lblStatus = new JLabel("當前狀態:");
lblStatus.setForeground(Color.YELLOW);
lblStatus.setFont(new Font("宋體", 0, 12));
txtStatus = new JTextField(10);
txtStatus.setBackground(Color.decode("#d6f4f2"));
txtStatus.setFont(new Font("宋體", 0, 12));
txtStatus.setEditable(false);
lblNumber = new JLabel("當前在線人數:");
lblNumber.setForeground(Color.YELLOW);
lblNumber.setFont(new Font("宋體", 0, 12));
txtNumber = new JTextField("0 人", 10);
txtNumber.setBackground(Color.decode("#d6f4f2"));
txtNumber.setFont(new Font("宋體", 0, 12));
txtNumber.setEditable(false);
lblMax = new JLabel("最多在線人數:");
lblMax.setForeground(Color.YELLOW);
lblMax.setFont(new Font("宋體", 0, 12));
txtMax = new JTextField("50 人", 10);
txtMax.setBackground(Color.decode("#d6f4f2"));
txtMax.setFont(new Font("宋體", 0, 12));
txtMax.setEditable(false);
lblServerName = new JLabel("服務器名稱:");
lblServerName.setForeground(Color.YELLOW);
lblServerName.setFont(new Font("宋體", 0, 12));
txtServerName = new JTextField(10);
txtServerName.setBackground(Color.decode("#d6f4f2"));
txtServerName.setFont(new Font("宋體", 0, 12));
txtServerName.setEditable(false);
lblProtocol = new JLabel("訪問協議:");
lblProtocol.setForeground(Color.YELLOW);
lblProtocol.setFont(new Font("宋體", 0, 12));
txtProtocol = new JTextField("HTTP", 10);
txtProtocol.setBackground(Color.decode("#d6f4f2"));
txtProtocol.setFont(new Font("宋體", 0, 12));
txtProtocol.setEditable(false);
lblIP = new JLabel("服務器IP:");
lblIP.setForeground(Color.YELLOW);
lblIP.setFont(new Font("宋體", 0, 12));
txtIP = new JTextField(10);
txtIP.setBackground(Color.decode("#d6f4f2"));
txtIP.setFont(new Font("宋體", 0, 12));
txtIP.setEditable(false);
lblPort = new JLabel("服務器端口:");
lblPort.setForeground(Color.YELLOW);
lblPort.setFont(new Font("宋體", 0, 12));
txtPort = new JTextField("8000", 10);
txtPort.setBackground(Color.decode("#d6f4f2"));
txtPort.setFont(new Font("宋體", 0, 12));
txtPort.setEditable(false);
btnStop = new JButton("關閉服務器(C)");
btnStop.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
closeServer();
}
});
btnStop.setBackground(Color.ORANGE);
btnStop.setFont(new Font("宋體", 0, 12));
lblLog = new JLabel("[服務器日誌]");
lblLog.setForeground(Color.YELLOW);
lblLog.setFont(new Font("宋體", 0, 12));
taLog = new TextArea(20, 50);
taLog.setFont(new Font("宋體", 0, 12));
btnSaveLog = new JButton("保存日誌(S)");
btnSaveLog.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
saveLog();
}
});
btnSaveLog.setBackground(Color.ORANGE);
btnSaveLog.setFont(new Font("宋體", 0, 12));
pnlServerInfo.add(lblStatus);
pnlServerInfo.add(txtStatus);
pnlServerInfo.add(lblNumber);
pnlServerInfo.add(txtNumber);
pnlServerInfo.add(lblMax);
pnlServerInfo.add(txtMax);
pnlServerInfo.add(lblServerName);
pnlServerInfo.add(txtServerName);
pnlServerInfo.add(lblProtocol);
pnlServerInfo.add(txtProtocol);
pnlServerInfo.add(lblIP);
pnlServerInfo.add(txtIP);
pnlServerInfo.add(lblPort);
pnlServerInfo.add(txtPort);
pnlServerInfo.setBounds(5, 5, 100, 400);
lblLog.setBounds(110, 5, 100, 30);
taLog.setBounds(110, 35, 400, 370);
btnStop.setBounds(200, 410, 120, 30);
btnSaveLog.setBounds(320, 410, 120, 30);
pnlServer.add(pnlServerInfo);
pnlServer.add(lblLog);
pnlServer.add(taLog);
pnlServer.add(btnStop);
pnlServer.add(btnSaveLog);
// ===========在線用戶面板====================
pnlUser = new JPanel();
pnlUser.setLayout(null);
pnlUser.setBackground(new Color(52, 130, 203));
pnlUser.setFont(new Font("宋體", 0, 12));
lblMessage = new JLabel("[用戶消息]");
lblMessage.setFont(new Font("宋體", 0, 12));
lblMessage.setForeground(Color.YELLOW);
taMessage = new TextArea(20, 20);
taMessage.setFont(new Font("宋體", 0, 12));
lblNotice = new JLabel("通知:");
lblNotice.setFont(new Font("宋體", 0, 12));
txtNotice = new JTextField(20);
txtNotice.setFont(new Font("宋體", 0, 12));
btnSend = new JButton("發送");
btnSend.setBackground(Color.ORANGE);
btnSend.setFont(new Font("宋體", 0, 12));
btnSend.setEnabled(true);
btnSend.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
serverMessage();
}
});
lblUserCount = new JLabel("在線總人數 0 人");
lblUserCount.setFont(new Font("宋體", 0, 12));
lblUser = new JLabel("[在線用戶列表]");
lblUser.setFont(new Font("宋體", 0, 12));
lblUser.setForeground(Color.YELLOW);
lstUser = new JList();
lstUser.setFont(new Font("宋體", 0, 12));
lstUser.setVisibleRowCount(17);
lstUser.setFixedCellWidth(180);
lstUser.setFixedCellHeight(18);
spUser = new JScrollPane();
spUser.setBackground(Color.decode("#d6f4f2"));
spUser.setFont(new Font("宋體", 0, 12));
spUser.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
spUser.getViewport().setView(lstUser);
lblMessage.setBounds(5, 5, 100, 25);
taMessage.setBounds(5, 35, 300, 360);
lblUser.setBounds(310, 5, 100, 25);
spUser.setBounds(310, 35, 220, 360);
lblNotice.setBounds(5, 410, 40, 25);
txtNotice.setBounds(50, 410, 160, 25);
btnSend.setBounds(210, 410, 80, 25);
lblUserCount.setBounds(320, 410, 100, 25);
pnlUser.add(lblMessage);
pnlUser.add(taMessage);
pnlUser.add(lblUser);
pnlUser.add(spUser);
list = new JList();
list.setListData(new String[] { "" });
spUser.setViewportView(list);
pnlUser.add(lblNotice);
pnlUser.add(txtNotice);
pnlUser.add(btnSend);
pnlUser.add(lblUserCount);
// ============主標籤面板========================
tpServer = new JTabbedPane(JTabbedPane.TOP);
tpServer.setBackground(Color.decode("#d6f4f2"));
tpServer.setFont(new Font("宋體", 0, 12));
tpServer.add("服務器管理", pnlServer);
tpServer.add("用戶信息管理", pnlUser);
this.getContentPane().add(tpServer);
setVisible(true);
}
protected void serverMessage() {
this.serverMessage = txtNotice.getText();
txtNotice.setText("");
}
protected void closeServer() {
this.dispose();
}
protected void saveLog() {
try {
FileOutputStream fileoutput = new FileOutputStream("log.txt",
true);
String temp = taMessage.getText();
fileoutput.write(temp.getBytes());
fileoutput.close();
JOptionPane.showMessageDialog(null, "記錄保存在log.txt");
} catch (Exception e) {
System.out.println(e);
}
}
private void log(String string) {
String newta = taMessage.getText();
newta += ("\n"+string);
taMessage.setText(newta);
}
public void actionPerformed(ActionEvent evt) {
}
public static void main(String args[]) {
new ServerFrame();
}
}
服務器端主要是爲了監聽啓動的客戶端,所以這裏的功能可以統計在線的人數,以及客戶端登錄時間
客戶端(實現了用戶登錄註冊功能):
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
/**
* 聊天系統登錄程序
*/
public class Login extends JFrame implements ActionListener {
private static final long serialVersionUID = -8965773902056088264L;
private JPanel pnlLogin;
private JButton btnLogin, btnRegister, btnExit;
private JLabel lblServer, lblUserName, lblPassword, lblLogo;
private JTextField txtUserName, txtServer;
private JPasswordField pwdPassword;
private String strServerIp;
// 用於將窗口定位
private Dimension scrnsize;
private Toolkit toolkit = Toolkit.getDefaultToolkit();
/**
* 構造登陸窗體
*/
public Login() {
super("登錄聊天室");
pnlLogin = new JPanel();
this.getContentPane().add(pnlLogin);
lblServer = new JLabel("服務器:");
lblUserName = new JLabel("用戶名:");
lblPassword = new JLabel("口 令:");
txtServer = new JTextField(20);
txtServer.setText("127.0.0.1");
txtUserName = new JTextField(20);
pwdPassword = new JPasswordField(20);
btnLogin = new JButton("登錄");
btnLogin.setToolTipText("登錄到服務器");
btnLogin.setMnemonic('L');
btnRegister = new JButton("註冊");
btnRegister.setToolTipText("註冊新用戶");
btnRegister.setMnemonic('R');
btnExit = new JButton("退出");
btnExit.setToolTipText("退出系統");
btnExit.setMnemonic('X');
/***********************************************************************
* 該佈局採用手動佈局 setBounds設置組件位置 * setFont設置字體、字型、字號 * setForeground設置文字的顏色 *
* setBackground設置背景色 * setOpaque將背景設置爲透明
*/
pnlLogin.setLayout(null); // 組件用手動佈局
pnlLogin.setBackground(new Color(52, 130, 203));
lblServer.setBounds(50, 100, 100, 30);
txtServer.setBounds(150, 100, 120, 25);
lblUserName.setBounds(50, 130, 100, 30);
txtUserName.setBounds(150, 130, 120, 25);
lblPassword.setBounds(50, 160, 100, 30);
pwdPassword.setBounds(150, 160, 120, 25);
btnLogin.setBounds(50, 200, 80, 25);
btnRegister.setBounds(130, 200, 80, 25);
btnExit.setBounds(210, 200, 80, 25);
Font fontstr = new Font("宋體", Font.PLAIN, 12);
lblServer.setFont(fontstr);
txtServer.setFont(fontstr);
lblUserName.setFont(fontstr);
txtUserName.setFont(fontstr);
lblPassword.setFont(fontstr);
pwdPassword.setFont(fontstr);
btnLogin.setFont(fontstr);
btnRegister.setFont(fontstr);
btnExit.setFont(fontstr);
lblUserName.setForeground(Color.BLACK);
lblPassword.setForeground(Color.BLACK);
btnLogin.setBackground(Color.ORANGE);
btnRegister.setBackground(Color.ORANGE);
btnExit.setBackground(Color.ORANGE);
pnlLogin.add(lblServer);
pnlLogin.add(txtServer);
pnlLogin.add(lblUserName);
pnlLogin.add(txtUserName);
pnlLogin.add(lblPassword);
pnlLogin.add(pwdPassword);
pnlLogin.add(btnLogin);
pnlLogin.add(btnRegister);
pnlLogin.add(btnExit);
// 設置背景圖片
Icon logo1 = new ImageIcon("images\\loginlogo.jpg");
lblLogo = new JLabel(logo1);
lblLogo.setBounds(0, 0, 340, 66);
pnlLogin.add(lblLogo);
// 設置登錄窗口
setResizable(false);
setSize(340, 260);
setVisible(true);
scrnsize = toolkit.getScreenSize();
setLocation(scrnsize.width / 2 - this.getWidth() / 2, scrnsize.height
/ 2 - this.getHeight() / 2);
Image img = toolkit.getImage("images\\appico.jpg");
setIconImage(img);
// 三個按鈕註冊監聽
btnLogin.addActionListener(this);
btnRegister.addActionListener(this);
btnExit.addActionListener(this);
} // 構造方法結束
/**
* 按鈕監聽響應
*/
@SuppressWarnings({ "deprecation", "static-access" })
public void actionPerformed(ActionEvent ae) {
Object source = ae.getSource();
if (source.equals(btnLogin)) {
// 判斷用戶名和密碼是否爲空
if (txtUserName.getText().equals("")
|| pwdPassword.getText().equals("")) {
JOptionPane op1 = new JOptionPane();
op1.showMessageDialog(null, "用戶名或密碼不能爲空");
} else {
strServerIp = txtServer.getText();
login();
}
}
if (source.equals(btnRegister)) {
strServerIp = txtServer.getText();
this.dispose();
new Register(strServerIp);
}
if (source == btnExit) {
System.exit(0);
}
} // actionPerformed()結束
/**
* 登錄事件響應方法
*/
@SuppressWarnings("deprecation")
public void login() {
// 接受客戶的詳細資料
Customer data = new Customer();
data.custName = txtUserName.getText();
data.custPassword = pwdPassword.getText();
try {
// 連接到服務器
Socket toServer;
toServer = new Socket(strServerIp, 1001);
ObjectOutputStream streamToServer = new ObjectOutputStream(toServer
.getOutputStream());
// 寫客戶詳細資料到服務器socket
streamToServer.writeObject((Customer) data);
// 讀來自服務器socket的登錄狀態
BufferedReader fromServer = new BufferedReader(
new InputStreamReader(toServer.getInputStream()));
String status = fromServer.readLine();
if (status.equals("登錄成功")) {
new ChatRoom((String) data.custName, strServerIp);
this.dispose();
// 關閉流對象
streamToServer.close();
fromServer.close();
toServer.close();
} else {
JOptionPane.showMessageDialog(null, status);
// 關閉流對象
streamToServer.close();
fromServer.close();
toServer.close();
}
} catch (ConnectException e1) {
JOptionPane.showMessageDialog(null, "未能建立到指定服務器的連接!");
} catch (InvalidClassException e2) {
JOptionPane.showMessageDialog(null, "類錯誤!");
} catch (NotSerializableException e3) {
JOptionPane.showMessageDialog(null, "對象未序列化!");
} catch (IOException e4) {
JOptionPane.showMessageDialog(null, "不能寫入到指定服務器!");
}
} // login()結束
/**
* 啓動登陸窗體
* @param args
*/
public static void main(String args[]) {
new Login();
}
} // Class Login結束
登錄窗口
運行效果:
服務器頁面
註冊、登錄
聊天(私聊、羣聊)
技術:使用了java的swing窗口、socket通信,沒有用數據庫,用了文件存儲的方式
(鑑於這裏貼出完整代碼太多,如需要,可以加我Q: 3459067873 我發你)