1. 程式人生 > >#java 聊天室(二)—— 給聊天室增加選單和私聊功能

#java 聊天室(二)—— 給聊天室增加選單和私聊功能

#java    聊天室(二)——  給聊天室增加選單和私聊功能

在上一篇部落格裡,我們實現了用java寫了一個telnet聊天伺服器,實現了群聊功能。今天我們就來給這個聊天室新增選單,並且實現私聊功能。 

1.實現目標 

 在使用者登入後顯示選單:

當用戶輸入1後用戶進入公共聊天室,提示使用者輸入想給大家發的訊息,輸入x退出公共聊天室:

當用戶輸入2後,顯示出線上使用者的列表,輸入想私聊使用者對應的編號即可與使用者私聊,x退出: 

2.思路解析

(1)、處理使用者的錯誤輸入:

使用者可能輸入很奇怪的內容,因此我們需要用一些條件語句嚴格判斷使用者輸入,只允許使用者輸入指定內容。在使用者輸入正確後執行相關操作,輸入錯誤時讓使用者重新輸入。 實現重新輸入可以將這一系列的程式碼放在一個while迴圈裡面,如果需要退出這些程式碼,用break即可實現。

例如:

//主選單的實現
while (start) {
		showMenu();
	    String choice = bs.readLine();
	    if (choice != null) {
			switch (choice) {
			case "1":
				setMsg(bs);
				break;
			case "2":
				personList();
				break;
			case "3":
				sk.close();
				start = false;
				break;
			default:
				out.write("輸入錯誤,請重新輸入!".getBytes());
			}
		}
	}

有些地方只允許使用者輸入數字,可以用下面的方法判斷一個字串是不是數字:

// 判斷一個字串是不是數字
	public static boolean isNumeric(String str) {
		for (int i = str.length(); --i >= 0;) {
			if (!Character.isDigit(str.charAt(i))) {
				return false;
			}
		}
		return true;
	}

(2)、私聊功能的實現

a、顯示使用者列表:

從儲存使用者資訊的Message佇列裡面獲取使用者名稱,將使用者的索引和使用者名稱輸出到使用者控制檯,使用者輸入聊天物件的索引開始私聊。這裡的私聊需要能一直持續,而不是輸入了一句還需要重新選擇物件。另外也允許使用者輸入指定命令退出私聊。因此可以把私聊功能放在一個while迴圈裡面,當用戶輸入指定命令時執行break退出迴圈:

	// 進入私人聊天模組,列出線上使用者
	public void personList() throws IOException {
		while (true) {
			out.write("以下是線上的使用者,請選擇你要聊天的使用者\r\n".getBytes());
			for (int i = 0; i < msg.size(); i++) {
				if (msg.get(i).getName() != null) {
					out.write((i + "." + msg.get(i).getName() + "\r\n").getBytes());
				}
			}
			out.write("x.返回\r\n".getBytes());
			String strChoice = bs.readLine();
            //如果使用者輸入了“x”,退出
			if (strChoice.equals("x"))
				break;
            //判斷使用者輸入的是不是陣列,使用者輸入的數字即為Message佇列裡對應使用者的索引
			else if (isNumeric(strChoice)) {
				int index = Integer.parseInt(strChoice);
				if (index >= 0 && index < msg.size()) {
                    //給索引為index的使用者發訊息,此函式在下面介紹
					chatPerson(index);
				}
			} else {
				out.write("輸入錯誤,請重新輸入!\r\n".getBytes());
			}
		}
	}

b、私聊功能的實現:

在Message類(這個類在我的前一篇部落格或者下面的"完整的程式碼"模組裡有全部內容)裡面有連個方法需要提一下,一個是將訊息儲存的方法,一個是將訊息輸出的方法:

//儲存訊息
public void setMsg(String msg) {
		this.msg = msg;
	}

//將訊息輸出
public void outPut() throws IOException {
		out.write(msg.getBytes());
	}

 我們只需要將使用者輸入的訊息存入Message佇列裡要私聊使用者的物件,並執行私聊使用者物件的outPut()方法即可在該使用者的控制檯輸出私聊訊息。同時也需要注意,這裡也需要給用使用者一個退出私聊的命令。所以和上面一樣,將整個程式碼塊放在一個while迴圈裡面,使用者輸入指定命令後執行break即可。

//獲取使用者的輸入,在索引為index的使用者的控制檯顯示,即實現私聊功能。
	public void chatPerson(int index) throws IOException {
		while (true) {
			out.write(("請輸入給" + msg.get(index).getName() + "傳送的訊息,輸入x返回:\r\n").getBytes());
			String strMsg = bs.readLine();
			if (strMsg.equals("x"))
				break;
			out.write(("你對" + msg.get(index).getName() + "說:" + strMsg + "\r\n").getBytes());
			msg.get(index).setMsg(msg.get(count).getName() + "對你說:" + strMsg + "\r\n");
			msg.get(index).outPut();
		}
	}

3.完整的程式碼

——Manage.java——


import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class Manage {
	static ArrayList<Message> m = new ArrayList<>();
	static int count = 0;
	static ServerSocket sever;

	public static void main(String[] args) {
		try {
			sever = new ServerSocket(6666);
			System.out.println("伺服器已開啟。");
			while (true) {
				Socket sk = sever.accept();
				Sever ss = new Sever(m, sk, count++);
				Thread ts = new Thread(ss);
				ts.start();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

——Message.java——


import java.io.IOException;
import java.io.OutputStream;
import java.net.SocketException;
import java.util.ArrayList;

public class Message {
	private String name;
	private ArrayList<Message> arrMsg;
	private boolean start = true;
	private OutputStream out;
	private String msg;

	public Message(String name, OutputStream out, ArrayList<Message> arrMsg) {
		this.name = name;
		this.out = out;
		this.arrMsg = arrMsg;
	}

	public boolean getStart() {
		return start;
	}

	public String getName() {
		return name;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}

	public void setMsgAll(String msg) {
		this.msg = msg;
		for (int i = 0; i < arrMsg.size(); i++) {
			arrMsg.get(i).setMsg(msg);
		}
		outPutAll();
	}

	public void exit() {
		start = false;
	}

	public void outPutAll() {
		for (int i = 0; i < arrMsg.size(); i++) {
			try {
				arrMsg.get(i).outPut();
			} catch (SocketException e1) {
				arrMsg.get(i).exit();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public void outPut() throws IOException {
		out.write(msg.getBytes());
	}
}

——Sever.java——


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;

public class Sever implements Runnable {
	private ArrayList<Message> msg;
	private Socket sk;
	private Message m;
	private int count;
	private OutputStream out;
	private BufferedReader bs;
	private InputStream in;
	private boolean start = true;

	public Sever(ArrayList<Message> msg, Socket sk, int count) {
		this.msg = msg;
		this.sk = sk;
		this.count = count;
	}

	public void run() {
		recieve();
	}

	// 判斷一個字串是不是數字
	public static boolean isNumeric(String str) {
		for (int i = str.length(); --i >= 0;) {
			if (!Character.isDigit(str.charAt(i))) {
				return false;
			}
		}
		return true;
	}

	// 使用者登陸後顯示選單
	public void showMenu() throws IOException {
		out.write("1.公共聊天室\r\n".getBytes());
		out.write("2.給某使用者發私信\r\n".getBytes());
		out.write("3.退出\r\n".getBytes());
	}

	// 實現群聊功能
	public void setMsg(BufferedReader bs) throws IOException {
		out.write("歡迎來到公共聊天室,請輸入您想說的話,輸入x退出:\r\n".getBytes());
		while (msg.get(count).getStart()) {
			out.write("請輸入您想對大家說的話,輸入x退出:\r\n".getBytes());
			String strMsg = bs.readLine();
			if (strMsg != null) {
				if (strMsg.equals("x"))
					break;
				else
					msg.get(count).setMsgAll(msg.get(count).getName() + " said:" + strMsg + "\r\n");
			}
		}
	}

	// 使用者登入後初始化
	public void login() throws IOException {
		out = sk.getOutputStream();
		in = sk.getInputStream();
		out.write("welcome!Please enter your username:\r\n".getBytes());
		bs = new BufferedReader(new InputStreamReader(in));
		String name = bs.readLine();
		out.write(("Your username is:" + name + "\r\n").getBytes());
		m = new Message(name, out, msg);
		count = msg.size();
		msg.add(count, m);
		msg.get(count).setMsgAll(name + " is on line.\r\n");
	}

	// 進入私人聊天模組,列出線上使用者
	public void personList() throws IOException {
		while (true) {
			out.write("以下是線上的使用者,請選擇你要聊天的使用者\r\n".getBytes());
			for (int i = 0; i < msg.size(); i++) {
				if (msg.get(i).getName() != null) {
					out.write((i + "." + msg.get(i).getName() + "\r\n").getBytes());
				}
			}
			out.write("x.返回\r\n".getBytes());
			String strChoice = bs.readLine();
			if (strChoice.equals("x"))
				break;
			else if (isNumeric(strChoice)) {
				int index = Integer.parseInt(strChoice);
				if (index >= 0 && index < msg.size()) {
					chatPerson(index);
				}
			} else {
				out.write("輸入錯誤,請重新輸入!\r\n".getBytes());
			}
		}
	}

	// 私人聊天
	public void chatPerson(int index) throws IOException {
		while (true) {
			out.write(("請輸入給" + msg.get(index).getName() + "傳送的訊息,輸入x返回:\r\n").getBytes());
			String strMsg = bs.readLine();
			if (strMsg.equals("x"))
				break;
			out.write(("你對" + msg.get(index).getName() + "說:" + strMsg + "\r\n").getBytes());
			msg.get(index).setMsg(msg.get(count).getName() + "對你說:" + strMsg + "\r\n");
			msg.get(index).outPut();
		}
	}

	public void recieve() {
		try {
			login();
			while (start) {
				showMenu();
				String choice = bs.readLine();
				if (choice != null) {
					switch (choice) {
					case "1":
						setMsg(bs);
						break;
					case "2":
						personList();
						break;
					case "3":
						sk.close();
						start = false;
						break;
					default:
						out.write("輸入錯誤,請重新輸入!".getBytes());
					}
				}
			}
			out.close();
			in.close();
			sk.close();
			msg.remove(count);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}