[JAVA] Java聊天室之实现聊天室客户端功能

1727 0
王子 2022-11-8 17:53:01 | 显示全部楼层 |阅读模式
目录

    一、题目描述二、解题思路三、代码详解


一、题目描述

题目实现:实现聊天室客户端。运行程序,用户登录服务器后,可以从用户列表中选择单个用户进行聊天,也可以选择多个用户进行聊天。

二、解题思路

创建一个服务类:ChatClientFrame,继承JFrame类。用于进行用户登录、发送聊天信息和显示聊天信息,在该类中完成窗体界面的设计。
定义createClientSocket)方法,用于创建套接字对象、输出流对象以及启动线程对象对服务器转发的信息进行处理。
定义内部线程类ClientThread,用于对服务器端转发的信息进行处理,并显示在相应的控件中。
定义发送聊天信息的send()方法。
技术重点:
通过线程对接收到的信息进行处理,其中分为3种情况,第一种接收到的是登录用户,第二种接收到的是退出提示,第三种接收到的是消息。
使用maven-assembly-plugin插件,把引用的第三方jar包打到项目的jar包中。
启动上一题的服务端,运行服务端


启动多个客户端:
java -jar basics100-1.0-SNAPSHOT.jar



三、代码详解

引入hutool的pom,和使用maven-assembly-plugin插件
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5.     <modelVersion>4.0.0</modelVersion>
  6.     <groupId>com.xiaoxuzhu</groupId>
  7.     <artifactId>basics100</artifactId>
  8.     <version>1.0-SNAPSHOT</version>
  9.     <dependencies>
  10.         <dependency>
  11.             <groupId>cn.hutool</groupId>
  12.             <artifactId>hutool-core</artifactId>
  13.             <version>5.6.5</version>
  14.         </dependency>
  15.     </dependencies>
  16.     <build>
  17.         <plugins>
  18.             <plugin>
  19.                 <artifactId>maven-assembly-plugin</artifactId>
  20.                 <configuration>
  21.                     <archive>
  22.                         <manifest>
  23.                             <!--这里要替换成jar包main方法所在类 -->
  24.                             <mainClass>com.xiaoxuzhu.ChatClientFrame</mainClass>
  25.                         </manifest>
  26.                         <manifestEntries>
  27.                             <Class-Path>.</Class-Path>
  28.                         </manifestEntries>
  29.                     </archive>
  30.                     <descriptorRefs>
  31.                         <descriptorRef>jar-with-dependencies</descriptorRef>
  32.                     </descriptorRefs>
  33.                     <appendAssemblyId>false</appendAssemblyId>
  34.                 </configuration>
  35.                 <executions>
  36.                     <execution>
  37.                         <id>make-assembly</id> <!-- this is used for inheritance merges -->
  38.                         <phase>package</phase> <!-- 指定在打包节点执行jar包合并操作 -->
  39.                         <goals>
  40.                             <goal>single</goal>
  41.                         </goals>
  42.                     </execution>
  43.                 </executions>
  44.             </plugin>
  45.         </plugins>
  46.     </build>
  47. </project>
复制代码
ChatClientFrame
  1. package com.xiaoxuzhu;
  2. import cn.hutool.core.io.resource.ResourceUtil;
  3. import java.awt.*;
  4. import java.awt.event.ActionEvent;
  5. import java.awt.event.ActionListener;
  6. import java.awt.event.MouseAdapter;
  7. import java.awt.event.MouseEvent;
  8. import java.io.BufferedReader;
  9. import java.io.IOException;
  10. import java.io.InputStreamReader;
  11. import java.io.ObjectOutputStream;
  12. import java.net.Socket;
  13. import java.net.URL;
  14. import java.net.UnknownHostException;
  15. import java.text.DateFormat;
  16. import java.util.Date;
  17. import java.util.Vector;
  18. import javax.swing.*;
  19. /**
  20. * Description:
  21. *
  22. * @author xiaoxuzhu
  23. * @version 1.0
  24. *
  25. * <pre>
  26. * 修改记录:
  27. * 修改后版本                修改人                修改日期                        修改内容
  28. * 2022/6/6.1            xiaoxuzhu                2022/6/6                    Create
  29. * </pre>
  30. * @date 2022/6/6
  31. */
  32. public class ChatClientFrame extends JFrame {
  33.     private JTextField tf_newUser;
  34.     private JList user_list;
  35.     private JTextArea ta_info;
  36.     private JTextField tf_send;
  37.     private ObjectOutputStream out;// 声明输出流对象
  38.     private Socket socket;
  39.     private boolean loginFlag = false;// 为true时表示已经登录,为false时表示未登录
  40.     public static void main(String args[]) {
  41.         System.out.println(SwingUtilities.isEventDispatchThread());
  42.         EventQueue.invokeLater(new Runnable() {
  43.             public void run() {
  44.                 System.out.println(SwingUtilities.isEventDispatchThread());
  45.                 try {
  46.                     ChatClientFrame frame = new ChatClientFrame();
  47.                     frame.setVisible(true);
  48.                     frame.createClientSocket();// 调用方法创建套接字对象
  49.                 } catch (Exception e) {
  50.                     e.printStackTrace();
  51.                 }
  52.             }
  53.         });
  54.     }
  55.     public void createClientSocket() {
  56.         try {
  57.              socket = new Socket("127.0.0.1", 9527);// 创建套接字对象
  58.             out = new ObjectOutputStream(socket.getOutputStream());// 创建输出流对象
  59.             SwingWorker<Void,Void> worker=new SwingWorker<Void, Void>() {
  60.                 @Override
  61.                 protected Void doInBackground() throws Exception {
  62.                     try {
  63.                         System.out.println(SwingUtilities.isEventDispatchThread());
  64.                         BufferedReader in = new BufferedReader(new InputStreamReader(
  65.                                 socket.getInputStream()));// 创建输入流对象
  66.                         DefaultComboBoxModel model = (DefaultComboBoxModel) user_list
  67.                                 .getModel();// 获得列表框的模型
  68.                         while (true) {
  69.                             String info = in.readLine().trim();// 读取信息
  70.                             if (!info.startsWith("MSG:")) {// 接收到的不是消息
  71.                                 if (info.startsWith("退出:")) {// 接收到的是退出消息
  72.                                     model.removeElement(info.substring(3));// 从用户列表中移除用户
  73.                                 } else {// 接收到的是登录用户
  74.                                     boolean itemFlag = false;// 标记是否为列表框添加列表项,为true不添加,为false添加
  75.                                     for (int i = 0; i < model.getSize(); i++) {// 对用户列表进行遍历
  76.                                         if (info.equals((String) model.getElementAt(i))) {// 如果用户列表中存在该用户名
  77.                                             itemFlag = true;// 设置为true,表示不添加到用户列表
  78.                                             break;// 结束for循环
  79.                                         }
  80.                                     }
  81.                                     if (!itemFlag) {
  82.                                         model.addElement(info);// 将登录用户添加到用户列表
  83.                                     }
  84.                                 }
  85.                             } else {// 如果获得的是消息,则在文本域中显示接收到的消息
  86.                                 DateFormat df = DateFormat.getDateInstance();// 获得DateFormat实例
  87.                                 String dateString = df.format(new Date());         // 格式化为日期
  88.                                 df = DateFormat.getTimeInstance(DateFormat.MEDIUM);// 获得DateFormat实例
  89.                                 String timeString = df.format(new Date());         // 格式化为时间
  90.                                 String sendUser = info.substring(4,info.indexOf(":发送给:"));// 获得发送信息的用户
  91.                                 String receiveInfo = info.substring(info.indexOf(":的信息是:")+6);// 获得接收到的信息
  92.                                 ta_info.append("  "+sendUser + "    " +dateString+"  "+timeString+"\n  "+receiveInfo+"\n");// 在文本域中显示信息
  93.                                 ta_info.setSelectionStart(ta_info.getText().length()-1);// 设置选择起始位置
  94.                                 ta_info.setSelectionEnd(ta_info.getText().length());// 设置选择的结束位置
  95.                                 tf_send.requestFocus();// 使发送信息文本框获得焦点
  96.                             }
  97.                         }
  98.                     } catch (IOException e) {
  99.                         e.printStackTrace();
  100.                     }
  101.                     return null;
  102.                 }
  103.             };
  104.             worker.execute();
  105.             //new ClientThread(socket).start();// 创建并启动线程对象
  106.         } catch (UnknownHostException e) {
  107.             e.printStackTrace();
  108.         } catch (IOException e) {
  109.             e.printStackTrace();
  110.         }
  111.     }
  112.     class ClientThread extends Thread {
  113.         Socket socket;
  114.         public ClientThread(Socket socket) {
  115.             this.socket = socket;
  116.         }
  117.         public void run() {
  118.         }
  119.     }
  120.     private void send() {
  121.         if (!loginFlag) {
  122.             JOptionPane.showMessageDialog(null, "请先登录。");
  123.             return;// 如果用户没登录则返回
  124.         }
  125.         String sendUserName = tf_newUser.getText().trim();// 获得登录用户名
  126.         String info = tf_send.getText();// 获得输入的发送信息
  127.         if (info.equals("")) {
  128.             return;// 如果没输入信息则返回,即不发送
  129.         }
  130.         Vector<String> v = new Vector<String>();// 创建向量对象,用于存储发送的消息
  131.         Object[] receiveUserNames = user_list.getSelectedValues();// 获得选择的用户数组
  132.         if (receiveUserNames.length <= 0) {
  133.             return;// 如果没选择用户则返回
  134.         }
  135.         for (int i = 0; i < receiveUserNames.length; i++) {
  136.             String msg = sendUserName + ":发送给:" + (String) receiveUserNames[i]
  137.                     + ":的信息是: " + info;// 定义发送的信息
  138.             v.add(msg);// 将信息添加到向量
  139.         }
  140.         try {
  141.             out.writeObject(v);// 将向量写入输出流,完成信息的发送
  142.             out.flush();// 刷新输出缓冲区
  143.         } catch (IOException e) {
  144.             e.printStackTrace();
  145.         }
  146.         DateFormat df = DateFormat.getDateInstance();// 获得DateFormat实例
  147.         String dateString = df.format(new Date());         // 格式化为日期
  148.         df = DateFormat.getTimeInstance(DateFormat.MEDIUM);// 获得DateFormat实例
  149.         String timeString = df.format(new Date());         // 格式化为时间
  150.         String sendUser = tf_newUser.getText().trim();// 获得发送信息的用户
  151.         String receiveInfo = tf_send.getText().trim();// 显示发送的信息
  152.         ta_info.append("  "+sendUser + "    " +dateString+"  "+timeString+"\n  "+receiveInfo+"\n");// 在文本域中显示信息
  153.         tf_send.setText(null);// 清空文本框
  154.         ta_info.setSelectionStart(ta_info.getText().length()-1);// 设置选择的起始位置
  155.         ta_info.setSelectionEnd(ta_info.getText().length());// 设置选择的结束位置
  156.         tf_send.requestFocus();// 使发送信息文本框获得焦点
  157.     }
  158.     /**
  159.      * Create the frame
  160.      */
  161.     public ChatClientFrame() {
  162.         super();
  163.         setTitle("聊天室客户端");
  164.         setBounds(100, 100, 385, 288);
  165.         final JPanel panel = new JPanel();
  166.         getContentPane().add(panel, BorderLayout.SOUTH);
  167.         final JLabel label = new JLabel();
  168.         label.setText("输入聊天内容:");
  169.         panel.add(label);
  170.         tf_send = new JTextField();
  171.         tf_send.addActionListener(new ActionListener() {
  172.             public void actionPerformed(final ActionEvent e) {
  173.                 send();// 调用方法发送信息
  174.             }
  175.         });
  176.         tf_send.setPreferredSize(new Dimension(180, 25));
  177.         panel.add(tf_send);
  178.         final JButton button = new JButton();
  179.         button.addActionListener(new ActionListener() {
  180.             public void actionPerformed(final ActionEvent e) {
  181.                 send();// 调用方法发送信息
  182.             }
  183.         });
  184.         button.setText("发  送");
  185.         panel.add(button);
  186.         final JSplitPane splitPane = new JSplitPane();
  187.         splitPane.setDividerLocation(100);
  188.         getContentPane().add(splitPane, BorderLayout.CENTER);
  189.         final JScrollPane scrollPane = new JScrollPane();
  190.         splitPane.setRightComponent(scrollPane);
  191.         ta_info = new JTextArea();
  192.         ta_info.setFont(new Font("", Font.BOLD, 14));
  193.         scrollPane.setViewportView(ta_info);
  194.         final JScrollPane scrollPane_1 = new JScrollPane();
  195.         splitPane.setLeftComponent(scrollPane_1);
  196.         user_list = new JList();
  197.         user_list.setModel(new DefaultComboBoxModel(new String[] { "" }));
  198.         scrollPane_1.setViewportView(user_list);
  199.         final JPanel panel_1 = new JPanel();
  200.         getContentPane().add(panel_1, BorderLayout.NORTH);
  201.         final JLabel label_1 = new JLabel();
  202.         label_1.setText("用户名称:");
  203.         panel_1.add(label_1);
  204.         tf_newUser = new JTextField();
  205.         tf_newUser.setPreferredSize(new Dimension(140, 25));
  206.         panel_1.add(tf_newUser);
  207.         final JButton button_1 = new JButton();
  208.         button_1.addActionListener(new ActionListener() {
  209.             public void actionPerformed(final ActionEvent e) {
  210.                 if (loginFlag) {// 已登录标记为true
  211.                     JOptionPane.showMessageDialog(null, "在同一窗口只能登录一次。");
  212.                     return;
  213.                 }
  214.                 String userName = tf_newUser.getText().trim();// 获得登录用户名
  215.                 Vector v = new Vector();// 定义向量,用于存储登录用户
  216.                 v.add("用户:" + userName);// 添加登录用户
  217.                 try {
  218.                     out.writeObject(v);// 将用户向量发送到服务器
  219.                     out.flush();// 刷新输出缓冲区
  220.                 } catch (IOException ex) {
  221.                     ex.printStackTrace();
  222.                 }
  223.                 tf_newUser.setEnabled(false);// 禁用用户文本框
  224.                 loginFlag = true;// 将已登录标记设置为true
  225.             }
  226.         });
  227.         button_1.setText("登  录");
  228.         panel_1.add(button_1);
  229.         final JButton button_2 = new JButton();
  230.         button_2.addActionListener(new ActionListener() {
  231.             public void actionPerformed(final ActionEvent e) {
  232.                 String exitUser = tf_newUser.getText().trim();
  233.                 Vector v = new Vector();
  234.                 v.add("退出:" + exitUser);
  235.                 try {
  236.                     out.writeObject(v);
  237.                     out.flush();// 刷新输出缓冲区
  238.                 } catch (IOException ex) {
  239.                     ex.printStackTrace();
  240.                 }
  241.                 System.exit(0);                                     // 退出系统
  242.             }
  243.         });
  244.         button_2.setText("退  出");
  245.         panel_1.add(button_2);
  246.         //托盘
  247.         if (SystemTray.isSupported()){                                      // 判断是否支持系统托盘
  248.             URL url= ResourceUtil.getResource("client.png",null);         // 获取图片所在的URL
  249.             ImageIcon icon = new ImageIcon(url);                            // 实例化图像对象
  250.             Image image=icon.getImage();                                    // 获得Image对象
  251.             TrayIcon trayIcon=new TrayIcon(image);                          // 创建托盘图标
  252.             trayIcon.addMouseListener(new MouseAdapter(){                   // 为托盘添加鼠标适配器
  253.                 public void mouseClicked(MouseEvent e){                     // 鼠标事件
  254.                     if (e.getClickCount()==2){                              // 判断是否双击了鼠标
  255.                         showFrame();                                    // 调用方法显示窗体
  256.                     }
  257.                 }
  258.             });
  259.             trayIcon.setToolTip("系统托盘");                                    // 添加工具提示文本
  260.             PopupMenu popupMenu=new PopupMenu();                    // 创建弹出菜单
  261.             MenuItem exit=new MenuItem("退出");                           // 创建菜单项
  262.             exit.addActionListener(new ActionListener() {                   // 添加事件监听器
  263.                 public void actionPerformed(final ActionEvent arg0) {
  264.                     String exitUser = tf_newUser.getText().trim();
  265.                     Vector v = new Vector();
  266.                     v.add("退出:" + exitUser);
  267.                     try {
  268.                         out.writeObject(v);
  269.                         out.flush();// 刷新输出缓冲区
  270.                     } catch (IOException ex) {
  271.                         ex.printStackTrace();
  272.                     }
  273.                     System.exit(0);                                     // 退出系统
  274.                 }
  275.             });
  276.             popupMenu.add(exit);                                        // 为弹出菜单添加菜单项
  277.             trayIcon.setPopupMenu(popupMenu);                           // 为托盘图标加弹出菜弹
  278.             SystemTray systemTray=SystemTray.getSystemTray();           // 获得系统托盘对象
  279.             try{
  280.                 systemTray.add(trayIcon);                               // 为系统托盘加托盘图标
  281.             }catch(Exception e){
  282.                 e.printStackTrace();
  283.             }
  284.         }
  285.     }
  286.     public void showFrame(){
  287.         this.setVisible(true);                                              // 显示窗体
  288.         this.setState(Frame.NORMAL);
  289.     }
  290. }
复制代码
上一题服务端启动:


第一个客户端:小小 启动


第二个客户端:虚虚 启动


第三个客户端:竹竹 启动


小小给竹竹发消息


竹竹回复小小:


小小收到回复:


以上就是Java聊天室之实现聊天室客户端功能的详细内容,更多关于Java聊天室的资料请关注中国红客联盟其它相关文章!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行