聊天室小程序

项目简介
项目名称:聊天室。
项目功能:此项目通过连接数据库实现了用户的注册登录功能,支持用户创建房间或者加入别人的房间,并在房间内进行多人实时聊天。
此项目是我本学期Java基础课程的课程设计,综合Java基础课程中的文件输入输出、多线程、Swing编程、网络编程、数据库编程等技术实现了聊天室的基本功能。

系统设计与实现
聊天室系统的总体设计
聊天室系统的采用Client-Server(C/S)模式,服务器与客户端之间使用数据包(data package)作为交换的消息。用户通过聊天室客户端的用户界面向服务器发送请求(request)包,服务器通过接收客户端发送的请求包,根据请求内容与数据库查询结果给予应答向客户端返回一个数据包,然后客户端接收服务器的回应(response),根据回应的内容将操作的结果通过界面反馈给用户。

服务器端功能设计

服务器大致由以下部分组成

在这里插入图片描述

  • 已连接的客户端列表:只要客户端连接了服务器,就会将客户端的socket传入这个列表中,便于后面服务器向每个连接的服务器发送消息(如:在线房间数更新,该列表中包括所有登录了的客户端socket)。
  • 房间列表:用户创建的房间都会被抽象为一个ChatRoom对象,存入该列表中,使用了观察者模式,服务器收到客户端聊天信息会发到指定的ChatRoom,再由该ChatRoom对象广播给该房间内的客户端(ChatRoom对象中含一个Socket列表存放该房间内的客户端Socket);
  • 数据库连接:控制数据库的连接,查询与更新
  • 服务器数据处理器:服务器要针对每一个客户端单独开设一个线程,监听客户端请求,为减小服务器的压力,采用线程池管理。
  • 客户端连接监听器:监听客户端的连接,一旦检测到新的客户端连接就让服务器数据处理器在线程池中创建一个新的线程。

客户端功能设计

客户端大致由以下部分组成

在这里插入图片描述

  • 客户端窗口:使用swing显示客户端的用户界面,并与用户进行交互。
  • 客户端信息接收器:使用一个线程接收服务器的应答。
  • 客户端用户:记录用户当前的状态与属性,为界面显示提供基本信息。

数据包

由于本系统客户端与服务器消息传输使用的是字符缓冲流,且服务器要通过此消息区分不同的请求,针对此需求,设计了一个数据包(DataPack)类。

 在这里插入图片描述

  • Type : 一个枚举型的标识,标名该请求/应答得类型。
  • Status : 服务器回应时的状态(成功/失败),客户端基于此状态判断请求是否成功。
  • Body : 请求的附带数据,比如登录时,客户端要将用户名和密码发送给服务器,若密码验证成功,服务器要将在数据库查询到的用户昵称发回给客户端,客户端便可以借此完成用户信息的初始化。
  • 源码展示

    服务器端代码

  • 服务器主体类(TTServer.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();
        }
    }

  • 聊天室类(ChatRoom.java)
  • 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();
                }
            }
        }
    }

  • 服务器数据处理器(ServerDataHandler.java)
  • 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);
        }
    }

    客户端代码

  • 客户端主体(TTClient.java)
  • 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();
        }
    }

  • 客户端窗口(ClientFrame.java)
  • 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();
        }
    }

  • 客户端接收器(ClientReceiver.java)
  • 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("客户端接收器关闭");
            }

        }
    }

  • 用户(TTUser.java)
  • 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;
        }    
    }

    数据包代码

  • 数据包类(DataPack.java)
  • 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()+"}}";
        }    
    }
    总结

  • 这个项目实现了多人多房间的网络聊天功能,使用数据库记录玩家账户信息,实现了基本的注册登录功能,已存在的功能实现和界面的设计都是比较好的,但是缺少了足够强大的数据库来作为支撑,只能支持实时聊天,既不能保存用户群组信息,也不能在用户离线时接收消息,等待用户连接后再推送给用户。此项目只能像一个文字版的腾讯会仪一样,客户在约定好的时间进入特定的房间进行聊天。但是尽管如此,这个项目的可拓展性还是很强的,它拥有一套简单而强大的数据交换协议。
     

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值