chat1.0

多人聊天室

功能设计

一、服务器端
  1. 启动服务器端,打开服务器端窗口
  2. 创建ServerSocket,循环监听客户端连接
  3. 存储连接到服务器端的多个Socket
  4. 接收客户端发送的信息(接收线程)
  5. 将接收到的消息转发给所有的客户端socket
  6. 在服务器窗口显示所有客户端发送的消息
  7. 关闭服务器
二、客户端
  1. 打开登录窗口,可以登录和注册
  2. 注册需要先判断账号密码是否规则,在验证账号是否已被注册,注册成功后返回登录窗口并在数据库用户表中插入用户信息
  3. 登录时与数据库连接比对账号密码
  4. 信息验证通过后,创建客户端Socket连接服务器
  5. 连接到服务器后,关闭登录窗口,打开聊天窗口
  6. 输入聊天信息(验证),发送聊天信息
  7. 客户端接收服务器发送过来的聊天(接收线程)
  8. 关闭客户端

流程图

在这里插入图片描述

具体设计

客户端
登录窗口
package frame;

import dao.LoginDao;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.Socket;

/**
 * 登录窗口
 *
 * @author Deevan
 */
public class LoginFrame extends JFrame {

    /**
     * 创建登录窗口
     */
    public void creatFrame() {
        //窗口设置
        this.setSize(500, 300);
        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("欢迎来到聊天室");
        this.setResizable(false);
        this.setIconImage(new ImageIcon("").getImage());

        //创建主面板
        JPanel jPanel = new JPanel(new GridLayout(4, 1));

        JPanel welcomePanel = new JPanel();
        JLabel welcomeLabel = new JLabel("欢迎登录");
        welcomeLabel.setFont(new Font("楷体", Font.BOLD, 25));
        welcomePanel.add(welcomeLabel);

        JPanel accountPanel = new JPanel();
        JLabel accountLabel = new JLabel("账号");
        JTextField accountTextField = new JTextField(20);
        accountPanel.add(accountLabel);
        accountPanel.add(accountTextField);

        JPanel passwordPanel = new JPanel();
        JLabel pswLabel = new JLabel("密码");
        JPasswordField pswField = new JPasswordField(20);
        passwordPanel.add(pswLabel);
        passwordPanel.add(pswField);

        JPanel btnPanel = new JPanel();
        JButton loginBtn = new JButton("登入");
        JButton registerBtn = new JButton("注册");
        btnPanel.add(loginBtn);
        btnPanel.add(registerBtn);

        //添加4个面板到主面板
        jPanel.add(welcomePanel);
        jPanel.add(accountPanel);
        jPanel.add(passwordPanel);
        jPanel.add(btnPanel);

        //监听登录按钮
        loginBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    //获取账号框和密码框信息
                    String account = accountTextField.getText();
                    String password = new String(pswField.getPassword());

                    //弹框提示账户密码为空
                    if (account.length() == 0) {
                        JOptionPane.showMessageDialog(null, "请输入账号", "操作提示", JOptionPane.WARNING_MESSAGE);
                        return;
                    }
                    if (password.length() == 0) {
                        JOptionPane.showMessageDialog(null, "请输入密码", "操作提示", JOptionPane.WARNING_MESSAGE);
                        return;
                    }

                    //与数据交互,验证账号密码是否正确
                    LoginDao loginDao = new LoginDao();
                    int res = loginDao.login(account, password);
                    System.out.println(res);
                    if (res == 0) {
                        JOptionPane.showMessageDialog(null, "账号或密码错误", "操作提示", JOptionPane.WARNING_MESSAGE);
                        return;
                    }

                    //登录成功,创建Socket,打开聊天窗口,释放登录窗口
                    Socket socket = new Socket("192.168.1.14", 7777);

                    new ChatFrame(socket, account).creatFrame();
                    dispose();
                } catch (Exception exception) {
                    exception.printStackTrace();
                    JOptionPane.showMessageDialog(null, "服务器连接失败", "操作提示", JOptionPane.WARNING_MESSAGE);//弹窗提示
                }

            }
        });

        //监听注册按钮
        registerBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //打开注册窗口,释放登录窗口
                new RegFrame().creatFrame();
                dispose();
            }
        });

        this.add(jPanel);
        this.setVisible(true);
    }
}
注册窗口
package frame;

import dao.RegDao;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * 注册窗口
 *
 * @author Deevan
 */
public class RegFrame extends JFrame {
    public void creatFrame() {
        //窗口设置
        this.setSize(600, 400);
        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("请注册你的信息");
        this.setResizable(false);
        this.setIconImage(new ImageIcon("").getImage());


        JPanel jPanel = new JPanel(new GridLayout(4, 1));

        JPanel welcomePanel = new JPanel();
        JLabel welcomeLabel = new JLabel("账号注册");
        welcomeLabel.setFont(new Font("楷体", Font.BOLD, 25));
        welcomePanel.add(welcomeLabel);

        JPanel accountPanel = new JPanel();
        JLabel accountLabel = new JLabel("账号");
        JTextField accountTextField = new JTextField(20);
        accountPanel.add(accountLabel);
        accountPanel.add(accountTextField);

        JPanel passwordPanel = new JPanel();
        JLabel pswLabel = new JLabel("密码");
        JPasswordField pswField = new JPasswordField(20);
        passwordPanel.add(pswLabel);
        passwordPanel.add(pswField);

        JPanel btnPanel = new JPanel();
        JButton okBtn = new JButton("确定");
        JButton backBtn = new JButton("返回");
        btnPanel.add(okBtn);
        btnPanel.add(backBtn);

        jPanel.add(welcomePanel);
        jPanel.add(accountPanel);
        jPanel.add(passwordPanel);
        jPanel.add(btnPanel);

        //监听确定按钮
        okBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {

                try {
                    String account = accountTextField.getText();
                    String password = new String(pswField.getPassword());

                    if (account.length() == 0) {
                        JOptionPane.showMessageDialog(null, "账号不能为空", "操作提示", JOptionPane.WARNING_MESSAGE);
                        return;
                    }
                    if (password.length() == 0) {
                        JOptionPane.showMessageDialog(null, "密码不能为空", "操作提示", JOptionPane.WARNING_MESSAGE);
                        return;
                    }

                    //与数据交互,验证账号是否重复
                    int result = new RegDao().repeatVerification(account);
                    if (result == 1) {  //重复
                        JOptionPane.showMessageDialog(null, "账号已被注册", "操作提示", JOptionPane.WARNING_MESSAGE);
                    }
                    if (result == 0) {  //不重复
                        //注册完成,保存用户信息
                        RegDao regDao = new RegDao();
                        regDao.saveInformation(account, password);
                        JOptionPane.showMessageDialog(null, "账号注册成功", "操作提示", JOptionPane.WARNING_MESSAGE);
                        //返回登录界面
                        new LoginFrame().creatFrame();
                        dispose();
                    }
                } catch (Exception exception) {
                    exception.printStackTrace();
                    JOptionPane.showMessageDialog(null, "注册失败", "操作提示", JOptionPane.WARNING_MESSAGE);//弹窗提示
                }

            }
        });

        //监听返回按钮
        backBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //打开登录界面,释放此界面
                new LoginFrame().creatFrame();
                dispose();
            }
        });

        this.add(jPanel);
        this.setVisible(true);
    }
}

聊天窗口
package frame;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Date;

/**
 * 客户端聊天窗口
 *
 * @author Deevan
 */

public class ChatFrame extends JFrame {

    Socket socket;
    String account;
    DataOutputStream dataOutputStream;
    DataInputStream dataInputStream;
    JTextArea jTextArea;


    public ChatFrame(Socket socket, String account) throws HeadlessException, IOException {
        //初始化变量
        this.socket = socket;
        this.account = account;
        this.dataOutputStream = new DataOutputStream(socket.getOutputStream());
        this.dataInputStream = new DataInputStream(socket.getInputStream());
    }

    public void creatFrame() {
        this.setSize(600, 600);
        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle(account);
        this.setResizable(false);
        this.setIconImage(new ImageIcon("").getImage());

        JPanel jPanel = new JPanel(new BorderLayout());  //边界布局

        //显示聊天记录
        jTextArea = new JTextArea();
        jTextArea.setEditable(false);
        JScrollPane jScrollPane = new JScrollPane(jTextArea);
        jPanel.add(jScrollPane);

        //发送框输入和发送
        JPanel inputPanel = new JPanel();
        JTextField inputTextField = new JTextField(40);
        JButton sendBtn = new JButton("发送");
        inputPanel.add(inputTextField);
        inputPanel.add(sendBtn);

        jPanel.add(inputPanel, BorderLayout.SOUTH); //下边显示


        this.add(jPanel);
        this.setVisible(true);

        //窗口添加事件监听
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                int res = JOptionPane.showConfirmDialog(null, "您确定要退出聊天室吗?", "操作提示", JOptionPane.OK_CANCEL_OPTION);
                if (res == 0) {
                    try {
                        socket.close();
                        dispose();//释放聊天窗口
                        new LoginFrame().creatFrame();//打开登录窗口
                    } catch (IOException ioException) {
                        ioException.printStackTrace();
                    }
                }
            }
        });

        //进入到聊天窗口同时开启线程来接收服务器发来的数据
        new ClientThread().start();

        //发送信息到服务器
        //监听发送按钮
        sendBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //获取发送框输入的信息加以判断
                String inputMsg = inputTextField.getText();
                if (inputMsg.length() == 0) {
                    JOptionPane.showMessageDialog(null, "发送内容不能为空", "操作提示", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                if (inputMsg.length() > 200) {
                    JOptionPane.showMessageDialog(null, "发送内容不能超过200字", "操作提示", JOptionPane.WARNING_MESSAGE);
                    return;
                }
                try {
                    //规范发送到服务器的信息内容:获取账号名称.时间.内容并添加到输出信息sendMessage
                    String sendMsg = account + "\t" + new Date().toLocaleString() + "\n" + inputMsg + "\n";
                    dataOutputStream.writeUTF(sendMsg);     //发送
                    inputTextField.setText(""); //重置发送框让其为空
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                }
            }
        });

    }


    /**
     * 创建线程监听服务器发来的信息
     * 接收消息需要一直监听服务器
     */
    class ClientThread extends Thread {
        @Override
        public void run() {
            boolean flag = true;
            while (flag) {
                try {
                    String acceptMsg = dataInputStream.readUTF();
                    //聊天框显示读的信息
                    jTextArea.append(acceptMsg);
                } catch (IOException e) {
                    e.printStackTrace();
                    flag = false;//服务器关闭  循环终止
                    //用户提示
                    JOptionPane.showMessageDialog(null, "服务器连接失败", "操作提示", JOptionPane.WARNING_MESSAGE);
                    dispose();//释放聊天窗口
                    new LoginFrame().creatFrame();//打开登录
                }
            }
        }
    }

}
注册访问数据库交互类
package dao;

import java.sql.*;

/**
 * 注册访问数据库交互类
 *
 * @author Deevan
 */
public class RegDao {
    /**
     * 验证账号id是否重复
     *
     * @param account 账号
     * @return result
     */
    public int repeatVerification(String account) throws ClassNotFoundException, SQLException {
        //创建传输sql的Connection管道
        Connection conn = null;
        //创建用来封装发送sql的PreparedStatement
        PreparedStatement ps = null;
        //记录比对结果,0为不重复,1为重复
        int result = 0;

        try {
            //加载mysql驱动,连接数据库chat_db
            Class.forName("com.mysql.cj.jdbc.Driver");
            String url = "jdbc:mysql://127.0.0.1:3306/chat_db?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai";
            conn = DriverManager.getConnection(url, "root", "******");
            ps = conn.prepareStatement("SELECT\n" +
                    "  COUNT(account) COUNT\n" +
                    "FROM\n" +
                    "  USER\n" +
                    "WHERE account = ?");

            ps.setObject(1, account);
            ResultSet res = ps.executeQuery();

            if (res.next()) {
                //result接收查询到数据的行数,所以查到了返回1,即为重复
                result = res.getInt("count");
            }
        } finally {
            if (ps != null) {
                ps.close();
            }
            if (conn != null) {
                conn.close();
            }
        }
        //返回查询结果
        return result;
    }


    /**
     * 保存用户信息
     *
     * @param account  账号
     * @param password 密码
     */
    public void saveInformation(String account, String password) throws SQLException, ClassNotFoundException {
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            String url = "jdbc:mysql://127.0.0.1:3306/chat_db?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai";
            conn = DriverManager.getConnection(url, "root", "152475");
            //在数据库chat_db中保存用户信息
            ps = conn.prepareStatement("INSERT INTO USER (account, PASSWORD, reg_time)\n" +
                    "VALUES\n" +
                    "  (?, ?, NOW ())");
            ps.setString(1, account);
            ps.setString(2, password);
            ps.executeUpdate();
        } finally {
            if (ps != null) {
                ps.close();
            }
            if (conn != null) {
                conn.close();
            }
        }
    }
}

登录访问数据库交互类
package dao;

import java.sql.*;

/**
 * 登录访问数据库交互类
 *
 * @author Deevan
 */
public class LoginDao {
    /**
     * 验证输入的账号密码是否存在与数据库当中
     *
     * @param account  账号
     * @param password 密码
     * @return result
     */
    public int login(String account, String password) throws ClassNotFoundException, SQLException {
        Connection conn = null;
        PreparedStatement ps = null;
        //用来记录查询到的行数,0就是没查到即不存在,1就是存在
        int result = 0;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            String url = "jdbc:mysql://127.0.0.1:3306/chat_db?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai";
            conn = DriverManager.getConnection(url, "root", "******");
            ps = conn.prepareStatement(" SELECT\n" +
                    "  COUNT(*) COUNT\n" +
                    "FROM\n" +
                    "  USER\n" +
                    "WHERE account = ?\n" +
                    "  AND PASSWORD = ?");
            ps.setString(1, account);
            ps.setString(2, password);
            ResultSet res = ps.executeQuery();
            if (res.next()) {
                result = res.getInt("count");
            }
        } finally {
            if (ps != null) {
                ps.close();
            }
            if (conn != null) {
                conn.close();
            }
        }
        //返回验证结果
        return result;
    }
}

启动
package frame;

/**
 * 客户端启动
 *
 * @author Deevan
 */
public class ClientRun {
    public static void main(String[] args) {
        //启动登录窗口
        new LoginFrame().creatFrame();
    }
}

服务器
import javax.swing.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * 服务器窗口
 *
 * @author Deevan
 */
public class ServerFrame extends JFrame {
    /**
     * 创建一个用来存放每一个客户端使用的socket的集合
     */
    ArrayList<Socket> sockets = new ArrayList<>();
    ServerSocket serverSocket;
    JTextArea jTextArea;

    public void creatFrame() {
        this.setSize(400, 600);
        this.setTitle("欢迎来到FJZ聊天室");
        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setResizable(false);
        this.setVisible(true);

        jTextArea = new JTextArea();
        jTextArea.setEditable(false);
        JScrollPane jScrollPane = new JScrollPane(jTextArea);
        this.add(jScrollPane);
        this.setVisible(true);

        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                try {
                    serverSocket.close();
                    System.exit(0);
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                }
            }
        });
    }

    public void startServer() {
        try {
            serverSocket = new ServerSocket(7777);

            //循环监听客户端连接信息
            int count = 0;
            while (true) {
                Socket socket = serverSocket.accept();
                count++;
                System.out.println("第" + count + "个客户端已连接");
                sockets.add(socket);
                new ServerThread(socket).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
            this.dispose();
            JOptionPane.showMessageDialog(null, "服务器启动失败", "操作提示", JOptionPane.WARNING_MESSAGE);
        }
    }

    class ServerThread extends Thread {
        Socket clientSocket;
        DataInputStream dataInputStream;

        public ServerThread(Socket clientSocket) throws IOException {
            this.clientSocket = clientSocket;
            this.dataInputStream = new DataInputStream(clientSocket.getInputStream());
        }

        @Override
        public void run() {
            //监听客户端发送的消息
            boolean flag = true;
            while (flag) {
                try {
                    //用msg读取接收到的信息并显示
                    String msg = dataInputStream.readUTF();
                    jTextArea.append(msg);

                    //将接收到的信息发送给其他的客户端
                    Iterator<Socket> socketIterator = sockets.iterator();   //创建一个放socket的集合socketIterator
                    while (socketIterator.hasNext()) {
                        Socket s = socketIterator.next();   //遍历存放所有客户端Socket的集合
                        if (s.isClosed()) {              //去除已经下线的客户端
                            socketIterator.remove();
                            continue;
                        }
                        //通过相应的Socket获得输出流对象
                        DataOutputStream dataOutputStream = new DataOutputStream(s.getOutputStream());
                        dataOutputStream.writeUTF(msg);       //把刚刚接收到的信息msg发送到遍历筛选过后的客户端
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                    flag = false;

                    sockets.remove(clientSocket);   //删除下线的客户端
                    System.out.println("客户端已下线");
                }
            }
        }
    }
}
/**
 * 启动服务器
 *
 * @author Deevan
 */
public class ServerRun {

    public static void main(String[] args) {
        ServerFrame serverFrame = new ServerFrame();
        serverFrame.creatFrame();
        serverFrame.startServer();
    }
}
数据库
CREATE DATABASE IF NOT EXISTS chat_db;

CREATE TABLE USER(
	id INT PRIMARY KEY AUTO_INCREMENT,
	account CHAR(12) NOT NULL ,
	PASSWORD CHAR(16) NOT NULL,
	reg_time DATETIME NOT NULL
	);
	
	

-- 验证账号是否重复
SELECT
  COUNT(account) COUNT
FROM
  USER
WHERE account = ?

-- 注册插入数据
INSERT INTO USER (account, PASSWORD, reg_time)
VALUES
  (?, ?, NOW ())

-- 登录是比对账号密码
 SELECT
  COUNT(*) COUNT
FROM
  USER
WHERE account = ?
  AND PASSWORD = ?
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EnndmeRedis

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值