当前位置:   article > 正文

springboot+vue集成websocket实现聊天功能_vue2需要实现websocket对话需要安装什么

vue2需要实现websocket对话需要安装什么

1、添加pom依赖

  1. <!-- websocket -->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-websocket</artifactId>
  5. </dependency>

2、创建一个config文件夹,在config文件夹中创建一个 WebSocketConfig.java 类

  1. import org.springframework.context.annotation.Bean;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.web.socket.server.standard.ServerEndpointExporter;
  4. @Configuration
  5. public class WebSocketConfig {
  6. /**
  7. * 注入一个ServerEndpointExporter,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
  8. */
  9. @Bean
  10. public ServerEndpointExporter serverEndpointExporter() {
  11. return new ServerEndpointExporter();
  12. }
  13. }

3、新建一个 component 文件夹,并且在 component 文件夹中新建  WebSocketServer.java 类

  1. import cn.hutool.json.JSONArray;
  2. import cn.hutool.json.JSONObject;
  3. import cn.hutool.json.JSONUtil;
  4. import org.slf4j.Logger;
  5. import org.slf4j.LoggerFactory;
  6. import org.springframework.stereotype.Component;
  7. import javax.websocket.*;
  8. import javax.websocket.server.PathParam;
  9. import javax.websocket.server.ServerEndpoint;
  10. import java.util.Map;
  11. import java.util.concurrent.ConcurrentHashMap;
  12. /**
  13. * @author websocket服务
  14. */
  15. @ServerEndpoint(value = "/imserver/{username}")
  16. @Component
  17. public class WebSocketServer {
  18. private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);
  19. /**
  20. * 记录当前在线连接数
  21. */
  22. public static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();
  23. /**
  24. * 连接建立成功调用的方法
  25. */
  26. @OnOpen
  27. public void onOpen(Session session, @PathParam("username") String username) {
  28. sessionMap.put(username, session);
  29. log.info("有新用户加入,username={}, 当前在线人数为:{}", username, sessionMap.size());
  30. JSONObject result = new JSONObject();
  31. JSONArray array = new JSONArray();
  32. result.set("users", array);
  33. for (Object key : sessionMap.keySet()) {
  34. JSONObject jsonObject = new JSONObject();
  35. jsonObject.set("username", key);
  36. // {"username", "zhang", "username": "admin"}
  37. array.add(jsonObject);
  38. }
  39. // {"users": [{"username": "zhang"},{ "username": "admin"}]}
  40. sendAllMessage(JSONUtil.toJsonStr(result)); // 后台发送消息给所有的客户端
  41. }
  42. /**
  43. * 连接关闭调用的方法
  44. */
  45. @OnClose
  46. public void onClose(Session session, @PathParam("username") String username) {
  47. sessionMap.remove(username);
  48. log.info("有一连接关闭,移除username={}的用户session, 当前在线人数为:{}", username, sessionMap.size());
  49. }
  50. /**
  51. * 收到客户端消息后调用的方法
  52. * 后台收到客户端发送过来的消息
  53. * onMessage 是一个消息的中转站
  54. * 接受 浏览器端 socket.send 发送过来的 json数据
  55. * @param message 客户端发送过来的消息
  56. */
  57. @OnMessage
  58. public void onMessage(String message, Session session, @PathParam("username") String username) {
  59. log.info("服务端收到用户username={}的消息:{}", username, message);
  60. JSONObject obj = JSONUtil.parseObj(message);
  61. String toUsername = obj.getStr("to"); // to表示发送给哪个用户,比如 admin
  62. String text = obj.getStr("text"); // 发送的消息文本 hello
  63. // {"to": "admin", "text": "聊天文本"}
  64. Session toSession = sessionMap.get(toUsername); // 根据 to用户名来获取 session,再通过session发送消息文本
  65. if (toSession != null) {
  66. // 服务器端 再把消息组装一下,组装后的消息包含发送人和发送的文本内容
  67. // {"from": "zhang", "text": "hello"}
  68. JSONObject jsonObject = new JSONObject();
  69. jsonObject.set("from", username); // from 是 zhang
  70. jsonObject.set("text", text); // text 同上面的text
  71. this.sendMessage(jsonObject.toString(), toSession);
  72. log.info("发送给用户username={},消息:{}", toUsername, jsonObject.toString());
  73. } else {
  74. log.info("发送失败,未找到用户username={}的session", toUsername);
  75. }
  76. }
  77. @OnError
  78. public void onError(Session session, Throwable error) {
  79. log.error("发生错误");
  80. error.printStackTrace();
  81. }
  82. /**
  83. * 服务端发送消息给客户端
  84. */
  85. private void sendMessage(String message, Session toSession) {
  86. try {
  87. log.info("服务端给客户端[{}]发送消息{}", toSession.getId(), message);
  88. toSession.getBasicRemote().sendText(message);
  89. } catch (Exception e) {
  90. log.error("服务端发送消息给客户端失败", e);
  91. }
  92. }
  93. /**
  94. * 服务端发送消息给所有客户端
  95. */
  96. private void sendAllMessage(String message) {
  97. try {
  98. for (Session session : sessionMap.values()) {
  99. log.info("服务端给客户端[{}]发送消息{}", session.getId(), message);
  100. session.getBasicRemote().sendText(message);
  101. }
  102. } catch (Exception e) {
  103. log.error("服务端发送消息给客户端失败", e);
  104. }
  105. }
  106. }

 4、在你的token拦截里,放行该接口

 5、新建Vue页面,Im.vue

  1. <template>
  2. <div style="padding: 10px; margin-bottom: 50px">
  3. <el-row>
  4. <el-col :span="4">
  5. <el-card style="width: 300px; height: 300px; color: #333">
  6. <div style="padding-bottom: 10px; border-bottom: 1px solid #ccc">在线用户<span style="font-size: 12px">(点击聊天气泡开始聊天)</span></div>
  7. <div style="padding: 10px 0" v-for="user in users" :key="user.username">
  8. <span>{{ user.username }}</span>
  9. <i class="el-icon-chat-dot-round" style="margin-left: 10px; font-size: 16px; cursor: pointer"
  10. @click="chatUser = user.username"></i>
  11. <span style="font-size: 12px;color: limegreen; margin-left: 5px" v-if="user.username === chatUser">chatting...</span>
  12. </div>
  13. </el-card>
  14. </el-col>
  15. <el-col :span="20">
  16. <div style="width: 800px; margin: 0 auto; background-color: white;
  17. border-radius: 5px; box-shadow: 0 0 10px #ccc">
  18. <div style="text-align: center; line-height: 50px;">
  19. Web聊天室({{ chatUser }})
  20. </div>
  21. <div style="height: 350px; overflow:auto; border-top: 1px solid #ccc" v-html="content"></div>
  22. <div style="height: 200px">
  23. <textarea v-model="text" style="height: 160px; width: 100%; padding: 20px; border: none; border-top: 1px solid #ccc;
  24. border-bottom: 1px solid #ccc; outline: none"></textarea>
  25. <div style="text-align: right; padding-right: 10px">
  26. <el-button type="primary" size="mini" @click="send">发送</el-button>
  27. </div>
  28. </div>
  29. </div>
  30. </el-col>
  31. </el-row>
  32. </div>
  33. </template>
  34. <script>
  35. import request from "@/utils/request";
  36. let socket;
  37. export default {
  38. name: "Im",
  39. data() {
  40. return {
  41. circleUrl: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png',
  42. user: {},
  43. isCollapse: false,
  44. users: [],
  45. chatUser: '',
  46. text: "",
  47. messages: [],
  48. content: ''
  49. }
  50. },
  51. created() {
  52. this.init()
  53. },
  54. methods: {
  55. send() {
  56. if (!this.chatUser) {
  57. this.$message({type: 'warning', message: "请选择聊天对象"})
  58. return;
  59. }
  60. if (!this.text) {
  61. this.$message({type: 'warning', message: "请输入内容"})
  62. } else {
  63. if (typeof (WebSocket) == "undefined") {
  64. console.log("您的浏览器不支持WebSocket");
  65. } else {
  66. console.log("您的浏览器支持WebSocket");
  67. // 组装待发送的消息 json
  68. // {"from": "zhang", "to": "admin", "text": "聊天文本"}
  69. let message = {from: this.user.username, to: this.chatUser, text: this.text}
  70. socket.send(JSON.stringify(message)); // 将组装好的json发送给服务端,由服务端进行转发
  71. this.messages.push({user: this.user.username, text: this.text})
  72. // 构建消息内容,本人消息
  73. this.createContent(null, this.user.username, this.text)
  74. this.text = '';
  75. }
  76. }
  77. },
  78. createContent(remoteUser, nowUser, text) { // 这个方法是用来将 json的聊天消息数据转换成 html的。
  79. let html
  80. // 当前用户消息
  81. if (nowUser) { // nowUser 表示是否显示当前用户发送的聊天消息,绿色气泡
  82. html = "<div class=\"el-row\" style=\"padding: 5px 0\">\n" +
  83. " <div class=\"el-col el-col-22\" style=\"text-align: right; padding-right: 10px\">\n" +
  84. " <div class=\"tip left\">" + text + "</div>\n" +
  85. " </div>\n" +
  86. " <div class=\"el-col el-col-2\">\n" +
  87. " <span class=\"el-avatar el-avatar--circle\" style=\"height: 40px; width: 40px; line-height: 40px;\">\n" +
  88. " <img src=\"https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png\" style=\"object-fit: cover;\">\n" +
  89. " </span>\n" +
  90. " </div>\n" +
  91. "</div>";
  92. } else if (remoteUser) { // remoteUser表示远程用户聊天消息,蓝色的气泡
  93. html = "<div class=\"el-row\" style=\"padding: 5px 0\">\n" +
  94. " <div class=\"el-col el-col-2\" style=\"text-align: right\">\n" +
  95. " <span class=\"el-avatar el-avatar--circle\" style=\"height: 40px; width: 40px; line-height: 40px;\">\n" +
  96. " <img src=\"https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png\" style=\"object-fit: cover;\">\n" +
  97. " </span>\n" +
  98. " </div>\n" +
  99. " <div class=\"el-col el-col-22\" style=\"text-align: left; padding-left: 10px\">\n" +
  100. " <div class=\"tip right\">" + text + "</div>\n" +
  101. " </div>\n" +
  102. "</div>";
  103. }
  104. console.log(html)
  105. this.content += html;
  106. },
  107. init() {
  108. this.user = sessionStorage.getItem("user") ? JSON.parse(sessionStorage.getItem("user")) : {}
  109. let username = this.user.username;
  110. let _this = this;
  111. if (typeof (WebSocket) == "undefined") {
  112. console.log("您的浏览器不支持WebSocket");
  113. } else {
  114. console.log("您的浏览器支持WebSocket");
  115. let socketUrl = "ws://localhost:9090/imserver/" + username;
  116. if (socket != null) {
  117. socket.close();
  118. socket = null;
  119. }
  120. // 开启一个websocket服务
  121. socket = new WebSocket(socketUrl);
  122. //打开事件
  123. socket.onopen = function () {
  124. console.log("websocket已打开");
  125. };
  126. // 浏览器端收消息,获得从服务端发送过来的文本消息
  127. socket.onmessage = function (msg) {
  128. console.log("收到数据====" + msg.data)
  129. let data = JSON.parse(msg.data) // 对收到的json数据进行解析, 类似这样的: {"users": [{"username": "zhang"},{ "username": "admin"}]}
  130. if (data.users) { // 获取在线人员信息
  131. _this.users = data.users.filter(user => user.username !== username) // 获取当前连接的所有用户信息,并且排除自身,自己不会出现在自己的聊天列表里
  132. } else {
  133. // 如果服务器端发送过来的json数据 不包含 users 这个key,那么发送过来的就是聊天文本json数据
  134. // // {"from": "zhang", "text": "hello"}
  135. if (data.from === _this.chatUser) {
  136. _this.messages.push(data)
  137. // 构建消息内容
  138. _this.createContent(data.from, null, data.text)
  139. }
  140. }
  141. };
  142. //关闭事件
  143. socket.onclose = function () {
  144. console.log("websocket已关闭");
  145. };
  146. //发生了错误事件
  147. socket.onerror = function () {
  148. console.log("websocket发生了错误");
  149. }
  150. }
  151. }
  152. }
  153. }
  154. </script>
  155. <style>
  156. .tip {
  157. color: white;
  158. text-align: center;
  159. border-radius: 10px;
  160. font-family: sans-serif;
  161. padding: 10px;
  162. width:auto;
  163. display:inline-block !important;
  164. display:inline;
  165. }
  166. .right {
  167. background-color: deepskyblue;
  168. }
  169. .left {
  170. background-color: forestgreen;
  171. }
  172. </style>

最后设置路由就好啦 

  1. {
  2. path: 'im',
  3. name: 'Im',
  4. component: () => import("@/views/Im"),
  5. },

 

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

闽ICP备14008679号