基于JavaGUI设计的聊天室

2023-12-28 14:26:55

基于JavaGUI设计的聊天室

写这篇博客的目的是为了更好的帮助广大学子完成相关课程上的需求。如有需求可以在评论区留言或者私信(附加课设报告)

一:系统设计图

在这里插入图片描述

二:展示程序运行初始效果图

登陆注册页面

在这里插入图片描述

共享聊天室页面

在这里插入图片描述

私聊页面

在这里插入图片描述

三:相关细节代码展示

1.登陆页面GUI设计
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.Random;

public class LoginPageSwing extends JFrame {
    private JTextField usernameField;       //用户名
    private JPasswordField passwordField;   //密码
    private static String Rusername;        //当前线程的用户名传出去
    private JTextField captchaField;        //显示验证码文字框
    private JLabel captchaLabel;            //显示验证码图片
    private String generatedCaptcha;        //生成验证码

    public LoginPageSwing() {
        // 设置窗口标题
        super("Login Page");

        // 设置字体
        Font labelFont = new Font("Arial", Font.PLAIN, 14);
        Font fieldFont = new Font("Arial", Font.PLAIN, 12);

        // 创建文本框和密码框
        usernameField = new JTextField(20);
        passwordField = new JPasswordField(20);

        //创建验证码控件
        captchaField = new JTextField(10);
       captchaLabel = new JLabel();

        // 创建标签
        JLabel usernameLabel = new JLabel("Username:");
        usernameLabel.setFont(labelFont);
        JLabel passwordLabel = new JLabel("Password:");
        passwordLabel.setFont(labelFont);
        JLabel captchaInputLabel = new JLabel("验证码");

        // 创建按钮
        JButton loginButton = new JButton("Login");
        loginButton.setFont(labelFont);

        JButton registerButton = new JButton("Register");
        registerButton.setFont(labelFont);

        // 设置按钮事件处理
        loginButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
               login();
            }
        });

        registerButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
               openRegistrationPage();
            }
        });

        // 创建面板,并设置布局管理器为网格布局
        JPanel panel = new JPanel(new GridLayout(5, 2, 10, 10));
        panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); // 设置面板边距
        panel.add(usernameLabel);
        panel.add(usernameField);
        panel.add(passwordLabel);
        panel.add(passwordField);
        panel.add(loginButton);
        panel.add(registerButton);
        panel.add(captchaInputLabel);
        panel.add(captchaField);
       // panel.add(captchaLabel);
      //  panel.add(new JPanel()); // 空白占位,使布局整齐
        // 设置布局管理器为边界布局
        setLayout(new BorderLayout());
        // 添加面板到窗口中央
        add(panel, BorderLayout.CENTER);

        generatedCaptcha = generateCaptcha();
        updateCaptchaImage();
        // 包装captchaLabel,并使用FlowLayout来实现底部居中
        JPanel captchaPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
        captchaPanel.add(captchaLabel);
        add(captchaPanel, BorderLayout.SOUTH);
        // 设置窗口大小和关闭操作
        setSize(400, 350);
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        setLocationRelativeTo(null); // 将窗口置于屏幕中央
        setVisible(true);
    }

    private String generateCaptcha() {
        Random random = new Random();
        int captcha = 1000 + random.nextInt(9000);
        return String.valueOf(captcha);
    }

    private void updateCaptchaImage() {
        int width = 120;
        int height = 30;

        BufferedImage captchaImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = captchaImage.createGraphics();

        // 设置验证码图片的背景和边框
        g2d.setColor(Color.WHITE);
        g2d.fillRect(0, 0, width, height);
        g2d.setColor(Color.BLACK);
        g2d.drawRect(0, 0, width - 1, height - 1);

        // 设置验证码文本
        g2d.setFont(new Font("Arial", Font.BOLD, 18));
        g2d.setColor(Color.BLACK);
        g2d.drawString(generatedCaptcha, 30, 20);

        g2d.dispose();

        // 将验证码图片显示在标签上
        ImageIcon icon = new ImageIcon(captchaImage);
        captchaLabel.setIcon(icon);
    }

    private void login() {
        String username = usernameField.getText();
        char[] passwordChars = passwordField.getPassword();
        String password = new String(passwordChars);

        // 与数据库匹配
        boolean userExists = false;
        User user = CRUD.select(username, password);
        if (user != null) {
            String enteredCaptcha = captchaField.getText();
            if (!enteredCaptcha.equals(generatedCaptcha)) {
                JOptionPane.showMessageDialog(this, "Invalid captcha. Please try again.");
                generatedCaptcha = generateCaptcha();
                updateCaptchaImage();
                return;
            }
            else if (user.getUsername().equals(username) && user.getPasswd().equals(password) && user.getIsfalse()==0) {
                userExists = true;
                System.out.println("登陆成功");
                CRUD.update(1,user.getUsername());
                Rusername = user.getUsername();
            }else if (user.getIsfalse() == 1){
                JOptionPane.showMessageDialog(this, "账户已经登陆,无法重复登陆");
            }
        }

        if (userExists) {
            JOptionPane.showMessageDialog(this, "Login successful!");
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    //群聊的话可能在这里更改代码
                    new QQChatPageSwing();
                    dispose();
                }
            });

        } else {
            JOptionPane.showMessageDialog(this, "Login failed. Please check your username and password.");
        }

    }

    private void openRegistrationPage() {
        // 在这里打开注册页面
        RegistrationPageSwing registrationPage = new RegistrationPageSwing();
        registrationPage.setLocationRelativeTo(this); // 让注册页面相对于登录页面居中显示
    }

    public static String username(){
        return Rusername;
    }
    public static void main(String[] args) {


        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new LoginPageSwing();
            }
        });
    }
}

登陆页面和注册页面几乎差不多,不过多阐述。其中输入密码也是加密的方式,不会显示,按钮的点击效果会通过数据库索引来查询结果。

客户端细节代码

private void connectToServer() {
    try {
        socket = new Socket("localhost", 9000);
        //写入消息实体类,方便服务器处理
        os = new ObjectOutputStream(socket.getOutputStream());
        is = new ObjectInputStream(socket.getInputStream());
        os.writeObject(new Message(username, "online", "登陆成功", 0, 0));
    } catch (IOException e) {
        e.printStackTrace();
        JOptionPane.showMessageDialog(this, "Unable to connect to the server.", "Error", JOptionPane.ERROR_MESSAGE);
        System.exit(1);
    }
}

//线程监听服务器发的消息
private void startListening() {
    new Thread(() -> {
        try {
            while (true) {
                Message message = (Message) is.readObject();
                if ((message.getContent()) == null) {
                    break; // 结束循环
                }
                handleServerResponse(message);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        if (socket == null) {
            try {
                is.close();
                os.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }).start();
}

这里展示的部分客户端代码是实现与服务器交互逻辑,聊天室的实现一定会使用到多线程,所以不免会出现线程同步等一系列问题。主要逻辑就是客户端的消息都发给服务器,然后服务器解析之后再转发。其中消息也是封装在一个实体类中,方便操作。

服务器端细节代码

public static void main(String[] args) {
    try {
        ServerSocket serverSocket = new ServerSocket(PORT);
        System.out.println("Server listening on port " + PORT);
        while (true) {
            Socket clientSocket = serverSocket.accept();
            System.out.println("New client connected: " + clientSocket);
            ObjectOutputStream oos = new ObjectOutputStream(clientSocket.getOutputStream());
            ObjectInputStream ois = new ObjectInputStream(clientSocket.getInputStream());
            clientSockets.put(clientSocket, oos);
            ClientHandler clientHandler = new ClientHandler(clientSocket, oos, ois);
            Thread thread = new Thread(clientHandler);
            thread.start();
        }
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

//线程处理消息
private static class ClientHandler implements Runnable {
    private Socket clientSocket;
    private ObjectInputStream ois;
    private ObjectOutputStream oos;

    public ClientHandler(Socket clientSocket, ObjectOutputStream oos, ObjectInputStream ois) throws IOException, ClassNotFoundException {
        this.clientSocket = clientSocket;
        this.oos = oos;
        this.ois = ois;
    }

    @Override
    public void run() {
        while (true) {
            Message message = null;
            //接受每一条Message
            try {
                message = (Message) ois.readObject();
                //处理Message
                handleClientMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            if (clientSocket == null) {
                // 关闭资源
                try {
                    oos.close();
                    ois.close();
                    clientSocket.close();
                    break;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

每一个客户端都是一个子线程,与之对应的是服务器这边也要开启线程进行管理,其中我是每个子页面都是一个线程。

四:运行效果图

共享聊天室运行结果,唯一的遗憾是在线用户列表不能实现同步功能

在这里插入图片描述

私聊聊天室展示

这里我从277的客户端点击在线列表中的dai,就能进入私聊页面,并且消息不会在共享页面中显示。

在这里插入图片描述## 以上就是程序展示效果,如有需要请在评论区留言,或者私信。

文章来源:https://blog.csdn.net/yi_qiu_/article/details/135253960
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。