• im即时通讯系统源码/如何搭建一个自己的im即时通讯呢?


    ​一,思路梳理

    1,首先思考群聊的实现方式。

    每当一个用户使用websocket建立连接时,都会存放一个连接对象(在connectMap集合存放,键为sessionId,值为该连接对象),每次当用户发送一条数据时,都会遍历connectMap中所有的连接对象,然后进行广播发送消息,接收消息也是,谁的消息都收,来之不拒,所以此为群聊。

     

    ​2,再来举一反三,思考单聊的实现方式。

    单聊的话,要改变下面几个地方。

    1,存放connectMap连接对象时,值要为userId(唯一标识)。

    2,使用websocket建立连接时要把自己的userId(发送人)和对方的userId(接收人)传到后台,因为发消息时,根据userId得到连接对象,并使用连接对象发消息到对方的窗口和自己的窗口。

    3,在js获取消息的地方要判断该消息的发送人userId是否和初始化时的接收人userId一致,如果一致的话则将消息添加到自己的窗口进行显示,如果不一致则不显示。

    有一个地方需要提一下,比如要给A用户发送消息,就要根据A的userId得到连接对象,然后就会把消息发送给A用户。演示:ym.fzapp.top

    二,代码分析

    1,首先是用户聊天框的js代码(html忽略)

    此为用户点击在线客服按钮进入聊天框页面就执行的js代码。

    说明:下面接收人id写死了为超级管理员,我这里省事情了,因为超级管理员的账号(也就是唯一标识)就是超级管理员这五个字,当真正开发时就要动态获取唯一标识了!

    2,其次为后台系统客服聊天框的js代码

    3,最后为服务端的websocket实例

    1. package com.qianlong.controller;
    2. import com.qianlong.service.SelectService;
    3. import org.springframework.beans.factory.annotation.Autowired;
    4. import org.springframework.stereotype.Component;
    5. import java.io.IOException;
    6. import java.text.SimpleDateFormat;
    7. import java.util.Date;
    8. import java.util.HashMap;
    9. import java.util.Map;
    10. import javax.websocket.OnClose;
    11. import javax.websocket.OnMessage;
    12. import javax.websocket.OnOpen;
    13. import javax.websocket.Session;
    14. import javax.websocket.server.PathParam;
    15. import javax.websocket.server.ServerEndpoint;
    16. /**
    17. * 聊天室的服务端程序
    18. * @author Administrator
    19. *
    20. */
    21. //声明websocket某个服务端的地址
    22. @ServerEndpoint(value = "/charRoomServer/{param}")
    23. @Component
    24. public class ChatRoomServer {
    25. @Autowired
    26. public static SelectService selectService;
    27. private boolean firstFlag=true;
    28. private Session session;
    29. private String userName;
    30. //发送人id
    31. private String userId;
    32. //key代表此次客户端的userId,value代表此次连接对象
    33. private static final HashMap connectMap=new HashMap();
    34. //保存所有用户昵称信息
    35. //key是session的id,value是用户昵称
    36. private static final HashMap userMap=new HashMap();
    37. //服务端收到客户端的连接请求,连接成功后会执行此方法
    38. @OnOpen
    39. public void start(@PathParam(value = "param") String param, Session session) {
    40. this.session=session;
    41. this.userId=param; //接收参数
    42. connectMap.put(param,this);
    43. }
    44. //客户端发来的信息,服务端接收
    45. @OnMessage //接收人userId
    46. public void chat(String clientMessage,Session session) {
    47. //firstFlag为true是第一次进入,第二次进入之后设为false
    48. ChatRoomServer client=null;
    49. if(firstFlag) {
    50. this.userName=clientMessage;
    51. //将新进来的用户保存到用户map
    52. userMap.put(session.getId(), userName);
    53. try {
    54. if("超级管理员".equals(userId)){
    55. }else{
    56. //构造发送给客户端的提示信息
    57. String message=htmlMessage("大白机器人:","亲爱的"+userId+",您想了解点儿啥?");
    58. client=(ChatRoomServer) connectMap.get(userId);
    59. //给对应的web端发送一个文本信息
    60. client.session.getBasicRemote().sendText(message);
    61. }
    62. } catch (IOException e) {
    63. e.printStackTrace();
    64. }
    65. firstFlag=false;
    66. }else {
    67. System.err.println("clientMessage:"+userName);
    68. //给对方发消息
    69. String message1=htmlMessage(userId,clientMessage);
    70. client = (ChatRoomServer) connectMap.get(userName);
    71. if(client!=null){
    72. try {
    73. client.session.getBasicRemote().sendText(message1);
    74. } catch (IOException e) {
    75. e.printStackTrace();
    76. }
    77. }
    78. //给自己窗口发消息
    79. String message2=htmlMessage(userId,clientMessage);
    80. client = (ChatRoomServer) connectMap.get(userId);
    81. try {
    82. client.session.getBasicRemote().sendText(message2);
    83. } catch (IOException e) {
    84. e.printStackTrace();
    85. }
    86. //这是将前台用户发送的消息存数据库并标记为未读,和上面通信没关系
    87. if("超级管理员".equals(userId)){
    88. }else{
    89. Map map=new HashMap();
    90. map.put("account",userId);
    91. map.put("message",clientMessage);
    92. map.put("addtime",new Date());
    93. int i = selectService.chatInsert(map);
    94. System.out.println(i);
    95. }
    96. }
    97. }
    98. /**
    99. * 前台js的ws.close事件,会触发后台的标注onClose的方法
    100. */
    101. @OnClose
    102. public void close() {
    103. userMap.remove(session.getId());
    104. connectMap.remove(userId);
    105. }
    106. /**
    107. * 渲染页面,把信息构造好标签再发送
    108. */
    109. public String htmlMessage(String userName,String message) {
    110. StringBuffer stringBuffer=new StringBuffer();
    111. SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    112. stringBuffer.append("
      ");
    113. stringBuffer.append(""+sf.format(new Date())+"");
    114. stringBuffer.append("
      ");
    115. stringBuffer.append("

      "+userName+"

      "
      );
    116. stringBuffer.append("
      ");
  • stringBuffer.append("
    ");
  • stringBuffer.append("
    "
    );
  • stringBuffer.append("
    "+message+"
    "
    );
  • stringBuffer.append("
    ");
  • stringBuffer.append("");
  • //这里拼接了消息发送人的userId,在前台进行截取字符串接收发送人的userId
  • stringBuffer.append("|"+userName);
  • return stringBuffer.toString();
  • }
  • }
  • 三,依赖注入

    websocket中进行依赖注入service并调用service方法进行数据库存储,如果按常规的方式是走不通的。

    解决方式:

    在该springboot项目中添加一个WebsocketConfig配置类,对service进行配置。

    1. @Configuration
    2. public class WebSocketConfig {
    3. /**
    4. * ServerEndpointExporter 用于扫描和注册所有携带 ServerEndPoint 注解的实例,
    5. * 若部署到外部容器 则无需提供此类。
    6. */
    7. @Bean
    8. public ServerEndpointExporter serverEndpointExporter() {
    9. return new ServerEndpointExporter();
    10. }
    11. /**
    12. * 因 SpringBoot WebSocket 对每个客户端连接都会创建一个 WebSocketServer(@ServerEndpoint 注解对应的对象,Bean 注入操作会被直接略过,因而手动注入一个全局变量
    13. */
    14. @Autowired
    15. public void setSelectService(SelectService selectService) {
    16. ChatRoomServer.selectService = selectService;
    17. }
    18. }

    然后在websocket中注入service

    在这里插入图片描述

    在这里插入图片描述

    四,效果展示

    进到聊天框中(左下角的用户名忽略,因为上面通过截取字符串得到的发送人userId,所以这里多了一个userId)

    登录之后会提示未读消息的信息。

    点击客服管理,进入客服聊天平台,并显示消息未读数。

    这是给123456用户发送的消息,其他用户也是收不到的。

    查看123456用户的聊天框内容,可以收到客服的消息,然后该用户可以和客服实现在线单聊。

    本次websocket讲解到此结束,谢谢观赏!

  • 相关阅读:
    web前端——简单的网页布局案列
    JVM判断对象是否存活之引用计数法、可达性分析
    用 Go 快速开发一个 RESTful API 服务
    java计算机毕业设计文物管理系统源程序+mysql+系统+lw文档+远程调试
    神经网络系列---损失函数
    matlab使用NCL提供的colormap
    初次接触氛围系统架构,聊聊我这三个月的理解
    Java系列之:var关键字
    CVPR 2024 截稿时间
    [JSOI2007] 建筑抢修
  • 原文地址:https://blog.csdn.net/q906270629/article/details/126248811