不登高山,不知天之高也;不临深溪,不知地之厚也。
| @Author:TTODS
项目名称:TT聊天室。
项目功能:此项目通过连接数据库实现了用户的注册登录功能,支持用户创建房间或者加入别人的房间,并在房间内进行多人实时聊天。
此项目是我本学期Java基础课程的课程设计,综合Java基础课程中的文件输入输出、多线程、Swing编程、网络编程、数据库编程等技术实现了聊天室的基本功能。
聊天室系统的采用Client-Server(C/S)模式,服务器与客户端之间使用数据包(data package)作为交换的消息。用户通过聊天室客户端的用户界面向服务器发送请求(request)包,服务器通过接收客户端发送的请求包,根据请求内容与数据库查询结果给予应答向客户端返回一个数据包,然后客户端接收服务器的回应(response),根据回应的内容将操作的结果通过界面反馈给用户。聊天室系统的总体设计如下图(图1):
private HashSet<Socket> clients;//已连接的客户端
private LinkedList<ChatRoom> chatRooms;// 当前开放的房间列表
private Connection con = null; // 数据库连接
private ServerDataHandler sDataHandler;// 服务器数据处理器,运用线程池,处理多个客户端请求
private AcceptListener acceptListener;//客户端连接监听器
ClientFrame clientFrame;// 用户界面
ClientReceiver clientReceiver;// 客户端接收器,用来随时接收服务器发来的消息
TTUser user;// 当前登录用户的引用
由于本系统客户端与服务器消息传输使用的是字符缓冲流,且服务器要通过此消息区分不同的请求,针对此需求,我设计了一个数据包(DataPack)类,这个类有点类似网络上常用的JSON数据,可以通过字符串解析为DataPack对象,但是它比JSON简单,它分为三个域(如图4):
final private RequestType type;
//请求的所有类型
public static enum RequestType{
signUp,signIn,signOut,enterRoom,createRoom,exitRoom,sendMessage,updateRoomCnt,updateUserCnt,rename
}
final private String status;
final private String body;
用户点击注册按钮后,程序会从界面收集表单的完整性,若有未填的数据项会给出提示,当数据符合要求时就会将数据整合成请求包的形式发送给服务器。服务器返回的结果会被客户端接收器接收,根据回应给用户以界面反馈。
用户点击登录按钮后,程序会从界面收集表单的完整性,若有未填的数据项会给出提示,当数据符合要求时就会将数据整合成请求包的形式发送给服务器。服务器返回的结果会被客户端接收器接收,根据回应给用户以界面反馈。
服务器收到创建房间请求时,会将房间对象加入自己的房间列表中,方便进一步对房间进行消息推送。
客户端socket被放入房间的客户端列表后,该房间内客户端向服务器发送消息请求后,该消息会由服务器分到该房间,再由该房间对该房间内所有的客户端转发(广播)。
用户点击退出的房间按钮,服务器处理后,客户端离开房间不再接收该房间的推送,界面返回房间操作界面。
房间内某一客户端发送的聊天信息,经服务器处理会推送到该房间内所有的客户端。
用户注册时,会默认注册名为用户昵称,登陆后可以修改。
注册界面:用户可以通过此界面完成注册操作,用户输入用户名和密码便可以完成注册,若已有账号,可以选择按“To sign in”按钮前往登录界面。
登录界面:用户可以通过此界面完成登录操作,用户输入用户名和密码便可以完成登录,若没有账号,可以选择按“Create an account”按钮前往注册界面。
创建/加入房间的界面:此界面是用户登录后显示的界面,用户可以选择创建房间或者加入别人的房间来进入聊天界面,也可以选择退出登录来切换账号,此外,该界面还提供软件基本信息(在线房间数,当前系统时间等)的显示和用户昵称的修改等功能。
聊天界面:此界面是聊天界面,用户可编辑消息发送给当前房间内的所有用户。还可以通过点击“exit room”按钮来退出房间(若是房主退出房间意味着该房间关闭,所有该房间内的用户都会被强制退出房间);
由于这是Java基础的课程设计,数据库这方面没有花功夫,只是使用了一个简单的用户表用来存放用户的账号密码
package ttserver;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.*;
import java.util.*;
import java.util.Date;
public class TTServer {
private LinkedList<ChatRoom> chatRooms;// 当前开放的房间列表
private ServerDataHandler sDataHandler;// 服务器数据处理器,运用线程池,处理多个客户端请求
private Connection con = null; // 数据库连接
private ServerSocket serverSocket; //服务器socket
private AcceptListener acceptListener; //连接监听器
private HashSet<Socket> clients; //已连接的客户端集合(实际上是登陆后的客户端集合)
private BufferedWriter logWriter = null; //日志字符输出流
static HashMap<Character, ArrayList<String>> illegalWordList; //敏感词列表
//敏感词加载
static {
try {
illegalWordList = new HashMap<>();
loadIllegalWordList();
} catch (Exception e) {
// TODO 自动生成的 catch 块
System.out.println("敏感词列表加载失败");
}
}
public TTServer() {
// TODO 自动生成的构造函数存根
try {
// 连接数据库
connectMySQL();
// 打开连接
serverSocket = new ServerSocket(9000);
// 加载敏感词列表
// 启动日志[!附加模式]
logWriter = new BufferedWriter(new FileWriter("TTchatRoom.log", true));
// 初始化房间列表
chatRooms = new LinkedList<>();
//初始化连接池
clients=new HashSet<>();
// 启动连接监听器
acceptListener = new AcceptListener();
acceptListener.start();
// 启动请求处理器
sDataHandler = new ServerDataHandler(this);
System.out.println(new Date().toLocaleString() + ": 服务器启动成功");
} catch (IOException e) {
// TODO 自动生成的 catch 块
System.err.println("服务器启动失败,请检查是否该端口是否已被其他程序占用");
e.printStackTrace();
}
}
// 连接数据库
public void connectMySQL() {
// 声明Connection对象
// 驱动程序名
String driver = "com.mysql.cj.jdbc.Driver";
// URL指向要访问的数据库名 test
String url = "jdbc:mysql://localhost:3306/ttchatroom?serverTimezone=UTC";
// MySQL配置时的用户名
String user = "root";
// MySQL配置时的密码
String password = "";
try {
// 加载驱动程序
Class.forName(driver);
// 1.getConnection()方法,连接MySQL数据库!!
con = DriverManager.getConnection(url, user, password);
if (!con.isClosed())
System.out.println("成功以 " + user + " 身份连接到数据库!!!");
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
//获取开放房间的列表
public LinkedList<ChatRoom>getChatRoomList() {
return this.chatRooms;
}
//获取已连接的客户端socket集合
public HashSet<Socket> getConnectedClientSet() {
return this.clients;
}
// sql查询,返回结果集
public synchronized ResultSet SQLSelect(String sql) throws Exception {
System.out.println(sql);
Statement statement = con.createStatement();
ResultSet rs = statement.executeQuery(sql);
return rs;
}
// sql更新,返回修改是否成功
public synchronized boolean SQLUpdate(String sql) throws Exception {
PreparedStatement sta = con.prepareStatement(sql);
int rows = sta.executeUpdate();
if (rows == 0)
return false;
return true;
}
// 加载敏感词列表
static void loadIllegalWordList() throws Exception {
BufferedReader bur = new BufferedReader(new FileReader("IllegalWordList.txt"));
String s = null;
while ((s = bur.readLine()) != null) {
if (!illegalWordList.containsKey(s.charAt(0))) {
illegalWordList.put(s.charAt(0), new ArrayList<String>());
}
illegalWordList.get(s.charAt(0)).add(s);
}
bur.close();
}
// 替换敏感词
static String replaceIllegalWord(String s) {
for (int i = 0; i < s.length(); i++) {
if (illegalWordList.containsKey(s.charAt(i))) {
for (String word : illegalWordList.get(s.charAt(i))) {
int len = word.length();
if (i + len <= s.length() && s.substring(i, i + len).equals(word)) {
char[] replaceWord = new char[len];
Arrays.fill(replaceWord, '*');
s = s.substring(0, i) + new String(replaceWord) + s.substring(i + len);
i += len - 1;
}
}
}
}
return s;
}
//获取当前房间数量
public int getRoomCnt() {
return chatRooms.size();
}
// 注册房间,在房间创建时调用
public synchronized void registerRoom(ChatRoom chatRoom) {
chatRooms.add(chatRoom);
}
// 将客户端注册到房间
public synchronized void registerClient(Long roomId, Socket client) {
for (ChatRoom chatRoom : chatRooms) {
if (chatRoom.getRoomId() == roomId) {
chatRoom.registerClient(client);
}
}
}
// 将客户端从聊天室中移除
public synchronized void removeClientFromRoom(Long roomId, Socket client) {
if(clients.contains(client)) clients.remove(client);
for (ChatRoom chatRoom : chatRooms) {
if (chatRoom.getRoomId() == roomId) {
chatRoom.removeClient(client);
}
}
}
//将客户端移除连接列表
public synchronized void removeClient(Socket client) {
clients.remove(client);
}
// 分发一条消息到相应的房间,再由房间对象广播消息
public synchronized void sendMessge(long roomId, String message) {
for (ChatRoom chatRoom : chatRooms) {
if (chatRoom.getRoomId() == roomId) {
chatRoom.broadcast(message);
break;
}
}
}
// 移除房间,在房间关闭时使用(使房间中的所有客户端,房间为空时,房间会自动清除)
public synchronized void removeRoom(long roomId) {
int i = 0;
for (; i < chatRooms.size(); i++) {
if (chatRooms.get(i).getRoomId() == roomId) {
chatRooms.get(i).broadcast("exitRoom", "roomClosed", "房主退出了房间,房间关闭");
chatRooms.remove(i);
break;
}
}
}
public ServerSocket getServerSocket() {
return serverSocket;
}
// 服务器连接监听器
class AcceptListener extends Thread {
@Override
public void run() {
// TODO 自动生成的方法存根
while (true) {
try {
Socket clientSocket = serverSocket.accept();
sDataHandler.addClient(clientSocket);
clients.add(clientSocket);
// 把这个客户端加入ServerDataHandler的处理队列
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
//记录日志
public synchronized void writeLog(String log) throws Exception {
logWriter.write("[" + (new Date().toLocaleString()) + "]" + log);
logWriter.newLine();
logWriter.flush();
}
//启动服务器
public static void main(String[] args) {
new TTServer();
}
}
package ttserver;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.LinkedList;
public class ChatRoom {
final private long roomId ; //房间编号
TTServer server;
LinkedList <Socket> clients=null; //房间内的客户端列表
//构造方法
public ChatRoom(TTServer server,long roomId){
this.roomId = roomId;
clients = new LinkedList<>();
this.server = server;
}
public long getRoomId() {
return roomId;
}
//注册房间
public synchronized void registerClient(Socket client) {
clients.add(client);
}
//移除房间内的某个客户端,移除后房间变空则从服务器房间列表中移除此房间
public synchronized void removeClient(Socket client) {
for(int i=0;i<clients.size();i++) {
if(clients.get(i)==client) {
clients.remove(i);
break;
}
}
if(clients.size()==0) server.removeRoom(roomId);;
}
//获取房间内的用户数
public int getUserCnt() {
return clients.size();
}
//在房间内广播消息(转发玩家发送的聊天消息)
public void broadcast(String message) {
for(Socket client : clients) {
try {
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
bw.write("{type:sendMessage,status:success,body:{"+message+"}}");
bw.newLine();
bw.flush();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
//在房间内广播一个数据包
public void broadcast(String type,String status,String body) {
for(Socket client : clients) {
try {
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
bw.write("{type:"+type+",status:"+status+",body:{"+body+"}}");
bw.newLine();
bw.flush();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
package ttserver;
import java.io.*;
import java.net.Socket;
import java.sql.ResultSet;
import java.util.concurrent.*;
import dataPack.*;
import dataPack.DataPack.RequestType;
public class ServerDataHandler {
private TTServer server;
private ExecutorService pool; //线程池
public ServerDataHandler(TTServer s) {
// TODO 自动生成的构造函数存根
server = s;
pool = Executors.newFixedThreadPool(8);
}
// 增加连接的客户端对象
public void addClient(Socket client) {
Runnable task = new Runnable() {
public void run() {
BufferedReader br = null;
BufferedWriter bw = null;
String userName = null;// 从数据库获取
long userId = -1;// 从数据库获取
long roomId = -1;
try {
br = new BufferedReader(new InputStreamReader(client.getInputStream()));
bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
while (!client.isClosed()) {
String s = "";
try {
while ((s = br.readLine()) != null) {
DataPack r = new DataPack(s);
System.out.println(r);
server.writeLog(r.toString());
RequestType type = r.getType();
if (type == RequestType.signUp) {
// 注册请求
String usrname = r.get("userName");
String password = r.get("password");
String sql = "insert into user(userName,password,name) values(" + usrname + ","
+ password + "," + usrname + ")";
//检查该用户名是否已被注册
ResultSet rs = server.SQLSelect("select * from user where userName = "+usrname);
if(rs.next()) {
bw.write("{type:signUp,status:error,body:{该用户名已被注册}}");
bw.newLine();
bw.flush();
server.writeLog("{type:signUp,status:error,body:{该用户名已被注册}}");
}else if (server.SQLUpdate(sql)) {
bw.write("{type:signUp,status:success,body:{注册成功}}");
bw.newLine();
bw.flush();
server.writeLog("{type:signUp,status:success,body:{注册成功}}");
} else {
bw.write("{type:signUp,status:error,body:{注册失败,服务器内部错误}}");
bw.newLine();
bw.flush();
server.writeLog("{type:signUp,status:error,body:{注册失败,服务器内部错误}}");
}
} else if (type == RequestType.signIn) {
// 登录请求
// 验证密码
String usrname = r.get("userName");
String pswd = r.get("password");
//检查用户名是否存在
ResultSet rs = server.SQLSelect(
"select password,id,name from user where userName='" + usrname + "'");
if (!rs.next()) {
bw.write("{type:signIn,status:error,body:{用户名不存在,请检查是否输入错误,如果您还没有账号,请先注册一个}}");
bw.newLine();
bw.flush();
server.writeLog("{type:signIn,status:error,body:{用户名不存在,请检查是否输入错误,如果您还没有账号,请先注册一个}}");
} else if (rs.getString("password").equals(pswd)) {
//检查密码是否正确
userId = rs.getLong("id");
userName = rs.getString("name");
bw.write("{type:signIn,status:success,body:{userId:" + userId + ",userName:" + userName + "}}");
bw.newLine();
bw.flush();
server.writeLog("{type:signIn,status:success,body:{userId:" + userId + ",userName:" + userName + "}}");
bw.write("{type:updateRoomCnt,status:,body:{num:"+server.getRoomCnt()+"}}");
bw.newLine();
bw.flush();
bw.write("{type:rename,status:success,body:{newName:"+userName+"}}");
bw.newLine();
bw.flush();
server.writeLog("{type:rename,status:success,body:{newName:"+userName+"}}");
} else {
bw.write("{type:signIn,status:error,body:{用户名或密码错误}}");
bw.newLine();
bw.flush();
server.writeLog("{type:signIn,status:error,body:{用户名或密码错误}}");
}
} else if (type == RequestType.createRoom) {
// 创建房间的请求
roomId = userId;
//将房间加入服务器的房间列表
ChatRoom chatRoom = new ChatRoom(server, roomId);
server.registerRoom(chatRoom);
bw.write("{type:createRoom,status:success,body:{roomId:" + roomId + "}}");
bw.newLine();
bw.flush();
server.writeLog("{type:createRoom,status:success,body:{roomId:" + roomId + "}}");
//通知所有客户端更新在线房间数
for(Socket client:server.getConnectedClientSet()) {
BufferedWriter buw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
buw.write("{type:updateRoomCnt,status:,body:{num:"+server.getRoomCnt()+"}}");
buw.newLine();
buw.flush();
}
} else if (type == RequestType.signOut) {
// 退出房间,如果该用户没有退出房间,就退出房间
server.removeClientFromRoom(roomId, client);
//移除连接列表
server.removeClient(client);
} else if (type == RequestType.enterRoom) {
//通过roomId找到房间,并将客户端socket放入该房间的客户端列表
roomId = Long.parseLong(r.get("roomId"));
boolean f=false;
for(ChatRoom cr : server.getChatRoomList()) {
if(cr.getRoomId()==roomId) {
f=true;
break;
}
bw.write("{type:enterRoom,status:error,body:{该房间不存在}}");
bw.newLine();
bw.flush();
}
if(!f) continue;
//成功加入房间,返回成功消息
server.registerClient(roomId, client);
bw.write("{type:enterRoom,status:success,body:{roomId:" + roomId + "}}");
bw.newLine();
bw.flush();
server.writeLog("{type:enterRoom,status:success,body:{roomId:" + roomId + "}}");
//在该房间内广播欢迎消息
String helloMessage = "系统(房间号:" + roomId + "):欢迎" + userName + "加入房间!!!(づ ̄ 3 ̄)づ";
server.sendMessge(roomId, helloMessage);
//通知该房间的客户端,更新人数
for(ChatRoom chatRoom:server.getChatRoomList()) {
if(chatRoom.getRoomId()==roomId) {
chatRoom.broadcast("updateUserCnt","","num:"+chatRoom.getUserCnt());
}
}
} else if (type == RequestType.exitRoom) {
bw.write("{type:exitRoom,status:success,body:{}}");
bw.newLine();
bw.flush();
server.writeLog("{type:exitRoom,status:success,body:{}}");
server.removeClientFromRoom(roomId, client);
server.sendMessge(roomId, "系统(房间号:" + roomId + "):" + userName + "退出了房间");
// 房主退出房间,关闭房间
if (roomId == userId) {
server.removeRoom(roomId);
}else {
//通知该房间的客户端,更新人数
for(ChatRoom chatRoom:server.getChatRoomList()) {
if(chatRoom.getRoomId()==roomId) {
chatRoom.broadcast("updateUserCnt","","num:"+chatRoom.getUserCnt());
}
}
}
} else if (type == RequestType.sendMessage) {
//敏感词屏蔽
String content = r.get("content");
String message = userName + ":" + TTServer.replaceIllegalWord(content);
//交给房间转发消息给房间内容易客户端
server.sendMessge(roomId, message);
}else if(type==RequestType.rename) {
//更新数据库信息
String sql = "update `user` set name=\""+ r.get("newName")+"\" where id = "+userId+";";
if(server.SQLUpdate(sql)) {
bw.write("{type:rename,status:success,body:{newName:"+r.get("newName")+"}}");
bw.newLine();
bw.flush();
userName = r.get("newName");
server.writeLog("{type:rename,status:success,body:{}}");
}else {
bw.write("{type:rename,status:error,body:{改名失败,请检查名字是否过长}}");
bw.newLine();
bw.flush();
server.writeLog("{type:rename,status:error,body:{改名失败,请检查名字是否过长}}");
}
}
else {
System.out.println("未知请求");
}
}
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
System.out.println(userName+"退出了连接");
//将该客户端的socket从连接集移除
server.getConnectedClientSet().remove(client);
//关闭监听线程
break;
}
}
}
};
//加入线程池
pool.submit(task);
}
}
package ttclient;
import java.awt.event.*;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import dataPack.*;
public class TTClient {
Socket socket;
ClientReceiver clientReceiver;// 客户端接收器,用来随时接收服务器发来的消息
ClientFrame clientFrame;// 用户界面
TTUser user;// 当前登录用户的引用
BufferedReader br=null;
BufferedWriter bw = null;
public TTClient() {
// TODO 自动生成的构造函数存根
try {
// 连接服务器,本地测试暂时使用"local host"
socket = new Socket("localhost", 9000);
clientFrame = new ClientFrame(this);
clientFrame.showSignInInterface();
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
clientReceiver = new ClientReceiver(this);
clientReceiver.start();
// 窗口关闭时,关闭输入输出
clientFrame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
// TODO 自动生成的方法存根
try {
socket.close();
} catch (IOException e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
}
}
});
} catch (UnknownHostException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
TTUser getUser() {
return user;
}
public Socket getSocket() {
return socket;
}
//向服务器发送请求
public void SendRequest(DataPack r) throws IOException {
System.out.println(r.toString());
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write(r.toString());
bw.newLine();
bw.flush();
}
// 注册账号
void signUp(String userName, String password) {
DataPack a =new DataPack(DataPack.RequestType.signUp,"{userName:'"+userName+"',password:'"+password+"'}") ;
try {
SendRequest(a);
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
// 登录账号
void signIn(String userName, String password) {
// 向服务器发送登录请求,
DataPack request = new DataPack(DataPack.RequestType.signIn,"userName:"+userName+",password:"+password) ;
try {
//发送请求
SendRequest(request);
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
void signOut() {
DataPack request = new DataPack(DataPack.RequestType.signOut,"");
try {
//发送请求
SendRequest(request);
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
// 创建房间
void createRoom() {
DataPack request = new DataPack(DataPack.RequestType.createRoom,"");
try {
SendRequest(request);
} catch (IOException e) {
// TODO 自动生成的 catch 块
}
}
// 进入房间
void enterRoom(long roomId) {
DataPack request = new DataPack(DataPack.RequestType.enterRoom,"roomId:"+roomId);
try {
SendRequest(request);
} catch (Exception e) {
// TODO: handle exception
}
}
//退出房间
void exitRoom() {
DataPack request = new DataPack(DataPack.RequestType.exitRoom,"");
try {
SendRequest(request);
}catch (Exception e) {
// TODO: handle exception
}
}
// 发送消息
void sendMessage(String content,long roomId) {
DataPack request = new DataPack(DataPack.RequestType.sendMessage,"content:"+content);
try {
SendRequest(request);
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
void rename(String newName) {
DataPack request = new DataPack(DataPack.RequestType.rename,"newName:"+newName);
try {
SendRequest(request);
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
// 接收消息
void receiveMessage(String message) {
// 界面上显示新消息
clientFrame.receiveMessage(message);
}
public static void main(String[] args) {
//启动客户端
new TTClient();
}
}
package ttclient;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import javax.swing.*;
import javax.swing.text.DefaultCaret;
public class ClientFrame extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
// 窗口显示的四个模式
final static int SIGN_IN = 0;
final static int SIGN_UP = 1;
final static int IN_THE_ROOM = 2;
final static int OUT_OF_ROOM = 3;
TTClient client;
private Container contentPane;
private JTextPane showArea = null;
private JScrollPane showScrollPane = null;
private JLabel timeLabel = null;
private Calendar now;
private JLabel NameLabel;//用户名显示
private JLabel roomCntLabel;//房间计数,out_room_interface;
private JLabel userCntLabel;//房间内人数计数,in_room_interface;
private int CntLabelWidth,timeLableWidth,NameLableWidth,settingBtnWidth,exitBtnWidth;
public ClientFrame(TTClient client) {
this.client = client;
// TODO 自动生成的构造函数存根
setTitle("TTChatRoom");
setIconImage(new ImageIcon("images/TTChatRoom.png").getImage());
contentPane = getContentPane();
contentPane.setBackground(Color.WHITE);
timeLabel = new JLabel();
timeLabel.setHorizontalAlignment(JLabel.CENTER);
timeLabel.setFont(new Font("Times New Roman", Font.ITALIC, 15));
timeLabel.setBounds(166, 0, 200, 30);
roomCntLabel = new JLabel("", JLabel.CENTER);
userCntLabel = new JLabel("",JLabel.CENTER);
CntLabelWidth=timeLableWidth=NameLableWidth=190;
settingBtnWidth=80;
exitBtnWidth=150;
NameLabel = new JLabel("昵称", JLabel.CENTER);
NameLabel.setFont(new Font("黑体", Font.ITALIC, 15));
NameLabel.setBounds(timeLableWidth+CntLabelWidth, 0, NameLableWidth, 30);
now = Calendar.getInstance();
new updateTimebar().start();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void showSignInInterface() {
contentPane.removeAll();
setBounds(700, 150, 500, 700);
setLayout(null);
setResizable(false);
// 第一个子面板,显示应用图标
JPanel iconPanel = new JPanel();
iconPanel.setBackground(Color.white);
iconPanel.setLayout(null);
// 图标
ImageIcon icon = new ImageIcon("images/TTChatRoom.png");
// 图标缩放
icon.setImage(icon.getImage().getScaledInstance(100, 100, Image.SCALE_DEFAULT));
// 图标标签
JLabel iconLabel = new JLabel(icon);
iconLabel.setBounds(0, 0, 500, 120);
// 文字标签
JLabel titleLabel = new JLabel("Sign in to TTChatRoom", JLabel.CENTER);
titleLabel.setFont(new Font("Times New Roman", 0, 30));
titleLabel.setBounds(0, 120, 500, 30);
iconPanel.add(iconLabel);
iconPanel.add(titleLabel);
iconPanel.setBounds(0, 30, 500, 180);
// 第二个子面板,显示玩家登录表单
JPanel formPanel = new JPanel();
formPanel.setBackground(Color.white);
GridLayout gL = new GridLayout(5, 1);
gL.setVgap(8);
formPanel.setLayout(gL);
JLabel usernamrLabel = new JLabel("Username or email address");
usernamrLabel.setFont(new Font("Times New Roman", Font.BOLD, 25));
JTextField nameInput = new JTextField();
nameInput.setFont(new Font("黑体", Font.BOLD, 25));
JLabel passwordLabel = new JLabel("Password");
passwordLabel.setFont(new Font("Times New Roman", Font.BOLD, 25));
JButton signInBtn = new JButton("Sign in");
signInBtn.setFont(new Font("Times New Roman", Font.BOLD, 25));
signInBtn.setBackground(new Color(50, 201, 85));
JPasswordField passwordInput = new JPasswordField();
passwordInput.setFont(new Font("宋体", Font.BOLD, 25));
signInBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 处理登录的代码
String userName = nameInput.getText();
String passWord = new String(passwordInput.getPassword());
if (userName.length() == 0) {
showErrorMessage("请输入用户名!");
return;
} else if (passWord.length() == 0) {
showErrorMessage("请输入密码!");
return;
}
client.signIn(userName, passWord);
}
});
formPanel.add(usernamrLabel);
formPanel.add(nameInput);
formPanel.add(passwordLabel);
formPanel.add(passwordInput);
formPanel.add(signInBtn);
formPanel.setBounds(50, 200, 400, 300);
// 第三个子面板,引导新用户注册
JPanel signUpPanel = new JPanel();
signUpPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
JLabel guideLabel = new JLabel("New to TTChatRoom?");
guideLabel.setFont(new Font("Times New Roman", Font.BOLD, 25));
JButton toSignUpBtn = new JButton("Create an account.");
toSignUpBtn.setBackground(new Color(63, 146, 210));
// toSignUpBtn.setBackground(new Color(50,201,85));
toSignUpBtn.setFont(new Font("Times New Roman", Font.BOLD, 25));
toSignUpBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO 自动生成的方法存根
showSignUpInterface();
}
});
signUpPanel.add(guideLabel);
signUpPanel.add(toSignUpBtn);
signUpPanel.setBounds(50, 510, 400, 100);
contentPane.add(iconPanel);
contentPane.add(formPanel);
contentPane.add(signUpPanel);
contentPane.repaint();
setVisible(true);
}
public void showSignUpInterface() {
contentPane.removeAll();
setBounds(700, 150, 500, 700);
setLayout(null);
setResizable(false);
// 第一个子面板,显示应用图标
JPanel iconPanel = new JPanel();
iconPanel.setBackground(Color.white);
iconPanel.setLayout(null);
// 图标
ImageIcon icon = new ImageIcon("images/TTChatRoom.png");
// 图标缩放
icon.setImage(icon.getImage().getScaledInstance(100, 100, Image.SCALE_DEFAULT));
// 图标标签
JLabel iconLabel = new JLabel(icon);
iconLabel.setBounds(0, 0, 500, 120);
// 文字标签
JLabel titleLabel = new JLabel("Create your account", JLabel.CENTER);
titleLabel.setFont(new Font("Times New Roman", 0, 30));
titleLabel.setBounds(0, 120, 500, 30);
iconPanel.add(iconLabel);
iconPanel.add(titleLabel);
// iconPanel.setBorder(BorderFactory.createLineBorder(Color.black));
iconPanel.setBounds(0, 30, 500, 180);
// 第二个子面板,显示玩家注册表单
JPanel formPanel = new JPanel();
formPanel.setBackground(Color.white);
GridLayout gL = new GridLayout(7, 1);
gL.setVgap(8);
formPanel.setLayout(gL);
JLabel usernameLabel = new JLabel("Username or email address");
usernameLabel.setFont(new Font("Times New Roman", Font.BOLD, 25));
JTextField nameInput = new JTextField();
nameInput.setFont(new Font("Times New Roman", Font.BOLD, 25));
JLabel passwordLabel = new JLabel("Password");
passwordLabel.setFont(new Font("黑体", Font.BOLD, 25));
JLabel passwordLabel1 = new JLabel("Confirm Password");
passwordLabel1.setFont(new Font("黑体", Font.BOLD, 25));
JButton signUpBtn = new JButton("Sign up for TTChatRoom");
signUpBtn.setFont(new Font("Times New Roman", Font.BOLD, 25));
signUpBtn.setBackground(new Color(63, 146, 210));
JPasswordField passwordInput = new JPasswordField();
passwordInput.setFont(new Font("宋体", Font.BOLD, 25));
JPasswordField passwordInput1 = new JPasswordField();
passwordInput1.setFont(new Font("宋体", Font.BOLD, 25));
signUpBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 处理注册的代码
String userName = nameInput.getText();
String pswd = new String(passwordInput.getPassword());
String pswd1 = new String(passwordInput1.getPassword());
if (userName.length() == 0) {
showErrorMessage("请输入用户名!");
return;
}
if (pswd.length() == 0) {
showErrorMessage("请输入密码!");
return;
}
if (pswd1.length() == 0) {
showErrorMessage("请输入第二遍密码!");
return;
}
for (int i = 0; i < userName.length(); i++) {
char ch = userName.charAt(i);
if (!((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '@'
|| ch == '_' || ch == '.')) {
showErrorMessage("用户名中不可以有特殊字符,用户名应为大小写字母(a~z,A~Z),数字(0~9)和#、_、.等符号的组合。");
return;
}
}
if (!pswd.equals(pswd1)) {
showErrorMessage("输入的两次密码不一样");
return;
}
client.signUp(userName, pswd);
}
});
formPanel.add(usernameLabel);
formPanel.add(nameInput);
formPanel.add(passwordLabel);
formPanel.add(passwordInput);
formPanel.add(passwordLabel1);
formPanel.add(passwordInput1);
formPanel.add(signUpBtn);
formPanel.setBounds(50, 200, 400, 300);
// 第三个子面板,引导用户回到登录界面
JPanel signUpPanel = new JPanel();
signUpPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
JLabel guideLabel = new JLabel("Already have an account?");
guideLabel.setFont(new Font("Times New Roman", Font.BOLD, 25));
JButton toSignInBtn = new JButton("To sign in.");
toSignInBtn.setBackground(new Color(50, 201, 85));
toSignInBtn.setFont(new Font("Times New Roman", Font.BOLD, 25));
toSignInBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO 自动生成的方法存根
showSignInInterface();
}
});
signUpPanel.add(guideLabel);
signUpPanel.add(toSignInBtn);
signUpPanel.setBounds(50, 510, 400, 100);
contentPane.add(iconPanel);
contentPane.add(formPanel);
contentPane.add(signUpPanel);
contentPane.repaint();
setVisible(true);
}
void showOutOfRoomInterface() {
contentPane.removeAll();
setBounds(getX(), getY(), 800, 600);
contentPane.setLayout(null);
// 子面板1 ,显示当前状态信息
JPanel statusPanel = new JPanel();
statusPanel.setLayout(null);
roomCntLabel.setFont(new Font("黑体", Font.ITALIC, 15));
roomCntLabel.setBounds(0, 0, CntLabelWidth, 30);
// timeLabel = new JLabel();
// timeLabel.setHorizontalAlignment(JLabel.CENTER);
// timeLabel.setFont(new Font("黑体", Font.ITALIC, 15));
// timeLabel.setBounds(216, 0, 266, 30);
// NameLabel = new JLabel("昵称:"+client.getUser().getName(), JLabel.CENTER);
ImageIcon signOutIcon = new ImageIcon("images/Sign out.png");
signOutIcon = new ImageIcon(signOutIcon.getImage().getScaledInstance(28, 28, Image.SCALE_DEFAULT));
JButton signOutBtn = new JButton("sign out", signOutIcon);
signOutBtn.setBackground(Color.lightGray);
signOutBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO 自动生成的方法存根
client.signOut();
}
});
signOutBtn.setBounds(NameLableWidth+CntLabelWidth+timeLableWidth+settingBtnWidth, 0, exitBtnWidth, 30);
ImageIcon settingIcon = new ImageIcon("images/setting.png");
settingIcon = new ImageIcon(settingIcon.getImage().getScaledInstance(28, 28, Image.SCALE_DEFAULT));
JButton settingButton = new JButton("修改");
settingButton.setBackground(Color.lightGray);
settingButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO 自动生成的方法存根
String newName = JOptionPane.showInputDialog("请输入新名称:");
if(newName!=null&&newName.length()!=0) {
client.rename(newName);
}else {
}
}
});
settingButton.setBounds(NameLableWidth+timeLableWidth+CntLabelWidth,0,settingBtnWidth,30);
statusPanel.add(settingButton);
statusPanel.add(roomCntLabel);
statusPanel.add(timeLabel);
statusPanel.add(NameLabel);
statusPanel.add(signOutBtn);
statusPanel.setBounds(0, 0, 800, 30);
// 子面板二,提供创建房间和加入房间按钮
JPanel roomBtnsPanel = new JPanel();
roomBtnsPanel.setLayout(null);
roomBtnsPanel.setBackground(Color.white);
// 创建房间按钮
ImageIcon createIcon = new ImageIcon(
new ImageIcon("images/createRoom1.png").getImage().getScaledInstance(150, 150, Image.SCALE_DEFAULT));
JButton createRoomBtn = new JButton(createIcon);
createRoomBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO 自动生成的方法存根
client.createRoom();
}
});
createRoomBtn.setBackground(Color.white);
createRoomBtn.setBounds(120, 73, 160, 160);
JLabel createLabel = new JLabel("创建房间", JLabel.CENTER);
createLabel.setFont(new Font("黑体", Font.PLAIN, 20));
createLabel.setBounds(120, 240, 160, 40);
roomBtnsPanel.add(createRoomBtn);
roomBtnsPanel.add(createLabel);
// 加入房间按钮
ImageIcon joinIcon = new ImageIcon(
new ImageIcon("images/joinRoom.png").getImage().getScaledInstance(150, 150, Image.SCALE_DEFAULT));
JButton enterRoomBtn = new JButton(joinIcon);
enterRoomBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO 自动生成的方法存根
String roomId = JOptionPane.showInputDialog("请输入房间号");
try {
long rd = Long.parseLong(roomId);
client.enterRoom(rd);
} catch (NumberFormatException exception) {
// TODO: handle exception
JOptionPane.showMessageDialog(enterRoomBtn, "请输入正确的房间号", "房间号错误", JOptionPane.ERROR_MESSAGE);
return;
}
}
});
enterRoomBtn.setBackground(Color.white);
enterRoomBtn.setBounds(320, 73, 160, 160);
JLabel joinLabel = new JLabel("加入房间", JLabel.CENTER);
joinLabel.setFont(new Font("黑体", Font.PLAIN, 20));
joinLabel.setBounds(320, 240, 160, 40);
roomBtnsPanel.add(joinLabel);
roomBtnsPanel.add(enterRoomBtn);
// 帮助按钮
ImageIcon helpIcon = new ImageIcon(
new ImageIcon("images/help.png").getImage().getScaledInstance(150, 150, Image.SCALE_DEFAULT));
JButton helpBtn = new JButton(helpIcon);
helpBtn.setBackground(Color.white);
helpBtn.setBounds(520, 73, 160, 160);
JLabel helpLabel = new JLabel("帮 助", JLabel.CENTER);
helpLabel.setFont(new Font("黑体", Font.PLAIN, 20));
helpLabel.setBounds(520, 240, 160, 40);
helpBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO 自动生成的方法存根
showErrorMessage("功能尚未完善");
}
});
roomBtnsPanel.add(helpLabel);
roomBtnsPanel.add(helpBtn);
roomBtnsPanel.setBounds(0, 33, 800, 400);
contentPane.add(statusPanel);
contentPane.add(roomBtnsPanel);
contentPane.repaint();
}
void showInRoomInterface() {
contentPane.removeAll();
setBounds(getX(),getY(), 800, 600);
contentPane.setLayout(null);
// 子面板1 ,显示当前状态信息
JPanel statusPanel = new JPanel();
statusPanel.setLayout(null);
userCntLabel.setFont(new Font("黑体", Font.ITALIC, 15));
userCntLabel.setBounds(0, 0, CntLabelWidth, 30);
// userNameLabel = new JLabel("昵称:"+client.getUser().getName(), JLabel.CENTER);
setVisible(true);
ImageIcon signOutIcon = new ImageIcon("images/Sign out.png");
signOutIcon = new ImageIcon(signOutIcon.getImage().getScaledInstance(28, 28, Image.SCALE_DEFAULT));
JButton exitBtn = new JButton("exit room", signOutIcon);
exitBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO 自动生成的方法存根
client.exitRoom();
}
});
ImageIcon settingIcon = new ImageIcon("images/setting.png");
settingIcon = new ImageIcon(settingIcon.getImage().getScaledInstance(28, 28, Image.SCALE_DEFAULT));
JButton settingButton = new JButton("修改");
settingButton.setBackground(Color.lightGray);
settingButton.setBounds(NameLableWidth+timeLableWidth+CntLabelWidth,0,settingBtnWidth,30);
settingButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO 自动生成的方法存根
showErrorMessage("房间内不能修改昵称哦");
}
});
exitBtn.setBackground(Color.lightGray);
exitBtn.setBounds(CntLabelWidth+timeLableWidth+NameLableWidth+settingBtnWidth, 0, exitBtnWidth, 30);
statusPanel.add(settingButton);
statusPanel.add(userCntLabel);
statusPanel.add(timeLabel);
statusPanel.add(NameLabel);
statusPanel.add(exitBtn);
statusPanel.setBounds(0, 0, 800, 30);
// 子面板二,聊天信息面板
JPanel showPanel = new JPanel();
showPanel.setBounds(0, 32, 800, 450);
showPanel.setLayout(null);
showPanel.setBackground(Color.lightGray);
showArea = new JTextPane();
showScrollPane = new JScrollPane();
showScrollPane.setViewportView(showArea);
showScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
DefaultCaret caret = (DefaultCaret)showArea.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
showArea.setBounds(0, 0, 780, 450);
showArea.setEditable(false);
showArea.setFont(new Font("黑体", Font.PLAIN, 18));
showScrollPane.setBounds(0, 0, 795, 450);
showPanel.add(showScrollPane);
// 子面板三,输入面板
JPanel inputPanel = new JPanel();
inputPanel.setLayout(null);
inputPanel.setBounds(0, 482, 800, 80);
JTextField inpuTextField = new JTextField();
inpuTextField.setBounds(20, 10, 650, 60);
inpuTextField.setFont(new Font("黑体", Font.PLAIN, 20));
ImageIcon submitIcon = new ImageIcon(
new ImageIcon("images/submit.png").getImage().getScaledInstance(60, 60, Image.SCALE_DEFAULT));
JButton submitBtn = new JButton(submitIcon);
submitBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO 自动生成的方法存根
String content = inpuTextField.getText().trim();
if (content.length() == 0) {
showErrorMessage("请不要发送空白消息");
return;
}
client.sendMessage(content, client.getUser().getRoomId());
inpuTextField.setText("");
}
});
// submitBtn.setFont(new Font("黑体",Font.PLAIN,20));
submitBtn.setBounds(680, 10, 80, 60);
submitBtn.setBackground(Color.white);
inputPanel.add(inpuTextField);
inputPanel.add(submitBtn);
contentPane.add(showPanel);
contentPane.add(statusPanel);
contentPane.add(inputPanel);
contentPane.repaint();
}
void showErrorMessage(String errMessage) {
JOptionPane.showMessageDialog(null, errMessage, "错误提示", JOptionPane.ERROR_MESSAGE);
}
void receiveMessage(String message) {
if (showArea != null) {
String oldString = showArea.getText();
StringBuilder mess = new StringBuilder();
for(int i=0;i<message.length();i++) {
if(i!=0&&i%42==0) {
mess.append("\n");
}
mess.append(message.charAt(i));
}
if (oldString.length() != 0)
showArea.setText(oldString + "\n" + mess);
else {
showArea.setText(""+mess);
}
}
}
void updateRoomCnt(int num) {
if(roomCntLabel!=null) {
roomCntLabel.setText("当前活跃房间数:"+num);
roomCntLabel.repaint();
}
}
void updateUserCnt(int num) {
if(userCntLabel!=null) {
userCntLabel.setText("当前房间("+ client.getUser().getRoomId()+" )人数:"+num);
userCntLabel.repaint();
}
}
void updateUserName(String newName) {
if(NameLabel!=null) {
NameLabel.setText("昵称:"+newName);
}
System.out.println("updateName");
}
private class updateTimebar extends Thread {
@Override
public void run() {
while(timeLabel!=null) {
try {
Thread.sleep(1000);
now.setTime(new Date());
timeLabel.setText(now.getTime().toLocaleString());
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
new ClientFrame(null).showSignUpInterface();
}
}
package ttclient;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import javax.swing.JOptionPane;
import dataPack.DataPack.*;
import dataPack.DataPack;
public class ClientReceiver extends Thread {
TTClient client;
Socket clientSocket;
ClientFrame clientFrame;
public ClientReceiver(TTClient client) {
// TODO 自动生成的构造函数存根
this.client = client;
clientFrame = client.clientFrame;
clientSocket = client.getSocket();
}
@Override
public void run() {
// TODO 自动生成的方法存根
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
String content = "";
try {
while (!clientSocket.isClosed()&&(content = br.readLine()) != null&&!clientSocket.isClosed()) {
System.out.println(" receiver: "+content);
DataPack response = new DataPack(content);
DataPack.RequestType type = response.getType();
String status = response.getStatus();
if(type==RequestType.sendMessage) {
//接收消息,显示
client.receiveMessage(response.getBody());
}else if(type==RequestType.signIn) {
//登录成功,换界面
if(status.equals("success")) {
client.user = new TTUser(Long.parseLong(response.get("userId")),response.get("userName"));
clientFrame .showOutOfRoomInterface();
}else {
//登录失败,给出提示
JOptionPane.showMessageDialog(clientFrame,response.getBody(),"登录失败",JOptionPane.ERROR_MESSAGE);
}
}else if(type==RequestType.signUp) {
//注册成功
if(status.equals("success")) {
JOptionPane.showMessageDialog(clientFrame,"注册成功,快去登录试试吧!");
}else if(response.getBody()!=null)
clientFrame.showErrorMessage(response.getBody());
else clientFrame.showErrorMessage("注册失败");
}else if(type==RequestType.signOut) {
//退出登录成功返回登录界面
if(status.equals("success")) {
clientFrame.showSignInInterface();
}else {
//失败
clientFrame.showErrorMessage(response.getBody());
}
}else if(type==RequestType.createRoom) {
//创建房间成功,自动进入房间
if(status.equals("success")) {
long roomId = Long.parseLong(response.get("roomId"));
client.enterRoom(roomId);
}else {
//失败
}
}else if(type==RequestType.enterRoom) {
//进入房间成功,切换界面
if(status.equals("success")) {
client.getUser().setRoomNum(Integer.parseInt(response.get("roomId")));
System.out.println("进入房间成功,开始接收房间消息");
clientFrame.showInRoomInterface();
}else {
//失败
clientFrame.showErrorMessage(response.getBody());
}
}else if(type==RequestType.exitRoom) {
//退出房间成功,切换界面
if(status.equals("success")) {
clientFrame.showOutOfRoomInterface();
}else if(status.equals("roomClosed")){
client.exitRoom();
clientFrame.showErrorMessage(response.getBody());
}
else{
//失败
}
}else if(type==RequestType.updateRoomCnt){
//更新界面显示
clientFrame.updateRoomCnt(Integer.parseInt(response.get("num")));
}else if(type==RequestType.updateUserCnt) {
//更新界面显示
clientFrame.updateUserCnt(Integer.parseInt(response.get("num")));
}else if(type==RequestType.rename) {
if(status.equals("success")) {
//更新用户状态
client.getUser().setName(response.get("newName"));
//更新界面显示
clientFrame.updateUserName(response.get("newName"));
}else {
clientFrame.showErrorMessage(response.getBody());
}
}
else {
System.out.println("未知请求");
}
}
} catch (IOException e) {
// TODO 自动生成的 catch 块
System.out.println("客户端接收器关闭");
}
}
}
package ttclient;
public class TTUser {
private String name;//用户名
private long id;//用户编号
private long roomId;//当前所在的房间编号
private boolean isRoomOwner;//是否为该房间的房主
public TTUser(long Id,String name) {
// TODO 自动生成的构造函数存根
this.setId(Id);
this.setName(name);
setRoomNum(-1);
setRoomOwner(false);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getRoomId() {
return roomId;
}
public void setRoomNum(long roomNum) {
this.roomId = roomNum;
}
public boolean isRoomOwner() {
return isRoomOwner;
}
public void setRoomOwner(boolean isRoomOwner) {
this.isRoomOwner = isRoomOwner;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
package dataPack;
public class DataPack {
//请求的所有类型
public static enum RequestType{
signUp,signIn,signOut,enterRoom,createRoom,exitRoom,sendMessage,updateRoomCnt,updateUserCnt,rename
}
final private RequestType type;
final private String body;
final private String status;
//通过字符串DataPack对象
public DataPack(String dataPackString) {
this.status = getStatus(dataPackString);
this.type = getType(dataPackString);
this.body = getBody(dataPackString);
}
//请求构造方法,通过类型和数据构成
public DataPack(RequestType type,String data) {
this.status = null;
this.type = type;
this.body = data;
}
//将字符串解析为DataPack对象
public static DataPack parse(String requestString) {
return new DataPack(requestString);
}
public RequestType getType() {
return type;
}
public String getBody() {
return body;
}
public String getStatus() {
return status;
}
//获取特定键对应的值
public String get(String key) {
int index= body.indexOf(key);
if(index!=-1) {
return body.substring(index+key.length()+1).split(",")[0].split("}")[0];
}
return null;
}
public static RequestType getType(String requestString) {
RequestType type =null;
int index =requestString.indexOf("type:");
if(index==-1) return type;
String typeString=requestString.substring(index+5).split(",")[0];
for(RequestType type1:RequestType.values()) {
if(typeString.equals(type1.toString()))
return type1;
}
return type;
}
public static String getBody(String dataPackString) {
String body=null;
int index = dataPackString.indexOf("body:{");
if(index==-1) return null;
body = dataPackString.substring(index+6,dataPackString.lastIndexOf("}}"));
return body;
}
public static String getStatus(String responseString) {
String status=null;
int index = responseString.indexOf("status:");
if(index==-1) return status;
return responseString.substring(index+7).split(",")[0].split("}}")[0];
}
public String toString() {
return "{type:"+getType()+",status:"+getStatus()+",body:{"+getBody()+"}}";
}
}
这个项目实现了多人多房间的网络聊天功能,使用数据库记录玩家账户信息,实现了基本的注册登录功能,已存在的功能实现和界面的设计都是比较好的,但是缺少了足够强大的数据库来作为支撑,只能支持实时聊天,既不能保存用户群组信息,也不能在用户离线时接收消息,等待用户连接后再推送给用户。此项目只能像一个文字版的腾讯会仪一样,客户在约定好的时间进入特定的房间进行聊天。但是尽管如此,这个项目的可拓展性还是很强的,它拥有一套简单而强大的数据交换协议。
在技术方面,此项目使用了几乎在Java基础课程中学到的所有基础知识,使用了文件的输入输出、网络编程、数据库编程、多线程编程还使用了线程池技术来管理线程。此项目是通过对Java基础知识学习后第一次综合实战项目,也是对自己在前段时间学习效果的检测与考验,整体来说还算可以,但是仍然发现了个人在项目开发时有一些缺点,比如在需求分析时有时分析的不够深入,在软件设计过程中也存在犯错的地方。此外由于时间关系这个项目还有很多不完善的地方比如异常处理,还有很多代码逻辑有待优化。
一个阶段的结束意味着下一个阶段的开始,在以后的学习开发中要吸取从这次课程设计过程中的经验教训,戒骄戒躁,砥砺前行。
此项目的所代码,依赖文件和数据库备份文件我都上传到了我的资源中:点击下载