#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();
}
}
}