欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java聊天室之實(shí)現(xiàn)聊天室客戶端功能

 更新時(shí)間:2022年11月01日 08:22:01   作者:小虛竹and掘金  
這篇文章主要為大家詳細(xì)介紹了Java簡易聊天室之實(shí)現(xiàn)聊天室客戶端功能,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以了解一下

一、題目描述

題目實(shí)現(xiàn):實(shí)現(xiàn)聊天室客戶端。運(yùn)行程序,用戶登錄服務(wù)器后,可以從用戶列表中選擇單個(gè)用戶進(jìn)行聊天,也可以選擇多個(gè)用戶進(jìn)行聊天。

二、解題思路

創(chuàng)建一個(gè)服務(wù)類:ChatClientFrame,繼承JFrame類。用于進(jìn)行用戶登錄、發(fā)送聊天信息和顯示聊天信息,在該類中完成窗體界面的設(shè)計(jì)。

定義createClientSocket)方法,用于創(chuàng)建套接字對象、輸出流對象以及啟動(dòng)線程對象對服務(wù)器轉(zhuǎn)發(fā)的信息進(jìn)行處理。

定義內(nèi)部線程類ClientThread,用于對服務(wù)器端轉(zhuǎn)發(fā)的信息進(jìn)行處理,并顯示在相應(yīng)的控件中。

定義發(fā)送聊天信息的send()方法。

技術(shù)重點(diǎn):

通過線程對接收到的信息進(jìn)行處理,其中分為3種情況,第一種接收到的是登錄用戶,第二種接收到的是退出提示,第三種接收到的是消息。

使用maven-assembly-plugin插件,把引用的第三方j(luò)ar包打到項(xiàng)目的jar包中。

啟動(dòng)上一題的服務(wù)端,運(yùn)行服務(wù)端

啟動(dòng)多個(gè)客戶端:

java -jar basics100-1.0-SNAPSHOT.jar

三、代碼詳解

引入hutool的pom,和使用maven-assembly-plugin插件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.xiaoxuzhu</groupId>
    <artifactId>basics100</artifactId>
    <version>1.0-SNAPSHOT</version>
    
    <dependencies>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-core</artifactId>
            <version>5.6.5</version>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <!--這里要替換成jar包main方法所在類 -->
                            <mainClass>com.xiaoxuzhu.ChatClientFrame</mainClass>
                        </manifest>
                        <manifestEntries>
                            <Class-Path>.</Class-Path>
                        </manifestEntries>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <appendAssemblyId>false</appendAssemblyId>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id> <!-- this is used for inheritance merges -->
                        <phase>package</phase> <!-- 指定在打包節(jié)點(diǎn)執(zhí)行jar包合并操作 -->
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

  

</project>

ChatClientFrame

package com.xiaoxuzhu;

import cn.hutool.core.io.resource.ResourceUtil;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.text.DateFormat;
import java.util.Date;
import java.util.Vector;

import javax.swing.*;

/**
 * Description: 
 *
 * @author xiaoxuzhu
 * @version 1.0
 *
 * <pre>
 * 修改記錄:
 * 修改后版本	        修改人		修改日期			修改內(nèi)容
 * 2022/6/6.1	    xiaoxuzhu		2022/6/6		    Create
 * </pre>
 * @date 2022/6/6
 */

public class ChatClientFrame extends JFrame {
    private JTextField tf_newUser;
    private JList user_list;
    private JTextArea ta_info;
    private JTextField tf_send;
    private ObjectOutputStream out;// 聲明輸出流對象
    private Socket socket;
    private boolean loginFlag = false;// 為true時(shí)表示已經(jīng)登錄,為false時(shí)表示未登錄

    public static void main(String args[]) {
        System.out.println(SwingUtilities.isEventDispatchThread());
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                System.out.println(SwingUtilities.isEventDispatchThread());
                try {
                    ChatClientFrame frame = new ChatClientFrame();
                    frame.setVisible(true);
                    frame.createClientSocket();// 調(diào)用方法創(chuàng)建套接字對象
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public void createClientSocket() {
        try {
             socket = new Socket("127.0.0.1", 9527);// 創(chuàng)建套接字對象
            out = new ObjectOutputStream(socket.getOutputStream());// 創(chuàng)建輸出流對象
            SwingWorker<Void,Void> worker=new SwingWorker<Void, Void>() {
                @Override
                protected Void doInBackground() throws Exception {
                    try {
                        System.out.println(SwingUtilities.isEventDispatchThread());
                        BufferedReader in = new BufferedReader(new InputStreamReader(
                                socket.getInputStream()));// 創(chuàng)建輸入流對象
                        DefaultComboBoxModel model = (DefaultComboBoxModel) user_list
                                .getModel();// 獲得列表框的模型
                        while (true) {
                            String info = in.readLine().trim();// 讀取信息
                            if (!info.startsWith("MSG:")) {// 接收到的不是消息
                                if (info.startsWith("退出:")) {// 接收到的是退出消息
                                    model.removeElement(info.substring(3));// 從用戶列表中移除用戶
                                } else {// 接收到的是登錄用戶
                                    boolean itemFlag = false;// 標(biāo)記是否為列表框添加列表項(xiàng),為true不添加,為false添加
                                    for (int i = 0; i < model.getSize(); i++) {// 對用戶列表進(jìn)行遍歷
                                        if (info.equals((String) model.getElementAt(i))) {// 如果用戶列表中存在該用戶名
                                            itemFlag = true;// 設(shè)置為true,表示不添加到用戶列表
                                            break;// 結(jié)束for循環(huán)
                                        }
                                    }
                                    if (!itemFlag) {
                                        model.addElement(info);// 將登錄用戶添加到用戶列表
                                    }
                                }
                            } else {// 如果獲得的是消息,則在文本域中顯示接收到的消息
                                DateFormat df = DateFormat.getDateInstance();// 獲得DateFormat實(shí)例
                                String dateString = df.format(new Date());         // 格式化為日期
                                df = DateFormat.getTimeInstance(DateFormat.MEDIUM);// 獲得DateFormat實(shí)例
                                String timeString = df.format(new Date());         // 格式化為時(shí)間
                                String sendUser = info.substring(4,info.indexOf(":發(fā)送給:"));// 獲得發(fā)送信息的用戶
                                String receiveInfo = info.substring(info.indexOf(":的信息是:")+6);// 獲得接收到的信息
                                ta_info.append("  "+sendUser + "    " +dateString+"  "+timeString+"\n  "+receiveInfo+"\n");// 在文本域中顯示信息
                                ta_info.setSelectionStart(ta_info.getText().length()-1);// 設(shè)置選擇起始位置
                                ta_info.setSelectionEnd(ta_info.getText().length());// 設(shè)置選擇的結(jié)束位置
                                tf_send.requestFocus();// 使發(fā)送信息文本框獲得焦點(diǎn)
                            }
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    return null;
                }
            };
            worker.execute();
            //new ClientThread(socket).start();// 創(chuàng)建并啟動(dòng)線程對象
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    class ClientThread extends Thread {
        Socket socket;
        public ClientThread(Socket socket) {
            this.socket = socket;
        }
        public void run() {
           
        }
    }

    private void send() {
        if (!loginFlag) {
            JOptionPane.showMessageDialog(null, "請先登錄。");
            return;// 如果用戶沒登錄則返回
        }
        String sendUserName = tf_newUser.getText().trim();// 獲得登錄用戶名
        String info = tf_send.getText();// 獲得輸入的發(fā)送信息
        if (info.equals("")) {
            return;// 如果沒輸入信息則返回,即不發(fā)送
        }
        Vector<String> v = new Vector<String>();// 創(chuàng)建向量對象,用于存儲(chǔ)發(fā)送的消息
        Object[] receiveUserNames = user_list.getSelectedValues();// 獲得選擇的用戶數(shù)組
        if (receiveUserNames.length <= 0) {
            return;// 如果沒選擇用戶則返回
        }
        for (int i = 0; i < receiveUserNames.length; i++) {
            String msg = sendUserName + ":發(fā)送給:" + (String) receiveUserNames[i]
                    + ":的信息是: " + info;// 定義發(fā)送的信息
            v.add(msg);// 將信息添加到向量
        }
        try {
            out.writeObject(v);// 將向量寫入輸出流,完成信息的發(fā)送
            out.flush();// 刷新輸出緩沖區(qū)
        } catch (IOException e) {
            e.printStackTrace();
        }
        DateFormat df = DateFormat.getDateInstance();// 獲得DateFormat實(shí)例
        String dateString = df.format(new Date());         // 格式化為日期
        df = DateFormat.getTimeInstance(DateFormat.MEDIUM);// 獲得DateFormat實(shí)例
        String timeString = df.format(new Date());         // 格式化為時(shí)間
        String sendUser = tf_newUser.getText().trim();// 獲得發(fā)送信息的用戶
        String receiveInfo = tf_send.getText().trim();// 顯示發(fā)送的信息
        ta_info.append("  "+sendUser + "    " +dateString+"  "+timeString+"\n  "+receiveInfo+"\n");// 在文本域中顯示信息
        tf_send.setText(null);// 清空文本框
        ta_info.setSelectionStart(ta_info.getText().length()-1);// 設(shè)置選擇的起始位置
        ta_info.setSelectionEnd(ta_info.getText().length());// 設(shè)置選擇的結(jié)束位置
        tf_send.requestFocus();// 使發(fā)送信息文本框獲得焦點(diǎn)
    }

    /**
     * Create the frame
     */
    public ChatClientFrame() {
        super();
        setTitle("聊天室客戶端");
        setBounds(100, 100, 385, 288);

        final JPanel panel = new JPanel();
        getContentPane().add(panel, BorderLayout.SOUTH);

        final JLabel label = new JLabel();
        label.setText("輸入聊天內(nèi)容:");
        panel.add(label);

        tf_send = new JTextField();
        tf_send.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                send();// 調(diào)用方法發(fā)送信息
            }
        });
        tf_send.setPreferredSize(new Dimension(180, 25));
        panel.add(tf_send);

        final JButton button = new JButton();
        button.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                send();// 調(diào)用方法發(fā)送信息
            }
        });
        button.setText("發(fā)  送");
        panel.add(button);

        final JSplitPane splitPane = new JSplitPane();
        splitPane.setDividerLocation(100);
        getContentPane().add(splitPane, BorderLayout.CENTER);

        final JScrollPane scrollPane = new JScrollPane();
        splitPane.setRightComponent(scrollPane);

        ta_info = new JTextArea();
        ta_info.setFont(new Font("", Font.BOLD, 14));
        scrollPane.setViewportView(ta_info);

        final JScrollPane scrollPane_1 = new JScrollPane();
        splitPane.setLeftComponent(scrollPane_1);

        user_list = new JList();
        user_list.setModel(new DefaultComboBoxModel(new String[] { "" }));
        scrollPane_1.setViewportView(user_list);

        final JPanel panel_1 = new JPanel();
        getContentPane().add(panel_1, BorderLayout.NORTH);

        final JLabel label_1 = new JLabel();
        label_1.setText("用戶名稱:");
        panel_1.add(label_1);

        tf_newUser = new JTextField();
        tf_newUser.setPreferredSize(new Dimension(140, 25));
        panel_1.add(tf_newUser);

        final JButton button_1 = new JButton();
        button_1.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                if (loginFlag) {// 已登錄標(biāo)記為true
                    JOptionPane.showMessageDialog(null, "在同一窗口只能登錄一次。");
                    return;
                }
                String userName = tf_newUser.getText().trim();// 獲得登錄用戶名
                Vector v = new Vector();// 定義向量,用于存儲(chǔ)登錄用戶
                v.add("用戶:" + userName);// 添加登錄用戶
                try {
                    out.writeObject(v);// 將用戶向量發(fā)送到服務(wù)器
                    out.flush();// 刷新輸出緩沖區(qū)
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                tf_newUser.setEnabled(false);// 禁用用戶文本框
                loginFlag = true;// 將已登錄標(biāo)記設(shè)置為true
            }
        });
        button_1.setText("登  錄");
        panel_1.add(button_1);

        final JButton button_2 = new JButton();
        button_2.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                String exitUser = tf_newUser.getText().trim();
                Vector v = new Vector();
                v.add("退出:" + exitUser);
                try {
                    out.writeObject(v);
                    out.flush();// 刷新輸出緩沖區(qū)
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                System.exit(0);                                     // 退出系統(tǒng)
            }
        });
        button_2.setText("退  出");
        panel_1.add(button_2);
        //托盤
        if (SystemTray.isSupported()){                                      // 判斷是否支持系統(tǒng)托盤
            URL url= ResourceUtil.getResource("client.png",null);         // 獲取圖片所在的URL
            ImageIcon icon = new ImageIcon(url);                            // 實(shí)例化圖像對象
            Image image=icon.getImage();                                    // 獲得Image對象
            TrayIcon trayIcon=new TrayIcon(image);                          // 創(chuàng)建托盤圖標(biāo)
            trayIcon.addMouseListener(new MouseAdapter(){                   // 為托盤添加鼠標(biāo)適配器
                public void mouseClicked(MouseEvent e){                     // 鼠標(biāo)事件
                    if (e.getClickCount()==2){                              // 判斷是否雙擊了鼠標(biāo)
                        showFrame();                                    // 調(diào)用方法顯示窗體
                    }
                }
            });
            trayIcon.setToolTip("系統(tǒng)托盤");                                    // 添加工具提示文本
            PopupMenu popupMenu=new PopupMenu();                    // 創(chuàng)建彈出菜單
            MenuItem exit=new MenuItem("退出");                           // 創(chuàng)建菜單項(xiàng)
            exit.addActionListener(new ActionListener() {                   // 添加事件監(jiān)聽器
                public void actionPerformed(final ActionEvent arg0) {
                    String exitUser = tf_newUser.getText().trim();
                    Vector v = new Vector();
                    v.add("退出:" + exitUser);
                    try {
                        out.writeObject(v);
                        out.flush();// 刷新輸出緩沖區(qū)
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                    System.exit(0);                                     // 退出系統(tǒng)
                }
            });
            popupMenu.add(exit);                                        // 為彈出菜單添加菜單項(xiàng)
            trayIcon.setPopupMenu(popupMenu);                           // 為托盤圖標(biāo)加彈出菜彈
            SystemTray systemTray=SystemTray.getSystemTray();           // 獲得系統(tǒng)托盤對象
            try{
                systemTray.add(trayIcon);                               // 為系統(tǒng)托盤加托盤圖標(biāo)
            }catch(Exception e){
                e.printStackTrace();
            }
        }

    }
    public void showFrame(){
        this.setVisible(true);                                              // 顯示窗體
        this.setState(Frame.NORMAL);
    }

}

上一題服務(wù)端啟動(dòng):

第一個(gè)客戶端:小小 啟動(dòng)

第二個(gè)客戶端:虛虛 啟動(dòng)

第三個(gè)客戶端:竹竹 啟動(dòng)

小小給竹竹發(fā)消息

竹竹回復(fù)小小:

小小收到回復(fù):

以上就是Java聊天室之實(shí)現(xiàn)聊天室客戶端功能的詳細(xì)內(nèi)容,更多關(guān)于Java聊天室的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringBoot項(xiàng)目導(dǎo)入外部jar包的詳細(xì)指南

    SpringBoot項(xiàng)目導(dǎo)入外部jar包的詳細(xì)指南

    在開發(fā)SpringBoot項(xiàng)目時(shí),我們經(jīng)常需要引入一些外部的jar包來增強(qiáng)項(xiàng)目的功能,這些jar包可能不是Maven中央倉庫中的,或者我們想要使用特定版本的jar包,本文將詳細(xì)介紹如何在SpringBoot項(xiàng)目中導(dǎo)入外部jar包,需要的朋友可以參考下
    2024-10-10
  • Java多線程編程小實(shí)例模擬停車場系統(tǒng)

    Java多線程編程小實(shí)例模擬停車場系統(tǒng)

    這是一個(gè)關(guān)于Java多線程編程的例子,用多線程的思想模擬停車場管理系統(tǒng),這里分享給大家,供需要的朋友參考。
    2017-10-10
  • Object.wait()與Object.notify()的用法詳細(xì)解析

    Object.wait()與Object.notify()的用法詳細(xì)解析

    以下是對java中Object.wait()與Object.notify()的用法進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下
    2013-09-09
  • 基于RocketMQ推拉模式詳解

    基于RocketMQ推拉模式詳解

    這篇文章主要介紹了RocketMQ推拉模式的使用,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 解決Spring國際化文案占位符失效問題的方法

    解決Spring國際化文案占位符失效問題的方法

    本篇文章主要介紹了解決Spring國際化文案占位符失效問題的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-04-04
  • Java用20行代碼實(shí)現(xiàn)抖音小視頻批量轉(zhuǎn)換為gif動(dòng)態(tài)圖

    Java用20行代碼實(shí)現(xiàn)抖音小視頻批量轉(zhuǎn)換為gif動(dòng)態(tài)圖

    這篇文章主要介紹了Java用20行代碼實(shí)現(xiàn)抖音小視頻批量轉(zhuǎn)換為gif動(dòng)態(tài)圖,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • 初識(shí)Java基礎(chǔ)之?dāng)?shù)據(jù)類型與運(yùn)算符

    初識(shí)Java基礎(chǔ)之?dāng)?shù)據(jù)類型與運(yùn)算符

    Java是一種強(qiáng)類型語言,每個(gè)變量都必須聲明其數(shù)據(jù)類型,下面這篇文章主要給大家介紹了關(guān)于Java基礎(chǔ)之?dāng)?shù)據(jù)類型與運(yùn)算符的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-10-10
  • Java實(shí)現(xiàn)高并發(fā)秒殺的七種方式

    Java實(shí)現(xiàn)高并發(fā)秒殺的七種方式

    本文主要介紹了Java實(shí)現(xiàn)高并發(fā)秒殺的六種方式,包括使用緩存、數(shù)據(jù)庫樂觀鎖、數(shù)據(jù)庫悲觀鎖、分布式鎖、隊(duì)列限流、令牌桶算法和限流器,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • Java8?Stream?流常用方法合集

    Java8?Stream?流常用方法合集

    這篇文章主要介紹了?Java8?Stream?流常用方法合集,Stream?是?Java8?中處理集合的關(guān)鍵抽象概念,它可以指定你希望對集合進(jìn)行的操作,可以執(zhí)行非常復(fù)雜的查找、過濾和映射數(shù)據(jù)等操作,下文相關(guān)資料,需要的朋友可以參考一下
    2022-04-04
  • 如何利用反射生成?MyBatisPlus中QueryWrapper動(dòng)態(tài)條件

    如何利用反射生成?MyBatisPlus中QueryWrapper動(dòng)態(tài)條件

    這篇文章主要介紹了如何利用反射生成?MyBatisPlus中QueryWrapper動(dòng)態(tài)條件,分享在MyBatisPlus中經(jīng)常會(huì)用到代碼來構(gòu)造查詢條件等內(nèi)容,需要的小伙伴可以參考一下
    2022-02-02

最新評論