基于JavaGUI实现多人聊天室

多人聊天室
          多人聊天室需要从客户端和服务器端两个方面着手来实现
客户端
    客户端分为登录界面,聊天界面

登录界面
package com.ffyc.chatRoom;
 
import java.awt.*;
 
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.Socket;
import java.util.regex.Pattern;
public class LoginFrame extends JFrame {
    public  LoginFrame() throws HeadlessException{
        this.setSize(600,400);//设置窗体的高和宽
        this.setLocationRelativeTo(null); //设置窗体水平垂直居中
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置窗体关闭后程序结束
 
        this.setTitle("欢迎登录!");
 
        JPanel jPanel = new JPanel(new GridLayout(4,1));
 
        JPanel welcomePanel = new JPanel(new FlowLayout());
        JLabel welcomeLabel = new JLabel("欢迎登录!");
        welcomeLabel.setFont(new Font("宋体",Font.BOLD,35));
        welcomeLabel.setForeground(new Color(7, 255, 224));
        welcomePanel.add(welcomeLabel);
 
        JPanel accountPanel = new JPanel(new FlowLayout());
        JLabel accountLabel = new JLabel("账号:");
        accountLabel.setFont(new Font("宋体",Font.BOLD,25));
        accountLabel.setForeground(new Color(248, 3, 3));
 
        JTextField accountTextField = new JTextField(15);
        accountPanel.add(accountLabel);
        accountPanel.add(accountTextField);
 
        JPanel passwordPanel = new JPanel(new FlowLayout());
        JLabel passwordLable = new JLabel("密码:");
        passwordLable.setFont(new Font("宋体",Font.BOLD,25));
        passwordLable.setForeground(new Color(255, 3, 3));
 
        JPasswordField passwordField = new JPasswordField(15);
 
        passwordPanel.add(passwordLable);
        passwordPanel.add(passwordField);
 
 
        JPanel buttonPanel = new JPanel(new FlowLayout());
        JButton loginButton = new JButton("登录");
        JButton regButton = new JButton("注册");
 
        buttonPanel.add(loginButton);
        buttonPanel.add(regButton);
 
        loginButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String account = accountTextField.getText();
                String password = new String(passwordField.getPassword());
 
                if (account.length() == 0){
                    JOptionPane.showMessageDialog(null, "账号不能为空,请重新输入!",
                            "系统提示!",JOptionPane.WARNING_MESSAGE);
                    return;
                }
                if (password.length() == 0){
                    JOptionPane.showMessageDialog(null,"密码不能为空!");
                    return;
                }
                String pattern = "^\\w+$";
 
                boolean flag =  Pattern.matches(pattern,password) && Pattern.matches(pattern,account);
                if (!flag){
                    JOptionPane.showMessageDialog(null,"账号密码只能由数字、字母组成!请重新输入!");
                    return;
                }
 
                //后期预留与数据库交互
 
                //创建Socket
                try {
                    Socket socket = new Socket("127.0.0.1",9999);
                    new ChatFrame(account,socket);//创建聊天窗口
                    dispose();//关闭登录界面
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                    JOptionPane.showMessageDialog(null, "服务器连接失败,请稍后再试!");
                }
            }
        });
 
        jPanel.add(welcomePanel);
        jPanel.add(accountPanel);
        jPanel.add(passwordPanel);
        jPanel.add(buttonPanel);
 
        this.add(jPanel);
        this.setVisible(true);
    }
}

聊天界面
package com.ffyc.chatRoom;
 
import util.DateUtil;
 
import javax.swing.*;
import java.awt.*;
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;
 
 
public class ChatFrame extends JFrame {
 
    JTextArea showArea;
    public ChatFrame(String account, Socket socket) throws HeadlessException, IOException {
        DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
 
 
        this.setSize(600,500);//设置聊天窗口的高和宽
        this.setLocationRelativeTo(null);//设置窗体水平垂直居中
        //this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置窗体关闭程序结束
        this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        this.setTitle("欢迎来到"+account+"聊天室");
        this.setResizable(false);//设置禁止窗口拖拽调整大小
 
        //最大面板  便捷布局
        JPanel jPanel = new JPanel(new BorderLayout());
 
        //创建一个文本域  用来显示多行聊天信息
        showArea = new JTextArea(23,34);
        showArea.setLineWrap(true);
        //创建一个滚动面板组件,将文本框作为显示组件
        JScrollPane scrollPane = new JScrollPane(showArea);
        showArea.setEditable(false);//设置文本域为不可编辑
 
        JPanel sendPanel = new JPanel(new FlowLayout());
        //创建一个文本框,用来输入单行聊天信息
        JTextArea inputField = new JTextArea(3,20);
        JButton sendbutton = new JButton("发送");
        inputField.setLineWrap(true);
        JScrollPane inputPanel = new JScrollPane(inputField);
 
 
 
        //为发送按钮添加监听事件
        sendbutton.addActionListener(e -> {
            String content = inputField.getText();
 
            //判断输入的信息是否为空
            //trim()方法返回调用字符串对象的一个副本,但是所有起始和结尾的空格都被删除了
            if (content != null && !content.trim().equals("")){
                //如果不为空,将向服务器端发送此消息
                String msg = account + " "+ DateUtil.dateToString("yyyy-MM-dd HH:mm:ss\n");
                  msg += content;
                System.out.println(msg);
 
                try {
                    dataOutputStream.writeUTF(msg);
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                    JOptionPane.showMessageDialog(null,"内容发送失败,请检查网络!");
                }
 
            }else {
                //如果为空  则提示聊天信息不能为空
                JOptionPane.showMessageDialog(null,"发送内容不能为空!");
            }
            inputField.setText("");//将输入的文本框设置为空
        });
 
 
        JLabel messagelabel = new JLabel("聊天信息");//创建一个标签
 
 
        sendPanel.add(messagelabel);
        sendPanel.add(inputPanel);
        sendPanel.add(sendbutton);
 
        jPanel.add(scrollPane,BorderLayout.NORTH);
        jPanel.add(sendPanel,BorderLayout.SOUTH);
 
        this.add(jPanel);
        this.setVisible(true);
 
        //来到聊天窗口后,可以开启一个线程监听服务器端发送的消息
         new ClientThread(socket).start();
 
        //为窗口添加事件监听
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                int res = JOptionPane.showConfirmDialog(null, "你确定要退出聊天吗?",
                        "操作提示",JOptionPane.OK_CANCEL_OPTION);
                if (res==0){
                    //点击确定
                    new LoginFrame();//打开登录窗口
                    dispose();
                }
            }
        });
    }
 
    //线程监听服务器发送的消息
    class ClientThread extends Thread{
        boolean mark = true;
        DataInputStream dataInputStream;
        public ClientThread(Socket socket) throws IOException {
            dataInputStream = new DataInputStream(socket.getInputStream());
        }
 
        @Override
        public void run() {
            while (mark){
                try {
                    String msg = dataInputStream.readUTF();
                    showArea.append(msg+"\n");//显示聊天内容,追加保留了之前的内容
                } catch (IOException e) {
                    e.printStackTrace();
                    mark = false;
                }
            }
        }
    }
 
}

主要的客户端界面到这里就基本成型了,这里还需要用到我们之前自己写的until包里面的日期转字符串构造方法,如下:

package util;
 
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
 
 
//日期转字符串
 
public class DateUtil {
    public static String dateToString(Date date ,String p){
        SimpleDateFormat sdf = new SimpleDateFormat(p);
        String str = sdf.format(date);
        return str;
    }
 
    public static String dateToString(String p){
        SimpleDateFormat sdf = new SimpleDateFormat(p);
        String str =sdf.format(new Date());
        return str;
    }
 
    //字符串转日期
    public static Date stringToDate(String datestr,String p) throws ParseException {
        SimpleDateFormat sdf =new SimpleDateFormat(p);
        Date date =sdf.parse(datestr);
        return date;
    }
 
 
 
 
    public static void main(String[] args) {
        System.out.println(DateUtil.dateToString("yyyy-MM-dd"));
    }
 
}

最后我们在run类里面启动客户端即可

package com.ffyc.chatRoom;
 
public class Run {
    public static void main(String[] args) {
 
        new LoginFrame();
    }
}
服务器端
package com.ffyc.chatroomserver;
 
import javax.swing.*;
import java.awt.*;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
 
public class Server extends JFrame {
    JTextArea serverText;
 
    public Server(){
        this.setSize(500,500);//设置聊天窗口的高和宽
        this.setLocationRelativeTo(null);//设置窗体水平垂直居中
        //this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置窗体关闭程序结束
        this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        this.setTitle("聊天室服务器端监控");
        this.setResizable(false);//设置禁止窗口拖拽调整大小
 
        //最大面板  便捷布局
        JPanel jPanel = new JPanel(new BorderLayout());
 
        //创建一个文本域  用来显示多行聊天信息
        serverText = new JTextArea();
        serverText.setLineWrap(true);
        //创建一个滚动面板组件,将文本框作为显示组件
        JScrollPane scrollPane = new JScrollPane(serverText);
        serverText.setEditable(false);//设置文本域为不可编辑
        jPanel.add(scrollPane);
 
        JPanel sendPanel = new JPanel(new FlowLayout());
        //创建一个文本框,用来输入单行聊天信息
        JTextArea inputField = new JTextArea(3,20);
        JButton sendbutton = new JButton("发送公告");
        inputField.setLineWrap(true);
        JScrollPane inputPanel = new JScrollPane(inputField);
        sendPanel.add(inputPanel);
        sendPanel.add(sendbutton);
 
        jPanel.add(sendPanel,BorderLayout.SOUTH);
 
 
        this.add(jPanel);
        this.setVisible(true);
        startServer();
    }
    //创建一个用来存放所有连接服务器端的Socket集合
    ArrayList<Socket> sockets = new ArrayList<>();
 
    //启动服务器
    public void startServer(){
        try {
            ServerSocket serverSocket = new ServerSocket(9999);
            serverText.append("服务器启动成功!\n");
            //监听多个客户端连接
            while (true){
                //监听客户端连接
                Socket socket = serverSocket.accept();
                sockets.add(socket);//将连接服务器的socket存进集合中
                serverText.append("有客户端连接成功,连接数为:"+sockets.size()+"\n");
 
                //为每一个连接到服务器的客户端开启一个线程
                new SocketThread(socket).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
            serverText.append("服务器启动失败!\n");
        }
    }
 
    //创建一个内部类,继承Thread类,用来监听自己客户端有没有发消息
    class SocketThread extends Thread{
 
        boolean flag = true;
        DataInputStream dataInputStream;
        Socket socket;
        public SocketThread(Socket socket) throws IOException {
            this.socket = socket;
            this.dataInputStream = new DataInputStream(socket.getInputStream());
        }
        @Override
        public void run() {
            while (flag){//一直死循环,监听客户端发送的消息
                try {
                    String msg = dataInputStream.readUTF();
                    serverText.append(msg+"\n");
                    //向不同的客户端转发消息
                    //遍历socket集合
                    for (Socket soc : sockets){
                        DataOutputStream dataOutputStream = new DataOutputStream(soc.getOutputStream());
                        dataOutputStream.writeUTF(msg);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    System.out.println("客户端下线了");
                    serverText.append("客户端下线了!");
                    sockets.remove(socket);
                    flag = false;
                }
            }
        }
    }
}

最后我们在服务器RUN类里面启动服务器即可

package com.ffyc.chatroomserver;
 
public class ServerRun {
    public static void main(String[] args) {
        new Server();
    }
}
运行效果
运行效果如下:

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值