java - 基于UDP协议实现简单局域网群聊程序

登录界面

package window;

import chat.ChatInfo;
import pojo.User;

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

/**
 * @author: 牧心
 * @Date: 2020/09/07
 * @Description: 登陆界面
 */
public class LoginWindow{
    private static final int LOGIN_WINDOW_WIDTH = 500;
    private static final int LOGIN_WINDOW_HEIGHT = 400;
    private static LoginWindow loginWindow;
    private JFrame loginFrame;
    private JPanel loginPanel;
    private JLabel titleLabel;
    private JLabel usernameLabel;
    private JTextField usernameInput;
    private JButton loginBtn;

    private LoginWindow(){
        init();
    }

    /**
     * 窗口初始化
     */
    private void init(){
        // 窗口标题
        loginFrame = new JFrame("登录");
        // 不可放缩
        loginFrame.setResizable(false);
        //
        Container container = loginFrame.getContentPane();
        /**********************/
        //获取屏幕的大小
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        //任务栏高度
//        int missionBoardHeight = Toolkit.getDefaultToolkit().getScreenInsets(new JFrame().getGraphicsConfiguration()).bottom;
        int SCREEN_WIDHTH = (int) screenSize.getWidth();
        int SCREEN_HEIGHT = (int)screenSize.getHeight();
        /**********************/
        // 窗口居中
        loginFrame.setSize(LOGIN_WINDOW_WIDTH,
                LOGIN_WINDOW_HEIGHT);
        loginFrame.setLocation((SCREEN_WIDHTH - LOGIN_WINDOW_WIDTH)/2,
                (SCREEN_HEIGHT - LOGIN_WINDOW_HEIGHT)/2);
        loginFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        // 创建面板容器
        loginPanel = new JPanel();
        //
        container.add(loginPanel);
        // loginFrame.setContentPane(loginPanel);
        // null布局
        loginPanel.setLayout(null);
        // 登录标题
        titleLabel = new JLabel("登录");
        titleLabel.setVerticalTextPosition(JLabel.CENTER);
        titleLabel.setHorizontalTextPosition(JLabel.CENTER);
        titleLabel.setFont(new Font(Font.SERIF, Font.BOLD, 50));
        titleLabel.setBounds(new Rectangle(190, 40, 120, 60));
        loginPanel.add(titleLabel);
        // 用户名输入标签
        usernameLabel = new JLabel("用户名:");
        usernameLabel.setVerticalTextPosition(JLabel.CENTER);
        usernameLabel.setHorizontalTextPosition(JLabel.CENTER);
        usernameLabel.setFont(new Font(Font.SERIF, Font.BOLD, 20));
        usernameLabel.setBounds(new Rectangle(80, 140, 80, 40));
        loginPanel.add(usernameLabel);
        // 用户名输入框
        usernameInput = new JTextField();
        usernameInput.setFont(new Font(Font.SERIF, Font.BOLD, 20));
        usernameInput.setBounds(160, 140, 260, 40);
        loginPanel.add(usernameInput);
        // 登录按钮
        loginBtn = new JButton("登录");
        loginBtn.setVerticalTextPosition(JButton.CENTER);
        loginBtn.setHorizontalTextPosition(JButton.CENTER);
        // 去除点击按钮时文字周围的线框
        loginBtn.setFocusPainted(false);
        loginBtn.setFont(new Font(Font.SERIF, Font.BOLD, 30));
        loginBtn.setBounds(80, 220, 340, 40);
        // 绑定登录事件
        loginBtn.addActionListener(e -> loginAction(e));
        loginPanel.add(loginBtn);
        //
        // loginFrame.pack();
        // 监听框架关闭按钮事件
        loginFrame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        //
        usernameInput.addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {}
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyChar() == KeyEvent.VK_ENTER){
                    loginBtn.doClick();
                }
            }
            @Override
            public void keyReleased(KeyEvent e) {}
        });
        //
        loginFrame.setVisible(true);
    }

    /**
     * 获取登录窗口
     * @return
     */
    public static LoginWindow getInstance(){
        if (loginWindow == null){
            loginWindow = new LoginWindow();
        }
        return loginWindow;
    }

    /**
     * 登录按钮事件
     * @param e
     */
    private void loginAction(ActionEvent e){
        String username = usernameInput.getText().trim();
        if ("".equals(username)){
            return;
        }
        // 销毁登录窗口
        loginWindow.loginFrame.dispose();
        loginWindow = null;
        // 存储本机登录用户用户名
        User user = new User(username);
        ChatInfo.setUser(user);
        // 进入群聊界面
        ChatWindow.getInstance();
    }
}

聊天界面

package window;

import chat.ChatHandler;
import chat.ChatInfo;
import chat.ChatReceiver;
import pojo.Message;
import pojo.User;

import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.StringSelection;
import java.awt.event.*;


/**
 * @author: 牧心
 * @Date: 2020/09/07
 * @Description: 聊天界面
 */
public class ChatWindow {

    private static final int CHAT_WINDOW_WIDTH = 800;
    private static final int CHAT_WINDOW_HEIGHT = 620;
    private User user;
    private static ChatWindow chatWindow;
    private JFrame chatFrame;
    private JPanel chatPanel;

    private JTextField msgInput;
    private JButton sendBtn;

    private JTextArea msgShowArea;
    private JScrollPane scrollPane;

    private JPopupMenu popupMenu;

    private ChatWindow() {
        this.user = ChatInfo.getUser();
        init();
        // 开启一个消息接收端线程
        new Thread(new ChatReceiver()).start();
    }

    /**
     *
     */
    private void init() {
        // 窗口标题
        chatFrame = new JFrame(user.getUsername());
        // 不可放缩
        chatFrame.setResizable(false);
        //
        Container container = chatFrame.getContentPane();
        /**********************/
        //获取屏幕的大小
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        int SCREEN_WIDHTH = (int) screenSize.getWidth();
        int SCREEN_HEIGHT = (int) screenSize.getHeight();
        /**********************/
        // 窗口居中
        chatFrame.setSize(CHAT_WINDOW_WIDTH, CHAT_WINDOW_HEIGHT);
        chatFrame.setLocation((SCREEN_WIDHTH - CHAT_WINDOW_WIDTH) / 2,
                (SCREEN_HEIGHT - CHAT_WINDOW_HEIGHT) / 2);
        chatFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        // 创建面板容器
        chatPanel = new JPanel();
        //
        container.add(chatPanel);
        // loginFrame.setContentPane(loginPanel);
        // null布局
        chatPanel.setLayout(null);
        // 消息输入框
        msgInput = new JTextField();
        msgInput.setFont(new Font(Font.SERIF, Font.BOLD, 20));
        msgInput.setBounds(20, 520, 620, 40);
        // 实现点击enter键发送消息
        msgInput.addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) { }
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyChar() == KeyEvent.VK_ENTER) {
                    sendBtn.doClick();
                }
            }
            @Override
            public void keyReleased(KeyEvent e) {
            }
        });
        chatPanel.add(msgInput);
        // 发送按钮
        sendBtn = new JButton("发送");
        sendBtn.setVerticalTextPosition(JButton.CENTER);
        sendBtn.setHorizontalTextPosition(JButton.CENTER);
        // 去除点击按钮时文字周围的线框
        sendBtn.setFocusPainted(false);
        sendBtn.setFont(new Font(Font.SERIF, Font.BOLD, 20));
        sendBtn.setBounds(660, 520, 120, 40);
        //
        sendBtn.addActionListener(e -> {
            try {
                sendMessage();
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        });
        //
        chatPanel.add(sendBtn);
        // 消息输入框
        msgShowArea = new JTextArea();
        msgShowArea.setFont(new Font(Font.SERIF, Font.BOLD, 20));
//        msgShowArea.setBounds(20, 20, 760, 470);
        // 自动换行
        msgShowArea.setLineWrap(true);
        //
        scrollPane = new JScrollPane(msgShowArea);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane.setBounds(20, 20, 760, 470);
//        chatPanel.add(msgShowArea);
        chatPanel.add(scrollPane);
        msgShowArea.setEditable(false);
        // 消息展示区右键菜单
        popupMenu = new JPopupMenu();
        JMenuItem copy = new JMenuItem("复制");
        copy.setFont(new Font(Font.SERIF, Font.TRUETYPE_FONT, 18));
        copy.setFocusPainted(false);
        copy.setSize(160, 30);
        // 点击复制,将选中内容复制到截切板
        copy.addActionListener(e -> {
            String selectText = msgShowArea.getSelectedText().trim();
            if (!"".equals(selectText)){
                StringSelection selection = new StringSelection(selectText);
                Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, selection);
            }
        });
        popupMenu.add(copy);
        msgShowArea.setComponentPopupMenu(popupMenu);
        //
        msgShowArea.setSelectedTextColor(Color.orange);
        // 监听框架关闭按钮事件
        chatFrame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                // 退出程序
                System.exit(0);
            }
        });
        //
        chatFrame.setVisible(true);
    }

    /**
     * 发送消息
     */
    private void sendMessage() throws Exception {
        String msg = msgInput.getText().trim();
        if (!"".equals(msg)) {
            // 清空消息输入框
            msgInput.setText("");
            // 将消息追加到消息列表
            Message message = new Message(user.getUsername(), msg);
            // 将消息展示在消息区
            ChatHandler.sendMessage(message);
        }
    }


    /**
     * 单例模式
     * @return
     */
    public static ChatWindow getInstance() {
        if (chatWindow == null) {
            chatWindow = new ChatWindow();
        }
        return chatWindow;
    }

    /**
     * 像文本域追加消息记录
     * @param message
     */
    private void showMsg(Message message) {
        if (!"".equals(message.getMessage())) {
            msgShowArea.append("@");
            msgShowArea.append(message.getUsername());
            msgShowArea.append("\t");
            msgShowArea.append(message.getDatestamp());
            msgShowArea.append("\n  ");
            msgShowArea.append(message.getMessage());
            msgShowArea.append("\n");
        }
        msgShowArea.setCaretPosition(msgShowArea.getText().length());
    }

    /**
     * @param message
     */
    public void displayMessage(Message message) {
        showMsg(message);
    }
}

消息接收线程

package chat;

import pojo.Message;
import window.ChatWindow;

import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
 * @author: 牧心
 * @Date: 2020/09/07
 * @Description: 用来接收消息
 */
public class ChatReceiver implements Runnable {

    private DatagramSocket socket;

    public ChatReceiver() {
        try {
            socket = new DatagramSocket(8633);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 接收消息
     */
    private void receive() {
        try {
            byte[] bytes = new byte[1024 * 16];
            DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
            socket.receive(packet);
            // 处理接收到的数据
            ByteArrayInputStream bais = new ByteArrayInputStream(packet.getData());
            ObjectInputStream ois = new ObjectInputStream(bais);
            // 将数据转为Message对象
            Message message = (Message) ois.readObject();
            // 将数据展示在消息区域
            ChatWindow.getInstance().displayMessage(message);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        while (true) {
            receive();
        }
    }
}

消息发送类

package chat;

import pojo.Message;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;


/**
 * @author: 牧心
 * @Date: 2020/09/07
 * @Description: 用来广播消息
 */
public class ChatHandler {

    private static DatagramSocket socket;
    private static ByteArrayOutputStream baos;
    private static ObjectOutputStream oos;

    static {
        try {
            socket = new DatagramSocket();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void sendMessage(Message message) throws Exception {
        //
        baos = new ByteArrayOutputStream();
        oos = new ObjectOutputStream(baos);
        oos.writeObject(message);
        byte[] bytes = baos.toByteArray();
        //
        int len = bytes.length;
        //广播消息
        InetAddress address = InetAddress.getByName("255.255.255.255");
        // 创建广播消息数据包
        DatagramPacket packet = new DatagramPacket(bytes, len, address, 8633);
        oos.flush();
        socket.send(packet);
    }
}

存储本机登录用户信息

package chat;

import pojo.User;

/**
 * @author: 牧心
 * @Date: 2020/09/07
 * @Description: 存储本机登录用户信息
 */
public class ChatInfo {

    private static User self = null;

    public static User getUser(){
        return self;
    }

    public static void setUser(User user){
        self = user;
    }
}

消息体

package pojo;

import utils.DateUtils;

import java.io.Serializable;

/**
 * @author: 牧心
 * @Date: 2020/09/07
 * @Description:
 */
public class Message implements Serializable {

    private String username;

    private String message;

    private String datestamp;

    public Message(String username, String message) {
        this.username = username;
        this.message = message;
        this.datestamp = DateUtils.getDateStamp();
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getDatestamp() {
        return datestamp;
    }

    public void setDatestamp(String datestamp) {
        this.datestamp = datestamp;
    }

    @Override
    public String toString() {
        return "Message{" +
                "username='" + username + '\'' +
                ", message='" + message + '\'' +
                ", datestamp='" + datestamp + '\'' +
                '}';
    }
}


用户实体类

package pojo;

/**
 * @author: 牧心
 * @Date: 2020/09/07
 * @Description:
 */
public class User {
    public String username;
    public User(String username) {
        this.username = username;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
}

时间戳工具类

package utils;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author: 牧心
 * @Date: 2020/09/07
 * @Description: 日期工具类
 */
public class DateUtils {

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 获取当前时间戳字符串
     * @return
     */
    public static String getDateStamp() {
        return dateFormat.format(new Date());
    }
}

程序启动类


import window.LoginWindow;

/**
 * @author: 牧心
 * @Date: 2020/09/07
 * @Description: 程序启动类
 */
public class ChatStarter {
    public static void main(String[] args){
        // 从登陆界面开始
        LoginWindow.getInstance();
    }
}

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值