Java课设—聊天室(附带整套代码)

目录

一.涉及的知识点

二.功能

1.登录界面

2.聊天页面

三.整体编程思路

四.客户端与服务器端

1.在注册页面加入事件监听和登录按钮事件

2.在聊天页面显示当前登录人账户

3.服务器端创建

4.客户端创建

5.为发送按钮添加事件

6.连接到服务器端的socket需要监听自己客户端有没有向服务器端发送消息,然后将消息转发给每一个客户端

7.客户端接收来自服务器端的消息

1.注册/登录页面

2.聊天页面

3.客户端页面

4.客户端


一.涉及的知识点

包含:java基础语法,异常处理,IO流,网络编程,多线程,GUI界面,内部类,匿名类等,

有不懂的地方可以边学习边进行阅读

二.功能

1.登录界面

2.聊天页面

显示用户账户,发送信息,聊天记录

3.客户端界面

显示在线人数,发布同告,查询聊天记录

三.整体编程思路

由于整体流程过大,我们进行分步编程,通过完成一步一步小任务,最后完成整个任务

四.客户端与服务器端

博主这里用的是idea官方的插件来进行制作的图形界面,不做过多讲解,有需要的可以在csdn搜索java图形界面插件,有详细安装教程

1.在注册页面加入事件监听和登录按钮事件

        loginbtn.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {//事件监听
                try {
                    String account = accountFiled.getText();//获取文本框内容
                    String password = passwordFiled.getText();
                    if (password.equals("")) {
                        JOptionPane.showMessageDialog(null, "密码不能为空", "来自系统的提示", JOptionPane.WARNING_MESSAGE);
                        return;
                    }
                    if (account.equals("")) {
                        JOptionPane.showMessageDialog(null, "账户不能为空", "来自系统的提示", JOptionPane.WARNING_MESSAGE);
                        //(,内容,标题,警告类型);
                        return;
                    }
                    //连接数据库
                    //连接服务器端
                    Socket socket = new Socket("127.0.0.1", 9999);
                    dispose();//释放关闭当前窗口
                    new ChatFrame(accountFiled.getText(),socket).setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                }catch(IOException ex){
                    ex.printStackTrace();
                    JOptionPane.showMessageDialog(null,"网络连接失败!","来自系统的提示",JOptionPane.WARNING_MESSAGE);
                }catch(Exception ex){
                    ex.printStackTrace();//打印异常信息
                    JOptionPane.showMessageDialog(null,"系统忙,请稍后再试!","来自系统的提示",JOptionPane.WARNING_MESSAGE);
                }
            }
        });
        regbnt.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //dispose();
                new RegFrame();
            }
        });

2.在聊天页面显示当前登录人账户

将注册页面的用于记录账户的标签传入登录页面,然后在登录页面调用setText方法

3.服务器端创建

public void startServer() {
        try {
            //创建服务器并监听客户端的连接
            ServerSocket serverSocket = new ServerSocket(9999);
            System.out.println("服务器启动成功!");
            while (true) {
                Socket socket = serverSocket.accept();
                arrayList.add(socket);
                System.out.println("客户端连接成功:" + arrayList.size());
                //为每一个连接到服务器端的Socket创建一个线程,让它独立的运行,不影响死循环监听客户端的连接
                new thread(socket).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("服务器启动失败!");
        }
    }

这里将accept写入死循环当中是因为,要持续监听是否有新的客户端,如果监听到了客户端就将他们加入arrayList中,arrayList当中每一个元素都Socket对象

4.客户端创建

在登录页面创建一个Socket对象,这样每打开一个注册页面都会创建一个客户端

//连接服务器端
Socket socket = new Socket("127.0.0.1", 9999);

5.为发送按钮添加事件

//为发送按钮创建事件
        button1.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String s = textArea1.getText();
                if(s.length()==0){
                    JOptionPane.showMessageDialog(null,"聊天内容不能为空");
                    return;
                }
                //发送聊天内容 发送人+时间+内容
                try {
                    s = account+" "+ DateUtil.DateUtil1(new Date())+"\n"+s+"\n";
                    dataOutputStream.writeUTF(s);//发送给了服务器端
                    textArea1.setText("");
                } catch (IOException ex) {
                    JOptionPane.showMessageDialog(null,"发送失败");
          }

     }
});

6.连接到服务器端的socket需要监听自己客户端有没有向服务器端发送消息,然后将消息转发给每一个客户端

这里必须将服务端监听消息写入线程中,其一是一个类中最多只能有一个死循环,其二,每一个连接到服务器端的客户端都需要被监听

//创建了一个线程类,一旦有客户端socket连接到服务器,把socket传入到一个线程中,在线程中独立的运行
    private class thread extends Thread {
        private DataInputStream dataInputStream;

        public thread(Socket socket) throws IOException {
            this.dataInputStream = new DataInputStream(socket.getInputStream());//服务器端接收
        }

        public void run() {
            try {
                FileWriter fileWriter = new FileWriter("C:/1javaSE/Chat.txt", false);
                BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
                while (true) {
                    try {
                        //这里保存着每一个客户端发送的记录,由服务器端作为中转站,将a客户端的消息转发给b,c 同理
                        String s = dataInputStream.readUTF();
                        System.out.println("服务器:" + s);
                        bufferedWriter.write(s);
                        bufferedWriter.flush();
                        //转发给其他客户端
                        for (Socket socket : arrayList) {//得到每一个socket对象,因为服务器与客户端是同一个socket对象
                            DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
                            dataOutputStream.writeUTF(s);
                        }
                    } catch (FileNotFoundException e) {
                        throw new RuntimeException(e);
                    } catch (IOException exception) {
                        exception.printStackTrace();
                    }
                }
            }catch(IOException ex){
                ex.printStackTrace();
            }
        }
}

7.客户端接收来自服务器端的消息

    public class thread1 extends Thread{
        boolean mark = true;
        public void run()
        {
            while(mark)
            {
                try {
                    String s = dataInputStream.readUTF();
                    System.out.println("客户端"+s);
                    textArea2.append(s);

                } catch (IOException e) {
                    mark = false;
                    throw new RuntimeException(e);
                }
            }
        }
    }

五.完整代码

1.注册/登录页面

public class LoginFrame extends JFrame {
    public LoginFrame() {
        initComponents();
    }

    private void initComponents() {
        // JFormDesigner - Component initialization - DO NOT MODIFY  //GEN-BEGIN:initComponents  @formatter:off
        panel5 = new JPanel();
        label2 = new JLabel();
        label3 = new JLabel();
        accountFiled = new JTextField();
        passwordFiled = new JTextField();
        loginbtn = new JButton();
        regbnt = new JButton();

        //======== this ========
        setTitle("Hello,World");
        setBackground(Color.black);
        Container contentPane = getContentPane();
        contentPane.setLayout(null);

        //======== panel5 ========
        {
            panel5.setBackground(new Color(0x666666));
            panel5.setLayout(null);

            //---- label2 ----
            label2.setText("\u8d26\u53f7:");
            label2.setFont(label2.getFont().deriveFont(Font.BOLD|Font.ITALIC, label2.getFont().getSize() + 4f));
            label2.setBackground(Color.gray);
            label2.setForeground(Color.white);
            panel5.add(label2);
            label2.setBounds(new Rectangle(new Point(95, 45), label2.getPreferredSize()));

            //---- label3 ----
            label3.setText("\u5bc6\u7801:");
            label3.setFont(label3.getFont().deriveFont(label3.getFont().getStyle() | Font.ITALIC, label3.getFont().getSize() + 4f));
            label3.setBackground(Color.gray);
            label3.setForeground(Color.white);
            panel5.add(label3);
            label3.setBounds(new Rectangle(new Point(95, 80), label3.getPreferredSize()));
            panel5.add(accountFiled);
            accountFiled.setBounds(140, 45, 135, accountFiled.getPreferredSize().height);
            panel5.add(passwordFiled);
            passwordFiled.setBounds(140, 80, 135, passwordFiled.getPreferredSize().height);

            //---- loginbtn ----
            loginbtn.setText("\u767b\u5f55");
            loginbtn.setForeground(new Color(0x666666));
            loginbtn.setBackground(new Color(0xcccccc));
            panel5.add(loginbtn);
            loginbtn.setBounds(new Rectangle(new Point(240, 145), loginbtn.getPreferredSize()));

            //---- regbnt ----
            regbnt.setText("\u6ce8\u518c");
            regbnt.setForeground(new Color(0x666666));
            regbnt.setBackground(new Color(0xcccccc));
            panel5.add(regbnt);
            regbnt.setBounds(new Rectangle(new Point(75, 145), regbnt.getPreferredSize()));
        }
        contentPane.add(panel5);
        panel5.setBounds(0, 0, 385, 275);

        contentPane.setPreferredSize(new Dimension(385, 240));
        pack();
        setLocationRelativeTo(getOwner());
        // JFormDesigner - End of component initialization  //GEN-END:initComponents  @formatter:on
        //按钮的事件处理程序 new 接口,是java中的一种简化的写法,创建了一个接口的匿名内部类对象
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setResizable(false);
        this.setVisible(true);//显示窗口,此行放在最后一行设置
        loginbtn.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {//事件监听
                try {
                    String account = accountFiled.getText();//获取文本框内容
                    String password = passwordFiled.getText();
                    if (password.equals("")) {
                        JOptionPane.showMessageDialog(null, "密码不能为空", "来自系统的提示", JOptionPane.WARNING_MESSAGE);
                        return;
                    }
                    if (account.equals("")) {
                        JOptionPane.showMessageDialog(null, "账户不能为空", "来自系统的提示", JOptionPane.WARNING_MESSAGE);
                        //(,内容,标题,警告类型);
                        return;
                    }
                    //连接数据库
                    //连接服务器端
                    Socket socket = new Socket("127.0.0.1", 9999);
                    dispose();//释放关闭当前窗口
                    new ChatFrame(accountFiled.getText(),socket).setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                }catch(IOException ex){
                    ex.printStackTrace();
                    JOptionPane.showMessageDialog(null,"网络连接失败!","来自系统的提示",JOptionPane.WARNING_MESSAGE);
                }catch(Exception ex){
                    ex.printStackTrace();//打印异常信息
                    JOptionPane.showMessageDialog(null,"系统忙,请稍后再试!","来自系统的提示",JOptionPane.WARNING_MESSAGE);
                }
            }
        });
        regbnt.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //dispose();
                new RegFrame();
            }
        });

    }

    // JFormDesigner - Variables declaration - DO NOT MODIFY  //GEN-BEGIN:variables  @formatter:off
    private JPanel panel5;
    private JLabel label2;
    private JLabel label3;
    private JTextField accountFiled;
    private JTextField passwordFiled;
    private JButton loginbtn;
    private JButton regbnt;
    // JFormDesigner - End of variables declaration  //GEN-END:variables  @formatter:on
    public static void main(String[] args) {
        LoginFrame loginFrame = new LoginFrame();
    }
}

2.聊天页面

public class ChatFrame extends JFrame {
    private String account;
    private DataOutputStream dataOutputStream;
    private DataInputStream dataInputStream;

    public ChatFrame(String account,Socket socket) {
        this.account = account;
        try {
            this.dataOutputStream = new DataOutputStream(socket.getOutputStream());
            this.dataInputStream = new DataInputStream(socket.getInputStream());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        initComponents();
    }

    private void initComponents() {
        // JFormDesigner - Component initialization - DO NOT MODIFY  //GEN-BEGIN:initComponents  @formatter:off
        scrollPane1 = new JScrollPane();
        textArea2 = new JTextArea();
        label1 = new JLabel();
        scrollPane2 = new JScrollPane();
        textArea1 = new JTextArea();
        button1 = new JButton();
        button2 = new JButton();
        label2 = new JLabel();

        //======== this ========
        setTitle("\u804a\u5929\u5ba4");
        Container contentPane = getContentPane();
        contentPane.setLayout(null);

        //======== scrollPane1 ========
        {
            scrollPane1.setEnabled(false);
            scrollPane1.setViewportView(textArea2);
        }
        contentPane.add(scrollPane1);
        scrollPane1.setBounds(0, 0, 490, 280);

        //---- label1 ----
        label1.setText("          \u597d\u53cb");
        contentPane.add(label1);
        label1.setBounds(490, 215, 110, 65);

        //======== scrollPane2 ========
        {
            scrollPane2.setViewportView(textArea1);
        }
        contentPane.add(scrollPane2);
        scrollPane2.setBounds(0, 280, 490, 120);

        //---- button1 ----
        button1.setText("\u53d1\u9001");
        contentPane.add(button1);
        button1.setBounds(490, 280, 110, 120);

        //---- button2 ----
        button2.setText("\u8fd4\u56de\u767b\u5f55\u9875\u9762");
        contentPane.add(button2);
        button2.setBounds(490, 0, 110, 90);

        //---- label2 ----
        label2.setText("\u7528\u6237\u4fe1\u606f:");
        contentPane.add(label2);
        label2.setBounds(490, 165, 110, 50);

        {
            // compute preferred size
            Dimension preferredSize = new Dimension();
            for(int i = 0; i < contentPane.getComponentCount(); i++) {
                Rectangle bounds = contentPane.getComponent(i).getBounds();
                preferredSize.width = Math.max(bounds.x + bounds.width, preferredSize.width);
                preferredSize.height = Math.max(bounds.y + bounds.height, preferredSize.height);
            }
            Insets insets = contentPane.getInsets();
            preferredSize.width += insets.right;
            preferredSize.height += insets.bottom;
            contentPane.setMinimumSize(preferredSize);
            contentPane.setPreferredSize(preferredSize);
        }
        pack();
        setLocationRelativeTo(getOwner());
        // JFormDesigner - End of component initialization  //GEN-END:initComponents  @formatter:on
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setResizable(false);
        this.setVisible(true);//显示窗口,此行放在最后一行设置
        label1.setText(account);

        new thread1().start();//你把开启线程写到 发送按钮里面了

        //为发送按钮创建事件
        button1.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String s = textArea1.getText();
                if(s.length()==0){
                    JOptionPane.showMessageDialog(null,"聊天内容不能为空");
                    return;
                }
                //发送聊天内容 发送人+时间+内容
                try {
                    s = account+" "+ DateUtil.DateUtil1(new Date())+"\n"+s+"\n";
                    dataOutputStream.writeUTF(s);//发送给了服务器端
                    textArea1.setText("");
                } catch (IOException ex) {
                    JOptionPane.showMessageDialog(null,"发送失败");
                }

            }
        });
        button2.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                dispose();//关闭页面
                new LoginFrame();
            }
        });
        //来到聊天窗口后,就会随时有别的客户端发送信息,在聊天窗口中,循环监听来自服务器端发送的消息
        //因为窗口不能和监听同时进行,我们需要加一个内部类线程监听
    }

    // JFormDesigner - Variables declaration - DO NOT MODIFY  //GEN-BEGIN:variables  @formatter:off
    private JScrollPane scrollPane1;
    private JTextArea textArea2;
    private JLabel label1;
    private JScrollPane scrollPane2;
    private JTextArea textArea1;
    private JButton button1;
    private JButton button2;
    private JLabel label2;
    // JFormDesigner - End of variables declaration  //GEN-END:variables  @formatter:on
    public class thread1 extends Thread{
        boolean mark = true;
        public void run()
        {
            while(mark)
            {
                try {
                    String s = dataInputStream.readUTF();
                    System.out.println("客户端"+s);
                    textArea2.append(s);

                } catch (IOException e) {
                    mark = false;
                    throw new RuntimeException(e);
                }
            }
        }
    }

}

3.客户端页面

public class ServerJFrame extends JFrame {
    public Server server;

    //创建一个客户端用来监听
    //public Socket socket;
    //public ServerJFrame(Socket socket){
    //    this.socket = socket;
    //}
    public ServerJFrame() throws IOException {
        try {
            initComponents();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void initComponents() throws IOException {
        // JFormDesigner - Component initialization - DO NOT MODIFY  //GEN-BEGIN:initComponents  @formatter:off
        label1 = new JLabel();
        textField1 = new JTextField();
        scrollPane1 = new JScrollPane();
        textArea1 = new JTextArea();
        button1 = new JButton();
        textField2 = new JTextField();
        button2 = new JButton();
        button3 = new JButton();

        //======== this ========
        setTitle("\u670d\u52a1\u5668\u7a97\u53e3");
        Container contentPane = getContentPane();
        contentPane.setLayout(null);

        //---- label1 ----
        label1.setText("\u5728\u7ebf\u4eba\u6570:");
        contentPane.add(label1);
        label1.setBounds(new Rectangle(new Point(35, 20), label1.getPreferredSize()));
        contentPane.add(textField1);
        textField1.setBounds(30, 50, 235, 70);

        //======== scrollPane1 ========
        {
            scrollPane1.setViewportView(textArea1);
        }
        contentPane.add(scrollPane1);
        scrollPane1.setBounds(30, 130, 300, 200);

        //---- button1 ----
        button1.setText("\u53d1\u9001\u516c\u544a");
        contentPane.add(button1);
        button1.setBounds(305, 65, button1.getPreferredSize().width, 40);
        contentPane.add(textField2);
        textField2.setBounds(95, 15, 155, 25);

        //---- button2 ----
        button2.setText("\u66f4\u65b0\u4eba\u6570");
        contentPane.add(button2);
        button2.setBounds(305, 10, 85, 40);

        //---- button3 ----
        button3.setText("\u670d\u52a1\u7aef\u67e5\u8be2");
        contentPane.add(button3);
        button3.setBounds(335, 245, button3.getPreferredSize().width, 80);

        contentPane.setPreferredSize(new Dimension(445, 380));
        pack();
        setLocationRelativeTo(getOwner());
        // JFormDesigner - End of component initialization  //GEN-END:initComponents  @formatter:on
        //显示在线人数
        button1.addActionListener(new AbstractAction() {
            //从服务器端发送一个公告到各个客户端
            @Override
            public void actionPerformed(ActionEvent e) {
                String s = "来自服务器端发布的通告:" + textField1.getText() + "\n";
                textField1.setText("");
                if (s.length() == 0) {
                    JOptionPane.showMessageDialog(null, "聊天内容不能为空");
                    return;
                }
                for (Socket socket : server.arrayList) {
                    try {
                        //向客户端发送通告
                        DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
                        dataOutputStream.writeUTF(s);
                    } catch (IOException ex) {
                        throw new RuntimeException(ex);
                    }
                }
            }
        });
        //启动聊天后天监视
        //new thread1().start();
        button2.addActionListener((new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                new thread().start();
            }
        }));
        button3.addActionListener(new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                textArea1.setText("");
                new thread1().start();
            }
        });
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setResizable(false);
        this.setVisible(true);//显示窗口,此行放在最后一行设置
        //在文本框中显示聊天内容
    }

    class thread extends Thread {
        public void run() {
            while (true) {
                textField2.setText("   " + String.valueOf(server.arrayList.size()) + "   ");
            }
        }
    }
    class thread1 extends Thread{
        public void run(){
            try {
                FileReader fileReader = new FileReader("C:/1javaSE/Chat.txt");
                BufferedReader bufferedReader = new BufferedReader(fileReader);
                while(bufferedReader.readLine()!=null){
                    String line = bufferedReader.readLine();
                    textArea1.append(line+"\n");
                }
            }catch(IOException exception){
                exception.printStackTrace();
            }
        }
    }

        // JFormDesigner - Variables declaration - DO NOT MODIFY  //GEN-BEGIN:variables  @formatter:off
        private JLabel label1;
        private JTextField textField1;
        private JScrollPane scrollPane1;
        private JTextArea textArea1;
        private JButton button1;
        private JTextField textField2;
        private JButton button2;
        private JButton button3;
    // JFormDesigner - End of variables declaration  //GEN-END:variables  @formatter:on
    public static void main(String[] args) throws IOException {
        ServerJFrame serverJFrame = null;
        serverJFrame = new ServerJFrame();
        serverJFrame.server = new Server();
        serverJFrame.server.startServer();

    }
}

4.客户端

public class Server {
    //存储连接到服务器端的多个客户端对象
    public ArrayList<Socket> arrayList = new ArrayList<>();

    public void startServer() {
        try {
            //创建服务器并监听客户端的连接
            ServerSocket serverSocket = new ServerSocket(9999);
            System.out.println("服务器启动成功!");
            while (true) {
                Socket socket = serverSocket.accept();
                arrayList.add(socket);
                System.out.println("客户端连接成功:" + arrayList.size());
                //为每一个连接到服务器端的Socket创建一个线程,让它独立的运行,不影响死循环监听客户端的连接
                new thread(socket).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("服务器启动失败!");
        }
    }
    //创建了一个线程类,一旦有客户端socket连接到服务器,把socket传入到一个线程中,在线程中独立的运行
    private class thread extends Thread {
        private DataInputStream dataInputStream;

        public thread(Socket socket) throws IOException {
            this.dataInputStream = new DataInputStream(socket.getInputStream());//服务器端接收
        }

        public void run() {
            try {
                FileWriter fileWriter = new FileWriter("C:/1javaSE/Chat.txt", false);
                BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
                while (true) {
                    try {
                        //这里保存着每一个客户端发送的记录,由服务器端作为中转站,将a客户端的消息转发给b,c 同理
                        String s = dataInputStream.readUTF();
                        System.out.println("服务器:" + s);
                        bufferedWriter.write(s);
                        bufferedWriter.flush();
                        //转发给其他客户端
                        for (Socket socket : arrayList) {//得到每一个socket对象,因为服务器与客户端是同一个socket对象
                            DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
                            dataOutputStream.writeUTF(s);
                        }
                    } catch (FileNotFoundException e) {
                        throw new RuntimeException(e);
                    } catch (IOException exception) {
                        exception.printStackTrace();
                    }
                }
            }catch(IOException ex){
                ex.printStackTrace();
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值