当前位置: 首页 > news >正文

SpringBoot整合WebSocket实现聊天室

1.简单的实现了聊天室功能,注意页面刷新后聊天记录不会保存,后端没有做消息的持久化

2.后端用户的识别只简单使用Session用户的身份

0.依赖

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>

1.配置WebSocketConfigurer配置类

package com.example.config;import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.server.HandshakeInterceptor;import javax.servlet.http.HttpSession;
import java.util.Map;@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfigurer implements WebSocketMessageBrokerConfigurer {@Overridepublic void configureMessageBroker(MessageBrokerRegistry config) {config.enableSimpleBroker("/topic");config.setApplicationDestinationPrefixes("/app");}@Overridepublic void registerStompEndpoints(StompEndpointRegistry registry) {registry.addEndpoint("/ws").withSockJS().setInterceptors(new HttpHandshakeInterceptor());}public class HttpHandshakeInterceptor implements HandshakeInterceptor {@Overridepublic boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {if (request instanceof ServletServerHttpRequest) {ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;HttpSession session = servletRequest.getServletRequest().getSession(false);if (session != null) {//使用session中的userString user = (String) session.getAttribute("user");if(user!=null){attributes.put("user", user);}}}return true;}@Overridepublic void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,WebSocketHandler wsHandler, Exception exception) { }}}

2.MessageHandler用于处理接收消息

package com.example.webController;import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;import javax.servlet.http.HttpSession;@Controller
public class MessageHandler {@MessageMapping("/chat")@SendTo("/topic/messages")public String chat(@PathVariable("messages") String message, SimpMessageHeaderAccessor headerAccessor) {// 获取用户数据Object user = headerAccessor.getSessionAttributes().get("user");System.out.println("User: " + user);return user.toString()+":" + message;}//登录@GetMapping("login/{userName}")public void login(@PathVariable String userName, HttpSession session) {System.out.println("User " + userName);session.setAttribute("user", userName);}
}

3.前端页面

先登录后发送消息

4.前端代码

<!DOCTYPE html>
<html>
<head><title>WebSocket Demo</title><script src="https://cdn.jsdelivr.net/npm/sockjs-client/dist/sockjs.min.js"></script><script src="https://cdn.jsdelivr.net/npm/stompjs/lib/stomp.min.js"></script><style>#chatBox {width: 60%;margin: auto;height: 500px;border: 1px solid black;padding: 10px;border-radius: 7px;}.chat-message {height: 85%;overflow: auto;}.flex-row, .flex-row-reverse {display: flex;justify-content: space-between;padding: 10px 0;}.message {max-width: 60%;padding: 10px;border-radius: 10px;}.user {background-color: #7986cb;color: white;}.assistant {background-color: #ffe082;}#inputMessage {width: 80%;padding: 10px;border-radius: 10px;border: 1px solid black;margin-top: 10px;}#sendButton {width: 15%;margin-left: 5%;padding: 11px;background-color: #ff7043;color: white;border: none;border-radius: 10px;cursor: pointer;}</style>
</head>
<body>
<div id="chat"><div id="chatBox"><div class="chat-message"><div class="flex-row"><div class="message user"><p>Hello</p></div></div><div class="flex-row-reverse"><div class="message assistant"><p>Hi, How can I help you?</p></div></div></div><input type="text" id="inputMessage" placeholder="Type message.." /><button id="sendButton"  onclick="send()">Send</button></div><input type="text" id="login" placeholder="输入用户名。。。" /><button  onclick="login()">Login</button></div>
<script>var socket = new SockJS('/ws');var stompClient = Stomp.over(socket);stompClient.connect({}, function(frame) {stompClient.subscribe('/topic/messages', function(message) {var div = document.createElement('div');div.className = "flex-row-reverse";var messageDiv = document.createElement('div');messageDiv.className = "message assistant";var p = document.createElement('p');p.textContent = message.body;messageDiv.appendChild(p);div.appendChild(messageDiv);document.querySelector('.chat-message').appendChild(div);});});function login() {var value = document.getElementById('login').value;//发送get请求fetch('/login/' + value)//刷新页面window.location.reload();}function send() {var inputValue = document.getElementById('inputMessage').value;var div = document.createElement('div');div.className = "flex-row";// var messageDiv = document.createElement('div');// messageDiv.className = "message user";// var p = document.createElement('p');// p.textContent = inputValue;// messageDiv.appendChild(p);// div.appendChild(messageDiv);document.querySelector('.chat-message').appendChild(div);stompClient.send("/app/chat", {}, inputValue);document.getElementById('inputMessage').value = '';}
</script>
</body>
</html>

相关文章:

  • MySQL数据库入门之视图、存储过程、触发器
  • 智能除螨—wtn6040-8s语音芯片方案引领除螨仪新时代
  • windows系统电脑外插键盘驱动出现感叹号或者显示未知设备,键盘无法输入的解决办法
  • GeoScene产品学习视频收集
  • 【UML用户指南】-02-UML的14种图
  • 二叉树链式结构的前序_中序_后续_层序遍历【详细图解】
  • leetCode-hot100-数组专题之子数组+二维数组
  • SSD图、用例描述
  • React Native 之 ToastAndroid(提示语)(二十一)
  • I2C协议详解
  • 日志输出-第四章-接口级(单体应用)前后端数据加解密 Filter 实现
  • 设计模式 17 组合模式 Composite Pattern
  • 网页设计步骤总结
  • C++ Qt:QString与数字之间的相互转换
  • es和mongdb对比
  • ES6指北【2】—— 箭头函数
  • golang 发送GET和POST示例
  • JavaScript创建对象的四种方式
  • tweak 支持第三方库
  • windows下使用nginx调试简介
  • XML已死 ?
  • 道格拉斯-普克 抽稀算法 附javascript实现
  • 免费小说阅读小程序
  • 前端代码风格自动化系列(二)之Commitlint
  • 腾讯视频格式如何转换成mp4 将下载的qlv文件转换成mp4的方法
  • 限制Java线程池运行线程以及等待线程数量的策略
  • 小试R空间处理新库sf
  • Java数据解析之JSON
  • PostgreSQL之连接数修改
  • Spring Batch JSON 支持
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • ​DB-Engines 11月数据库排名:PostgreSQL坐稳同期涨幅榜冠军宝座
  • ‌前端列表展示1000条大量数据时,后端通常需要进行一定的处理。‌
  • # linux 中使用 visudo 命令,怎么保存退出?
  • #NOIP 2014# day.2 T2 寻找道路
  • #pragma once与条件编译
  • #多叉树深度遍历_结合深度学习的视频编码方法--帧内预测
  • (2)关于RabbitMq 的 Topic Exchange 主题交换机
  • (3) cmake编译多个cpp文件
  • (arch)linux 转换文件编码格式
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第2节(共同的基类)
  • (libusb) usb口自动刷新
  • (pytorch进阶之路)扩散概率模型
  • (办公)springboot配置aop处理请求.
  • (多级缓存)缓存同步
  • (附源码)springboot 房产中介系统 毕业设计 312341
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (每日一问)基础知识:堆与栈的区别
  • (十一)手动添加用户和文件的特殊权限
  • (一)Linux+Windows下安装ffmpeg
  • (转)ObjectiveC 深浅拷贝学习
  • (转载)利用webkit抓取动态网页和链接
  • (转载)深入super,看Python如何解决钻石继承难题
  • (轉貼) 蒼井そら挑戰筋肉擂台 (Misc)
  • *(长期更新)软考网络工程师学习笔记——Section 22 无线局域网