Java Swing實現socket通信(私聊/羣聊)

最近用有點時間,重溫了下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  我發你)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章