IT俱乐部 Java Java聊天室之实现聊天室服务端功能

Java聊天室之实现聊天室服务端功能

一、题目描述

题目实现:实现聊天室服务器端功能。运行程序,服务端等待客户端连接,并显示客户端的连接信息。

二、解题思路

创建一个服务类:ChatServerFrame,继承JFrame类

定义一个Hashtable对象,用于存储登录用户的用户名和套接字对象。

定义createSocket()方法,用于创建服务器套接字对象、获得连接到服务器的客户端套接字对象以及启动线程对象对客户端发送的信息进行处理。

定义内部线程类ServerThread用于对客户端的连接信息以及发送的信息进行处理和转发。

技术重点:

本实例使用Hashtable类来存储连接到服务器的用户名和套接字对象,并使用String类的 startWith()方法判断客户端发送信息的类型,从而实现了向服务器端添加登录用户、发送退出信息、通过服务器转发客户端发送的信息等功能,最终完成了聊天室服务器端程序的开发。

三、代码详解

引入hutool的pom

1
cn.hutoolhutool-core5.6.5

ChatServerFrame

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
package com.xiaoxuzhu;
import cn.hutool.core.io.resource.ResourceUtil;
 
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
/**
 * Description:
 *
 * @author xiaoxuzhu
 * @version 1.0
 *
 * <pre> * 修改记录:
 * 修改后版本            修改人     修改日期            修改内容
 * 2022/6/5.1       xiaoxuzhu       2022/6/5            Create
 * </pre>
<p> * @date 2022/6/5<br>
 */</p>
<p>public class ChatServerFrame extends JFrame {<br>
    private JTextArea ta_info;<br>
    private ServerSocket server; // 声明ServerSocket对象<br>
    private Socket socket; // 声明Socket对象socket<br>
    private Hashtable map = new Hashtable();// 用于存储连接到服务器的用户和客户端套接字对象</p>
<p>    public void createSocket() {<br>
        try {<br>
            server = new ServerSocket(9527);// 创建服务器套接字对象<br>
            while (true) {<br>
                ta_info.append("等待新客户连接......n");<br>
                socket = server.accept();// 获得套接字对象<br>
                ta_info.append("客户端连接成功。" + socket + "n");<br>
                new ServerThread(socket).start();// 创建并启动线程对象<br>
            }<br>
        } catch (IOException e) {<br>
            e.printStackTrace();<br>
        }<br>
    }</p>
<p>    class ServerThread extends Thread {<br>
        Socket socket;<br>
        public ServerThread(Socket socket) {<br>
            this.socket = socket;<br>
        }<br>
        public void run() {<br>
            try {<br>
                ObjectInputStream ins = new ObjectInputStream(socket<br>
                        .getInputStream());<br>
                while (true) {<br>
                    Vector v = null;<br>
                    try {<br>
                        v = (Vector) ins.readObject();<br>
                    } catch (ClassNotFoundException e) {<br>
                        e.printStackTrace();<br>
                    }<br>
                    if (v != null && v.size() > 0) {<br>
                        for (int i = 0; i  set = map.keySet();// 获得集合中所有键的Set视图<br>
                                Iterator keyIt = set.iterator();// 获得所有键的迭代器<br>
                                while (keyIt.hasNext()) {<br>
                                    String receiveKey = keyIt.next();// 获得表示接收信息的键<br>
                                    Socket s = map.get(receiveKey);// 获得与该键对应的套接字对象<br>
                                    PrintWriter out = new PrintWriter(s<br>
                                            .getOutputStream(), true);// 创建输出流对象<br>
                                    Iterator keyIt1 = set.iterator();// 获得所有键的迭代器<br>
                                    while (keyIt1.hasNext()) {<br>
                                        String receiveKey1 = keyIt1.next();// 获得键,用于向客户端添加用户列表<br>
                                        out.println(receiveKey1);// 发送信息<br>
                                        out.flush();// 刷新输出缓冲区<br>
                                    }<br>
                                }<br>
                            } else if (info.startsWith("退出:")) {<br>
                                key = info.substring(3);// 获得退出用户的键<br>
                                map.remove(key);// 添加键值对<br>
                                Set set = map.keySet();// 获得集合中所有键的Set视图<br>
                                Iterator keyIt = set.iterator();// 获得所有键的迭代器<br>
                                while (keyIt.hasNext()) {<br>
                                    String receiveKey = keyIt.next();// 获得表示接收信息的键<br>
                                    Socket s = map.get(receiveKey);// 获得与该键对应的套接字对象<br>
                                    PrintWriter out = new PrintWriter(s<br>
                                            .getOutputStream(), true);// 创建输出流对象<br>
                                    out.println("退出:" + key);// 发送信息<br>
                                    out.flush();// 刷新输出缓冲区<br>
                                }<br>
                            } else {// 转发接收的消息<br>
                                key = info.substring(info.indexOf(":发送给:") + 5,<br>
                                        info.indexOf(":的信息是:"));// 获得接收方的key值,即接收方的用户名<br>
                                String sendUser = info.substring(0, info<br>
                                        .indexOf(":发送给:"));// 获得发送方的key值,即发送方的用户名<br>
                                Set set = map.keySet();// 获得集合中所有键的Set视图<br>
                                Iterator keyIt = set.iterator();// 获得所有键的迭代器<br>
                                while (keyIt.hasNext()) {<br>
                                    String receiveKey = keyIt.next();// 获得表示接收信息的键<br>
                                    if (key.equals(receiveKey) && !sendUser.equals(receiveKey)) {// 与接受用户相同,但不是发送用户<br>
                                        Socket s = map.get(receiveKey);// 获得与该键对应的套接字对象<br>
                                        PrintWriter out = new PrintWriter(s.getOutputStream(), true);// 创建输出流对象<br>
                                        out.println("MSG:" + info);// 发送信息<br>
                                        out.flush();// 刷新输出缓冲区<br>
                                    }<br>
                                }<br>
                            }<br>
                        }<br>
                    }<br>
                }<br>
            } catch (IOException e) {<br>
                ta_info.append(socket + "已经退出。n");<br>
            }<br>
        }<br>
    }</p>
<p>    public static void main(String args[]) {<br>
        ChatServerFrame frame = new ChatServerFrame();<br>
        frame.setVisible(true);<br>
        frame.createSocket();<br>
    }</p>
<p>    /**<br>
     * Create the frame<br>
     */<br>
    public ChatServerFrame() {<br>
        super();<br>
        addWindowListener(new WindowAdapter() {<br>
            public void windowIconified(final WindowEvent e) {<br>
                setVisible(false);<br>
            }<br>
        });<br>
        setTitle("聊天室服务器端");<br>
        setBounds(100, 100, 385, 266);</p>
<p>        final JScrollPane scrollPane = new JScrollPane();<br>
        getContentPane().add(scrollPane, BorderLayout.CENTER);</p>
<p>        ta_info = new JTextArea();<br>
        scrollPane.setViewportView(ta_info);</p>
<p>        //托盘<br>
        if (SystemTray.isSupported()){                                      // 判断是否支持系统托盘<br>
            URL url= ResourceUtil.getResource("server.png",null);         // 获取图片所在的URL<br>
            ImageIcon icon = new ImageIcon(url);                            // 实例化图像对象<br>
            Image image=icon.getImage();                                    // 获得Image对象<br>
            TrayIcon trayIcon=new TrayIcon(image);                          // 创建托盘图标<br>
            trayIcon.addMouseListener(new MouseAdapter(){                   // 为托盘添加鼠标适配器<br>
                public void mouseClicked(MouseEvent e){                     // 鼠标事件<br>
                    if (e.getClickCount()==2){                              // 判断是否双击了鼠标<br>
                        showFrame();                                    // 调用方法显示窗体<br>
                    }<br>
                }<br>
            });<br>
            trayIcon.setToolTip("系统托盘");                                    // 添加工具提示文本<br>
            PopupMenu popupMenu=new PopupMenu();                    // 创建弹出菜单<br>
            MenuItem exit=new MenuItem("退出");                           // 创建菜单项<br>
            exit.addActionListener(new ActionListener() {                   // 添加事件监听器<br>
                public void actionPerformed(final ActionEvent arg0) {<br>
                    System.exit(0);                                     // 退出系统<br>
                }<br>
            });<br>
            popupMenu.add(exit);                                        // 为弹出菜单添加菜单项<br>
            trayIcon.setPopupMenu(popupMenu);                           // 为托盘图标加弹出菜弹<br>
            SystemTray systemTray=SystemTray.getSystemTray();           // 获得系统托盘对象<br>
            try{<br>
                systemTray.add(trayIcon);                               // 为系统托盘加托盘图标<br>
            }catch(Exception e){<br>
                e.printStackTrace();<br>
            }<br>
        }<br>
    }<br>
    public void showFrame(){<br>
        this.setVisible(true);                                              // 显示窗体<br>
        this.setState(Frame.NORMAL);<br>
    }<br>
}
</p>

服务器启动

系统托盘

多学一个知识点

想把这个项目代码打成Jar包,独立运行,脱离IDEA,可以吗?

按照上一题学到的方式,来试试

1、把项目打成jar包:利用maven 的clean install

会在target目录下生成jar包

2、进入target目录,使用java -cp的命令运行指定的类

java -cp 命令中 cp 指的就是classpath。使用该命令可以运行jar中的某个指定的类(要包含全路径的包名)

进入cmd命令模式

运行服务端

java -cp basics99-1.0-SNAPSHOT.jar com.xiaoxuzhu.ChatServerFrame

看报错了

这是因为项目引用了第三方jar包,maven打jar时,只是打当前的项目的内容,没有把第三方Jar包打进去。

解决方案:

使用maven的插件 maven-assembly-plugin

pom的配置如下,可参考

1
4.0.0com.xiaoxuzhubasics991.0-SNAPSHOTcn.hutoolhutool-core5.6.5maven-assembly-plugincom.xiaoxuzhu.ChatServerFrame.jar-with-dependenciesfalsemake-assemblypackagesingle

还是使用maven 的clean install,会在target目录下生成jar包

进入target目录,进入CMD命令模式

java -jar basics99-1.0-SNAPSHOT.jar

启动效果:

到此这篇关于Java聊天室之实现聊天室服务端功能的文章就介绍到这了,更多相关Java聊天室内容请搜索IT俱乐部以前的文章或继续浏览下面的相关文章希望大家以后多多支持IT俱乐部!

本文收集自网络,不代表IT俱乐部立场,转载请注明出处。https://www.2it.club/code/java/6434.html
上一篇
下一篇
联系我们

联系我们

在线咨询: QQ交谈

邮箱: 1120393934@qq.com

工作时间:周一至周五,9:00-17:30,节假日休息

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部