行业知识
SpringBoot和Vue2集成WebSocket,实现聊天室功能
2026-10-31 18:43:48
来源:互联网转载
SpringBoot和Vue2集成WebSocket,实现聊天室功能
1.加入依赖2.后端建立socket服务端3.前端建立客户端
后端
org.springframework.boot spring-boot-starter-websocket com.alibaba fastjson 1.2.76
// 配置开启WebSocket@Configurationpublic class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); }} /** * @author websocket服务 */@ServerEndpoint(value = "/imserver/{userId}")@Componentpublic class WebSocketServer { private static UserService userService; private static RedisTemplate redisTemplate; public static void setUserService(ApplicationContext context){ userService = context.getBean(UserServiceImpl.class); redisTemplate = (RedisTemplate) context.getBean("redisTemplate"); } private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class); /** * 记录当前在线连接数 */ public static final Map sessionMap = new ConcurrentHashMap(); /** * 连接建立成功调用的方法 */ // 当前用户 private UserVo userVo; // 连接上服务端触发的方法 @OnOpen public void onOpen(Session session, @PathParam("userId") String userId) { if (StringUtils.hasText(userId)){ // 加入新用户 if (sessionMap.containsKey(userId)){ sessionMap.remove(userId); } sessionMap.put(userId, session); this.userVo = userService.findById(Long.valueOf(userId)); // 统计所有在线用户 List list = new LinkedList(); sessionMap.forEach((userId1,session1) -> { UserVo userVo = userService.findById(Long.valueOf(userId1)); list.add(userVo); }); try { // 发送给所有在线的用户,更新在线人数 sendAllMessage(JSON.toJSONString(list)); } catch (Exception e) { e.printStackTrace(); } log.info("有新用户加入,userId={}, 当前在线人数为:{}", userId, sessionMap.size()); } } /** * 连接关闭调用的方法 */ @OnClose public void onClose(Session session, @PathParam("userId") String userId) { sessionMap.remove(userId); // 统计所有在线用户 List list = new LinkedList(); sessionMap.forEach((userId1,session1) -> { UserVo userVo = userService.findById(Long.valueOf(userId1)); list.add(userVo); }); sendAllMessage(JSON.toJSONString(list)); log.info("有一连接关闭,移除userId={}的用户session, 当前在线人数为:{}", userId, sessionMap.size()); } /** * 收到客户端消息后调用的方法 * 后台收到客户端发送过来的消息 * onMessage 是一个消息的中转站 * 接受 浏览器端 socket.send 发送过来的 json数据 * @param message 客户端发送过来的消息 */ @OnMessage public void onMessage(String message, Session session, @PathParam("userId") String userId) { userVo = userService.findById(Long.valueOf(userId)); log.info("服务端收到用户username={},id={}的消息:{}", userVo.getNickname(),userId, message); // 解析消息 JSONObject jsonObject1 = JSON.parseObject(message); String toUserId = jsonObject1.getString("toUserId"); String text = jsonObject1.getString("text"); // 判断是给指定人发,还是群发 if (StringUtils.hasText(toUserId)){ // {"to": "admin", "text": "聊天文本"} Session toSession = sessionMap.get(toUserId); // 根据 to用户名来获取 session,再通过session发送消息文本 if (toSession != null) { // 服务器端 再把消息组装一下,组装后的消息包含发送人和发送的文本内容 // {"from": "zhang", "text": "hello"} JSONObject jsonObject = new JSONObject(); jsonObject.put("fromUser",userVo); jsonObject.put("toUser",userService.findById(Long.valueOf(toUserId))); jsonObject.put("text",text); this.sendMessage(jsonObject.toJSONString(), toSession); log.info("发送给用户userId={},消息:{}", toUserId, jsonObject.toJSONString()); } else { log.info("发送失败,未找到用户username={}的session", toUserId); } }else{ JSONObject jsonObject = new JSONObject(); jsonObject.put("fromUser",userVo); jsonObject.put("text",text); this.sendAllMessage(jsonObject.toJSONString()); // 将消息存入redis redisTemplate.opsForList().rightPush("messageList",jsonObject.toJSONString()); redisTemplate.expire("messageList",60*60, TimeUnit.SECONDS); // 过期时间 log.info("发送给所有用户,消息:{}", toUserId, jsonObject.toJSONString()); } } @OnError public void onError(Session session, Throwable error) { log.error("发生错误"); error.printStackTrace(); } /** * 服务端发送消息给客户端 */ private void sendMessage(String message, Session toSession) { try { log.info("服务端给客户端[{}]发送消息{}", toSession.getId(), message); toSession.getBasicRemote().sendText(message); } catch (Exception e) { log.error("服务端发送消息给客户端失败", e); } } /** * 服务端发送消息给所有客户端 */ private void sendAllMessage(String message) { try { for (Session session : sessionMap.values()) { log.info("服务端给客户端[{}]发送消息{}", session.getId(), message); session.getBasicRemote().sendText(message); } } catch (Exception e) { log.error("服务端发送消息给客户端失败", e); } }}// WebSocket服务类无法进行bean的注入,所以要自己调用ApplicationContext获取bean再注入@SpringBootApplicationpublic class BlogApplication { public static void main(String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(BlogApplication.class, args); WebSocketServer.setUserService(applicationContext); }} 前端
在线用户
{{user.account}}当前用户({{user.account}})
{{item.text}} 发送 import config from '@/utils/config' import {getCacheMessage} from '@/api/socket' import {mapState} from 'vuex' export default { name:'lm', data(){ return { text:'', onlineUser:[], messageList:[], socket:'', baseUrl:config.socketUrl } }, computed:{ ...mapState(['user']) }, methods:{ // 连接socket onOpen(){ if (typeof WebSocket == 'undefined'){ console.log('你的浏览器不支持webSocket') return; } const url = this.baseUrl+this.user.id this.socket = new WebSocket(url); this.socket.onopen = ()=>{ console.log('websocket打开了,'+this.user.id+'连接成功') } this.socket.onmessage = (data)=>{ var message = JSON.parse(data.data) if(message.hasOwnProperty("text")){ this.messageList.push(message) this.text = '' let scroll = this.$refs['scroll'].$refs['wrap'] this.$nextTick(() =>{ scroll.scrollTop = scroll.scrollHeight }) }else{ // 统计在线人数 this.onlineUser = message } } this.socket.onclose = function(){ console.log('断开连接成功') } }, sendMessage(){ const message = { text:this.text, userId:this.user.id } if(this.text == ''||this.text == null){ this.$message.warning('请输入内容') }else{ this.socket.send(JSON.stringify(message)) } }, // 初始化,缓存的消息 getCacheMessage(){ getCacheMessage().then( res => { const data = res.data for(var i in data){ this.messageList.push(JSON.parse(data[i])) } } ) } }, mounted(){ this.getCacheMessage() this.onOpen() }, beforeDestroy(){ this.socket.close() // 关闭socket } } .socket{ width: 1200px; height: 600px; padding:26px; background-color: #fff; border-radius: 5px; } .socket .online{ background-color: #f5f5f5; height: 300px; border-radius: 5px; overflow: hidden; } .socket .online .onlineUser{ display: flex; justify-content: flex-start; align-items: flex-start; } .socket .container{ position: relative; margin-left: 26px; background-color: #f5f5f5; height: 500px; border-radius: 5px; } .socket .el-button--primary{ background-color: #66b1ff; color: #fff; } .socket .container .content{ min-height: 400px; border: 1px solid #d6d6d6; border-radius: 4px; } .socket .container .content .message{ display: flex; align-content: flex-start; } .socket .write{ position:absolute; bottom: 10px; width: 500px; right: 50%; transform: translateX(50%); } .socket .text{ min-height: 24px; line-height: 20px; padding: 8px; font-size: 16px; background-color: #fff; border-radius: 5px; max-width: 280px; overflow-wrap:break-word; word-wrap:break-word; word-break: bread-all; white-space:pre-wrap; overflow: hidden; }
springboot集成websocket实现聊天室的功能。如有不足之处,还望大家斧正。
() ()下一篇:服务器搬迁怎么找公司?