当前位置:   article > 正文

WebSocket实现聊天室功能(springboot+vue3+vite)_websocket聊天室

websocket聊天室

1、项目展示图

登录

登录成功

互动

2、websocket介绍

websocket是一种全双工的连接,即服务器和客户端之间建立了一次连接后,两者之间就会一直打开这个通道,就可以相互进行通信。相对于传统单双工的http请求,节省很多资源,不需要一直轮询服务器。

3、springboot代码(主要是写websocket相关的方法,比如创建连接事件,接收消息以及发送消息事件,关闭连接事件)

  1. package com.example.message.WebSocket;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.gcp.basicproject.util.ParamUtil;
  5. import org.slf4j.Logger;
  6. import org.slf4j.LoggerFactory;
  7. import org.springframework.context.ApplicationContext;
  8. import org.springframework.stereotype.Component;
  9. import javax.websocket.OnClose;
  10. import javax.websocket.OnMessage;
  11. import javax.websocket.OnOpen;
  12. import javax.websocket.Session;
  13. import javax.websocket.server.PathParam;
  14. import javax.websocket.server.ServerEndpoint;
  15. import java.io.IOException;
  16. import java.util.concurrent.ConcurrentHashMap;
  17. /**
  18. * @author Admin
  19. */
  20. @ServerEndpoint("/chat/{name}")
  21. @Component
  22. public class AllWebSocketService {
  23. static Logger log = LoggerFactory.getLogger(AllWebSocketService.class);
  24. private static int onlineCount = 0;
  25. private static ConcurrentHashMap<String,AllWebSocketService> webSocketServerMap = new ConcurrentHashMap<>();
  26. private Session session;
  27. private String name = "";
  28. private static ApplicationContext applicationContext;
  29. /**
  30. * 解决引入外部类方法
  31. * @param context
  32. */
  33. public static void setApplicationContext(ApplicationContext context){
  34. applicationContext = context;
  35. }
  36. /**
  37. * 建立连接
  38. * @param session
  39. * @param name
  40. */
  41. @OnOpen
  42. public void onOpen(Session session,@PathParam("name") String name){
  43. this.session = session;
  44. webSocketServerMap.put(name,this);
  45. this.name = name;
  46. addOnlineCount();
  47. log.info("用户连接:"+name+",当前在线人数为:"+getOnlineCount());
  48. try{
  49. sendMessage("进入聊天室成功");
  50. }catch (IOException e){
  51. log.error("用户:"+name+",连接失败!!");
  52. }
  53. }
  54. /**
  55. * 关闭连接
  56. */
  57. @OnClose
  58. public void onClose(){
  59. subOnlineCount();
  60. webSocketServerMap.remove(name);
  61. log.info("用户退出:"+name+",当前在线人数为:"+getOnlineCount());
  62. }
  63. @OnMessage
  64. public void onMessage(String message){
  65. log.info("用户消息:"+name+",报文:"+message);
  66. if(ParamUtil.notEmpty(message)){
  67. log.info(message);
  68. JSONObject jsonObject = JSON.parseObject(message);
  69. jsonObject.put("name",this.name);
  70. webSocketServerMap.forEach((u,m)->{
  71. if(name.contains(u)){
  72. return;
  73. }
  74. try {
  75. m.sendMessage(jsonObject.toJSONString());
  76. } catch (IOException e) {
  77. e.printStackTrace();
  78. }
  79. });
  80. }
  81. }
  82. /**
  83. * 服务器推送消息
  84. * @param message
  85. * @throws IOException
  86. */
  87. public void sendMessage(String message) throws IOException {
  88. this.session.getBasicRemote().sendText(message);
  89. }
  90. /**
  91. * 获取在线人数
  92. * @return
  93. */
  94. public static synchronized int getOnlineCount(){
  95. return onlineCount;
  96. }
  97. /**
  98. * 上线
  99. */
  100. public static synchronized void addOnlineCount(){
  101. AllWebSocketService.onlineCount++;
  102. }
  103. /**
  104. * 离线
  105. */
  106. public static synchronized void subOnlineCount(){
  107. AllWebSocketService.onlineCount--;
  108. }
  109. }

4、vue代码(主要是写连接本地的websocket,接收、发送和显示消息)

  1. <!-- 聊天室 -->
  2. <template>
  3. <h1>聊天室</h1>
  4. <el-scrollbar height="400px" style="border:1px solid #1813131f">
  5. <el-tag v-for="item in list" :key="item" class="scrollbar-demo-item" :style="`justify-content: ${item.type}`">{{
  6. item.name
  7. }}:{{ item.content }}</el-tag>
  8. </el-scrollbar>
  9. 发送消息:<el-input v-model="msg"></el-input>
  10. <el-button @click="sendMesage(msg)">发送消息</el-button>
  11. <el-button text @click="dialogFormVisible = true">登录</el-button>
  12. <el-dialog v-model="dialogFormVisible" title="登录">
  13. 请输入用户昵称:
  14. <el-input v-model="name" autocomplete="off" />
  15. <template #footer>
  16. <span class="dialog-footer">
  17. <el-button type="primary" @click="login()">确认</el-button>
  18. </span>
  19. </template>
  20. </el-dialog>
  21. <router-link to="/">返回首页</router-link>
  22. </template>
  23. <script>
  24. import { onBeforeUnmount, reactive, ref } from 'vue'
  25. import { ElMessage } from 'element-plus'
  26. export default {
  27. name: "chat",
  28. setup() {
  29. const list = reactive([]);
  30. let socket = null;
  31. // Websoket连接成功事件
  32. const websocketonopen = (res) => {
  33. ElMessage.success("WebSocket连接成功");
  34. };
  35. // Websoket接收消息事件
  36. const websocketonmessage = (res) => {
  37. if (res.data) {
  38. ElMessage.success("接收到消息:" + JSON.parse(res.data).content);
  39. message.content = JSON.parse(res.data).content;
  40. message.name = JSON.parse(res.data).name;
  41. message.type = 'left';
  42. list.push(JSON.parse(JSON.stringify(message)));
  43. console.log(list);
  44. }
  45. };
  46. // Websoket连接错误事件
  47. const websocketonerror = (res) => {
  48. ElMessage.error("连接错误");
  49. };
  50. // Websoket断开事件
  51. const websocketclose = (res) => {
  52. ElMessage.error("断开连接");
  53. };
  54. let message = reactive(
  55. {
  56. name: "",
  57. content: "",
  58. type: ''
  59. }
  60. );
  61. let msg = ref("");
  62. let name = ref("");
  63. const dialogFormVisible = ref(false);
  64. const sendMesage = (m) => {
  65. if (name.value == "") {
  66. ElMessage.warning("未登录,无法发送消息");
  67. } else {
  68. ElMessage.success("发送消息:" + m)
  69. message.content = m;
  70. message.name = name.value;
  71. message.type = 'right';
  72. socket.send(JSON.stringify(message));
  73. //解决message对象只有一个,push修改所有message对象的问题
  74. list.push(JSON.parse(JSON.stringify(message)));
  75. console.log(list);
  76. }
  77. }
  78. // 创建 websocket 的实例
  79. const createSocket = () => {
  80. const wsurl = "ws://localhost:8075/chat/" + name.value;
  81. socket = new WebSocket(wsurl);
  82. socket.onopen = websocketonopen;
  83. socket.onmessage = websocketonmessage;
  84. socket.onerror = websocketonerror;
  85. socket.onclose = websocketclose;
  86. };
  87. //登录聊天室
  88. const login = () => {
  89. console.log(name);
  90. createSocket();
  91. dialogFormVisible.value = false;
  92. }
  93. // 组件被销毁之前,清空 sock 对象
  94. onBeforeUnmount(() => {
  95. // 关闭连接
  96. websocketclose;
  97. // 销毁 websocket 实例对象
  98. socket = null;
  99. });
  100. //建立连接,创建websocket实例
  101. return {
  102. name,
  103. list,
  104. msg,
  105. message,
  106. dialogFormVisible,
  107. sendMesage,
  108. createSocket,
  109. login
  110. };
  111. },
  112. };
  113. </script>
  114. <style scoped>
  115. .read-the-docs {
  116. color: #888;
  117. }
  118. .scrollbar-demo-item {
  119. display: flex;
  120. align-items: center;
  121. height: 30px;
  122. margin: 10px;
  123. text-align: left;
  124. border-radius: 4px;
  125. }
  126. </style>

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

闽ICP备14008679号