当前位置:   article > 正文

java仿qq聊天系统 多人聊天室_java多人聊天系统

java多人聊天系统

目录

项目介绍

项目截图

服务器与客户端

新用户注册

注册新账号成功 

进入聊天室

多人在线

选择发送文件

文件接收提醒

 项目代码参考

服务器入口程序

 服务器请求处理

原理解析

服务器多人网络连接:

如何实现窗口抖动

获取源码


项目介绍

使用 java swing 开发多人聊天室,分为服务端和客户端,属于BS架构。

功能包括:注册、登录、单聊、群聊、窗口抖动、发送文件、选头像。

服务器:可以看到全部已注册用户的列表,用户登录之后也可以在服务器看到在线信息。

客户端:可以注册新用户,注册时可以填写昵称、密码、性别、头像。

登录成功之后会进入聊天室,在聊天室可以看到其他在线用户,也可以选择某个具体用户进行单聊。

也可以给其他用户发送窗口抖动。

也可以给其他用户发送文件。

项目截图

服务器与客户端

新用户注册

可以选择头像

注册新账号成功 

进入聊天室

多人在线

选择发送文件

文件接收提醒

 项目代码参考

服务器入口程序

这是服务器启动的主程序,在这里监听了网络端口,循环接收客户端的连接请求。

  1. package server;
  2. import java.io.IOException;
  3. import java.net.*;
  4. import javax.swing.*;
  5. import server.controller.RequestProcessor;
  6. import server.ui.ServerInfoFrame;
  7. /** 服务器入口程序 */
  8. public class ServerMain {
  9. public static void main(String[] args) {
  10. try {//设置外观样式
  11. UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
  12. } catch (Exception e) {
  13. e.printStackTrace();
  14. }
  15. int port = Integer.parseInt(DataBuffer.configProp.getProperty("port"));
  16. //初始化服务器套节字
  17. try {
  18. DataBuffer.serverSocket = new ServerSocket(port);
  19. } catch (IOException e) {
  20. e.printStackTrace();
  21. }
  22. new Thread(new Runnable() {//启动新线程进行客户端连接监听
  23. public void run() {
  24. try {
  25. while (true) {
  26. // 监听客户端的连接
  27. Socket socket = DataBuffer.serverSocket.accept();
  28. System.out.println("客户来了:"
  29. + socket.getInetAddress().getHostAddress()
  30. + ":" + socket.getPort());
  31. //针对每个客户端启动一个线程,在线程中调用请求处理器来处理每个客户端的请求
  32. new Thread(new RequestProcessor(socket)).start();
  33. }
  34. } catch (IOException e) {
  35. e.printStackTrace();
  36. }
  37. }
  38. }).start();
  39. //启动服务器监控窗体
  40. new ServerInfoFrame();
  41. }
  42. }

 服务器请求处理

服务器对收到的消息进行处理,例如注册、登录、窗口震动、发送文件、接收文件、聊天、拒收文件,以及其他类型的消息都在这进行处理。

  1. package server.controller;
  2. import java.io.*;
  3. import java.net.Socket;
  4. import java.text.*;
  5. import java.util.concurrent.CopyOnWriteArrayList;
  6. import server.*;
  7. import server.model.service.UserService;
  8. import common.model.entity.*;
  9. /** 服务器端请求处理器 */
  10. public class RequestProcessor implements Runnable{
  11. private Socket currentClientSocket; //当前正在请求服务器的客户端Socket
  12. public RequestProcessor(Socket currentClientSocket){
  13. this.currentClientSocket = currentClientSocket;
  14. }
  15. public void run() {
  16. boolean flag = true; //是否不间断监听
  17. try{
  18. OnlineClientIOCache currentClientIOCache = new OnlineClientIOCache(
  19. new ObjectInputStream(currentClientSocket.getInputStream()),
  20. new ObjectOutputStream(currentClientSocket.getOutputStream()));
  21. while(flag){ //不停地读取客户端发过来的请求对象
  22. //从请求输入流中读取到客户端提交的请求对象
  23. Request request = (Request)currentClientIOCache.getOis().readObject();
  24. System.out.println("Server读取了客户端的请求:" + request.getAction());
  25. String actionName = request.getAction(); //获取请求中的动作
  26. if(actionName.equals("userRegiste")){ //用户注册
  27. registe(currentClientIOCache, request);
  28. }else if(actionName.equals("userLogin")){ //用户登录
  29. login(currentClientIOCache, request);
  30. }else if("exit".equals(actionName)){ //请求断开连接
  31. flag = logout(currentClientIOCache, request);
  32. }else if("chat".equals(actionName)){ //聊天
  33. chat(request);
  34. }else if("shake".equals(actionName)){ //振动
  35. shake(request);
  36. }else if("toSendFile".equals(actionName)){ //准备发送文件
  37. toSendFile(request);
  38. }else if("agreeReceiveFile".equals(actionName)){ //同意接收文件
  39. agreeReceiveFile(request);
  40. }else if("refuseReceiveFile".equals(actionName)){ //拒绝接收文件
  41. refuseReceiveFile(request);
  42. }
  43. }
  44. }catch(Exception e){
  45. e.printStackTrace();
  46. }
  47. }
  48. /** 拒绝接收文件 */
  49. private void refuseReceiveFile(Request request) throws IOException {
  50. FileInfo sendFile = (FileInfo)request.getAttribute("sendFile");
  51. Response response = new Response(); //创建一个响应对象
  52. response.setType(ResponseType.REFUSERECEIVEFILE);
  53. response.setData("sendFile", sendFile);
  54. response.setStatus(ResponseStatus.OK);
  55. //向请求方的输出流输出响应
  56. OnlineClientIOCache ocic = DataBuffer.onlineUserIOCacheMap.get(sendFile.getFromUser().getId());
  57. this.sendResponse(ocic, response);
  58. }
  59. /** 同意接收文件 */
  60. private void agreeReceiveFile(Request request) throws IOException {
  61. FileInfo sendFile = (FileInfo)request.getAttribute("sendFile");
  62. //向请求方(发送方)的输出流输出响应
  63. Response response = new Response(); //创建一个响应对象
  64. response.setType(ResponseType.AGREERECEIVEFILE);
  65. response.setData("sendFile", sendFile);
  66. response.setStatus(ResponseStatus.OK);
  67. OnlineClientIOCache sendIO = DataBuffer.onlineUserIOCacheMap.get(sendFile.getFromUser().getId());
  68. this.sendResponse(sendIO, response);
  69. //向接收方发出接收文件的响应
  70. Response response2 = new Response(); //创建一个响应对象
  71. response2.setType(ResponseType.RECEIVEFILE);
  72. response2.setData("sendFile", sendFile);
  73. response2.setStatus(ResponseStatus.OK);
  74. OnlineClientIOCache receiveIO = DataBuffer.onlineUserIOCacheMap.get(sendFile.getToUser().getId());
  75. this.sendResponse(receiveIO, response2);
  76. }
  77. /** 客户端退出 */
  78. public boolean logout(OnlineClientIOCache oio, Request request) throws IOException{
  79. System.out.println(currentClientSocket.getInetAddress().getHostAddress()
  80. + ":" + currentClientSocket.getPort() + "走了");
  81. User user = (User)request.getAttribute("user");
  82. //把当前上线客户端的IO从Map中删除
  83. DataBuffer.onlineUserIOCacheMap.remove(user.getId());
  84. //从在线用户缓存Map中删除当前用户
  85. DataBuffer.onlineUsersMap.remove(user.getId());
  86. Response response = new Response(); //创建一个响应对象
  87. response.setType(ResponseType.LOGOUT);
  88. response.setData("logoutUser", user);
  89. oio.getOos().writeObject(response); //把响应对象往客户端写
  90. oio.getOos().flush();
  91. currentClientSocket.close(); //关闭这个客户端Socket
  92. DataBuffer.onlineUserTableModel.remove(user.getId()); //把当前下线用户从在线用户表Model中删除
  93. iteratorResponse(response);//通知所有其它在线客户端
  94. return false; //断开监听
  95. }
  96. /** 注册 */
  97. public void registe(OnlineClientIOCache oio, Request request) throws IOException {
  98. User user = (User)request.getAttribute("user");
  99. UserService userService = new UserService();
  100. userService.addUser(user);
  101. Response response = new Response(); //创建一个响应对象
  102. response.setStatus(ResponseStatus.OK);
  103. response.setData("user", user);
  104. oio.getOos().writeObject(response); //把响应对象往客户端写
  105. oio.getOos().flush();
  106. //把新注册用户添加到RegistedUserTableModel中
  107. DataBuffer.registedUserTableModel.add(new String[]{
  108. String.valueOf(user.getId()),
  109. user.getPassword(),
  110. user.getNickname(),
  111. String.valueOf(user.getSex())
  112. });
  113. }
  114. /** 登录 */
  115. public void login(OnlineClientIOCache currentClientIO, Request request) throws IOException {
  116. String idStr = (String)request.getAttribute("id");
  117. String password = (String) request.getAttribute("password");
  118. UserService userService = new UserService();
  119. User user = userService.login(Long.parseLong(idStr), password);
  120. Response response = new Response(); //创建一个响应对象
  121. if(null != user){
  122. if(DataBuffer.onlineUsersMap.containsKey(user.getId())){ //用户已经登录了
  123. response.setStatus(ResponseStatus.OK);
  124. response.setData("msg", "该 用户已经在别处上线了!");
  125. currentClientIO.getOos().writeObject(response); //把响应对象往客户端写
  126. currentClientIO.getOos().flush();
  127. }else { //正确登录
  128. DataBuffer.onlineUsersMap.put(user.getId(), user); //添加到在线用户
  129. //设置在线用户
  130. response.setData("onlineUsers",
  131. new CopyOnWriteArrayList<User>(DataBuffer.onlineUsersMap.values()));
  132. response.setStatus(ResponseStatus.OK);
  133. response.setData("user", user);
  134. currentClientIO.getOos().writeObject(response); //把响应对象往客户端写
  135. currentClientIO.getOos().flush();
  136. //通知其它用户有人上线了
  137. Response response2 = new Response();
  138. response2.setType(ResponseType.LOGIN);
  139. response2.setData("loginUser", user);
  140. iteratorResponse(response2);
  141. //把当前上线的用户IO添加到缓存Map中
  142. DataBuffer.onlineUserIOCacheMap.put(user.getId(),currentClientIO);
  143. //把当前上线用户添加到OnlineUserTableModel中
  144. DataBuffer.onlineUserTableModel.add(
  145. new String[]{String.valueOf(user.getId()),
  146. user.getNickname(),
  147. String.valueOf(user.getSex())});
  148. }
  149. }else{ //登录失败
  150. response.setStatus(ResponseStatus.OK);
  151. response.setData("msg", "账号或密码不正确!");
  152. currentClientIO.getOos().writeObject(response);
  153. currentClientIO.getOos().flush();
  154. }
  155. }
  156. /** 聊天 */
  157. public void chat(Request request) throws IOException {
  158. Message msg = (Message)request.getAttribute("msg");
  159. Response response = new Response();
  160. response.setStatus(ResponseStatus.OK);
  161. response.setType(ResponseType.CHAT);
  162. response.setData("txtMsg", msg);
  163. if(msg.getToUser() != null){ //私聊:只给私聊的对象返回响应
  164. OnlineClientIOCache io = DataBuffer.onlineUserIOCacheMap.get(msg.getToUser().getId());
  165. sendResponse(io, response);
  166. }else{ //群聊:给除了发消息的所有客户端都返回响应
  167. for(Long id : DataBuffer.onlineUserIOCacheMap.keySet()){
  168. if(msg.getFromUser().getId() == id ){ continue; }
  169. sendResponse(DataBuffer.onlineUserIOCacheMap.get(id), response);
  170. }
  171. }
  172. }
  173. /** 发送振动 */
  174. public void shake(Request request)throws IOException {
  175. Message msg = (Message)request.getAttribute("msg");
  176. DateFormat df = new SimpleDateFormat("HH:mm:ss");
  177. StringBuffer sb = new StringBuffer();
  178. sb.append(" ").append(msg.getFromUser().getNickname())
  179. .append("(").append(msg.getFromUser().getId()).append(") ")
  180. .append(df.format(msg.getSendTime())).append("\n 给您发送了一个窗口抖动\n");
  181. msg.setMessage(sb.toString());
  182. Response response = new Response();
  183. response.setStatus(ResponseStatus.OK);
  184. response.setType(ResponseType.SHAKE);
  185. response.setData("ShakeMsg", msg);
  186. OnlineClientIOCache io = DataBuffer.onlineUserIOCacheMap.get(msg.getToUser().getId());
  187. sendResponse(io, response);
  188. }
  189. /** 准备发送文件 */
  190. public void toSendFile(Request request)throws IOException{
  191. Response response = new Response();
  192. response.setStatus(ResponseStatus.OK);
  193. response.setType(ResponseType.TOSENDFILE);
  194. FileInfo sendFile = (FileInfo)request.getAttribute("file");
  195. response.setData("sendFile", sendFile);
  196. //给文件接收方转发文件发送方的请求
  197. OnlineClientIOCache ioCache = DataBuffer.onlineUserIOCacheMap.get(sendFile.getToUser().getId());
  198. sendResponse(ioCache, response);
  199. }
  200. /** 给所有在线客户都发送响应 */
  201. private void iteratorResponse(Response response) throws IOException {
  202. for(OnlineClientIOCache onlineUserIO : DataBuffer.onlineUserIOCacheMap.values()){
  203. ObjectOutputStream oos = onlineUserIO.getOos();
  204. oos.writeObject(response);
  205. oos.flush();
  206. }
  207. }
  208. /** 向指定客户端IO的输出流中输出指定响应 */
  209. private void sendResponse(OnlineClientIOCache onlineUserIO, Response response)throws IOException {
  210. ObjectOutputStream oos = onlineUserIO.getOos();
  211. oos.writeObject(response);
  212. oos.flush();
  213. }
  214. }

原理解析

服务器多人网络连接:

首先来分析一下要实现的流程

  •  首先建立一个服务器端,构建serversocket并绑定端口
  •  创建socket客户端,连接到指定ip以及其端口
  •  然后使用accept阻塞接收socket发出的连接请求
  • 接收到的socket对象需要使用thread单独处理,
  • 每个用户分配单独的线程进行读写处理
  •  根据输入流和输出流进行两者数据的通信
  •  获取连接后的socket客户端的输入流和输出流

值得一提是:该socket是同步阻塞的,因此在socket客户端需要进行创建一个线程,来分别进行向服务器输出,和接收服务器传输的数据。

如何实现窗口抖动

窗口的左上角是原点,我们首先记录起始坐标,计算出向左上角移动的距离和右下角移动的距离,通过循环语句控制窗口位移,最终将窗口恢复到起始坐标。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/99183
推荐阅读
相关标签
  

闽ICP备14008679号