springboot -- 整合websocket 实现在线聊天
项目demo:
链接:https://pan.baidu.com/s/1xZtU-Rqc58m0-v397OW3hQ
提取码:01pt
复制这段内容后打开百度网盘手机App,操作更方便哦
websocket 实现在线聊天效果
用户1 发送消息
用户4 接收消息
关闭 2 3 4 页面,用户下线通知
pom.xml
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>
添加 config 配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;@Configuration
public class WebSocketConfig {/*** 服务器节点** 如果使用独立的servlet容器,而不是直接使用springboot的内置容器,就不要注入ServerEndpointExporter,因为它将由容器自己提供和管理* @return*/@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}
后端接收处理消息
package com.example.springboot_websocket.controller;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;/*** websocket类* @ServerEndpoint: socket链接地址*/
@ServerEndpoint("/websocket/{username}")
@Controller
public class WebsocketController {private Logger logger = LoggerFactory.getLogger(this.getClass());/*** 在线人数*/public static int onlineNumber = 0;/*** 以用户的姓名为key,WebSocket为对象保存起来*/private static Map<String, WebsocketController> clients = new ConcurrentHashMap<String, WebsocketController>();/*** 会话*/private Session session;/*** 用户名称*/private String username;/*** 进入聊天室 --> 项目中读取用户信息获取用户名 */@RequestMapping("/websocket")public String webSocket(Model model) {//定义随机时间戳名称String name = "游客:";//String datename = new SimpleDateFormat("yyyyMMddHHmmsss").format(new Date());String datename = new SimpleDateFormat("msss").format(new Date());name = name + datename;//websock链接地址+游客名--> 项目中请定义在配置文件 -->或直接读取服务器,ip 端口// 读取服务器,ip 端口可看:https://blog.csdn.net/qq_41463655/article/details/92002474String path="ws://192.168.100.7:8080/websocket/";model.addAttribute("path",path);model.addAttribute("username",name);return "socket";}/*** 监听连接(有用户连接,立马到来执行这个方法)* session 发生变化** @param session*/@OnOpenpublic void onOpen(@PathParam("username") String username, Session session) {onlineNumber++;//把新用户名赋给变量this.username = username;//把新用户的 session 信息赋给变量this.session = session;//输出 websocket 信息logger.info("现在来连接的客户id:" + session.getId() + "用户名:" + username);logger.info("有新连接加入! 当前在线人数" + onlineNumber);try {//把自己的信息加入到map当中去,this=当前类(把当前类作为对象保存起来)clients.put(username, this);//获得所有的用户Set<String> lists = clients.keySet();// 先给所有人发送通知,说我上线了//messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息Map<String, Object> map1 = new HashMap();// 把所有用户列表map1.put("onlineUsers", lists);// 返回上线状态map1.put("messageType", 1);// 返回用户名map1.put("username", username);// 返回在线人数map1.put("number", onlineNumber);// 发送全体信息(用户上线信息)sendMessageAll(JSON.toJSONString(map1), username);// 给自己发一条消息:告诉自己现在都有谁在线Map<String, Object> map2 = new HashMap();//messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息map2.put("messageType", 3);//把所有用户放入map2map2.put("onlineUsers", lists);//返回在线人数map2.put("number", onlineNumber);// 消息发送指定人(所有的在线用户信息)sendMessageTo(JSON.toJSONString(map2), username);} catch (IOException e) {logger.info(username + "上线的时候通知所有人发生了错误");}}/*** 监听连接断开(有用户退出,会立马到来执行这个方法)*/@OnClosepublic void onClose() {onlineNumber--; //所有在线用户中去除下线用户clients.remove(username); try {//messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息Map<String, Object> map1 = new HashMap();map1.put("messageType", 2);//所有在线用户map1.put("onlineUsers", clients.keySet());//下线用户的用户名map1.put("username", username);//返回在线人数map1.put("number", onlineNumber);//发送信息,所有人,通知谁下线了sendMessageAll(JSON.toJSONString(map1), username);} catch (IOException e) {logger.info(username + "下线的时候通知所有人发生了错误");}logger.info("有连接关闭! 当前在线人数" + onlineNumber);}@OnErrorpublic void onError(Session session, Throwable error) {logger.info("服务端发生了错误" + error.getMessage());//error.printStackTrace();}/*** 监听消息(收到客户端的消息立即执行)** @param message 消息* @param session 会话*/@OnMessagepublic void onMessage(String message, Session session) {try {logger.info("来自客户端消息:" + message + "客户端的id是:" + session.getId());//用户发送的信息com.alibaba.fastjson.JSONObject jsonObject = JSON.parseObject(message);//发送的内容String textMessage = jsonObject.getString("message");//发送人String fromusername = jsonObject.getString("username");//接收人 to=all 发送消息给所有人 || to= !all to == 用户名String tousername = jsonObject.getString("to");//发送消息 -- messageType 1代表上线 2代表下线 3代表在线名单 4代表消息Map<String, Object> map1 = new HashMap();map1.put("messageType", 4);map1.put("textMessage", textMessage);map1.put("fromusername", fromusername);if (tousername.equals("All")) {//消息发送所有人(同步)map1.put("tousername", "所有人");sendMessageAll(JSON.toJSONString(map1), fromusername);} else {//消息发送指定人(同步)map1.put("tousername", tousername);sendMessageTo(JSON.toJSONString(map1), tousername);}} catch (Exception e) {logger.info("发生了错误了");}}/*** 消息发送指定人*/public void sendMessageTo(String message, String ToUserName) throws IOException {//遍历所有用户for (WebsocketController item : clients.values()) {if (item.username.equals(ToUserName)) {//消息发送指定人(同步)item.session.getBasicRemote().sendText(message);break;}}}/*** 消息发送所有人*/public void sendMessageAll(String message, String FromUserName) throws IOException {for (WebsocketController item : clients.values()) {//消息发送所有人(同步)getAsyncRemoteitem.session.getBasicRemote().sendText(message); }}public static synchronized int getOnlineCount() {return onlineNumber;}
}/** 注解说明* @MessageMapping(value = "/chat") // 匹配客户端 send 消息时的URL* @SendTo("/topic/getResponse") //用于给客户端订阅广播消息* @SendToUser(value = "/personal") //用于给客户端订阅点对点消息;* @Payload:使用客户端 STOMP 帧的 body 赋值* @Header(“xxx”):使用客户端 STOMP 帧的 headers 中的 xxx 赋值***//*** 广播推送**/
// @MessageMapping(value = "/chat") // 匹配客户端 send 消息时的URL
// @SendTo("/topic/getResponse") //分别用于给客户端订阅广播消息
// public String talk(@Payload String text, @Header("simpSessionId") String sessionId) throws Exception {
// return "【" + sessionId + "】说:【" + text + "】";
// }/*** 点对点推送*/
/*@MessageMapping(value = "/speak") // 匹配客户端 send 消息时的URL@SendToUser(value = "/personal") //分别用于给客户端订阅点对点消息;public String speak(@Payload String text, @Header("simpSessionId") String sessionId) throws Exception {return text;}*//*** 异常信息推送*/
/*@MessageExceptionHandler@SendToUser(value = "/errors")public String handleException(Throwable exception) {return exception.getMessage();}*/
Html 页面发送接收消息
<!DOCTYPE html>
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head><meta charset="UTF-8"><meta name="renderer" content="webkit"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"><link rel="stylesheet" href="../frame/layui/css/layui.css"><link rel="stylesheet" href="../frame/static/css/style.css"><link rel="icon" href="../frame/static/image/code.png"><title>websocket</title><script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.min.js"></script><script src="http://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script><script src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js"></script>
</head>
<css></css>
<body><!-- socket url -->
<input type="hidden" th:value="${path}" id="path" style="display: none" />
<!-- 用户名 -->
<input type="hidden" th:value="${username}" id="username" style="display: none" /><!-- =============================================================================================================== -->
<br><!--<input type="hidden" value="所有人" id="onLineUser" text="所有人" style="display: none" />--><!-- =============================================================================================================== -->
<!-- overflow-y :auto;overflow :auto; 宽高自适应滚动条-->
<span id = "miqx" style="width:80%;height:300px; background-color: papayawhip;float:left;overflow-y :auto;overflow :auto;"><li style="text-align: center">群聊信息</li>
</span>
<span id = "miax" style="width:20%;background-color: #F2F2F2;float:left;overflow-y :auto;overflow :auto;"><li style="text-align: center">在线列表</li>
</span><textarea id="text" placeholder="请输入内容-发送消息[Ctrl+回车键]" rows="3%" cols="60%"></textarea><input onclick="send()" type="button" value="发送">
<td>消息发送至:</td>
<select id="onLineUser" size="1" style="width: 10%;height:30px"><option value="所有人">所有人</option>
</select><div id = "mizx" style="width:80%;height:300px;background-color: #FFEEE8;float:left;overflow-y :auto;overflow :auto;"><li style="text-align: center">私聊信息</li><!-- <li style="text-align: right">靠右</li><li style="text-align: left" >靠左</li>-->
</div>
<br>
<br><!-- =============================================================================== --></body>
<script type="text/javascript">function uaername(name){alert(name)}var miqx = $("#miqx"); //群聊var miax = $("#miax"); //在线列表var mizx = $("#mizx"); //私聊var onLineUser = $("#onLineUser"); //发送人select选择框var webSocket;var commWebSocket;http:if ("WebSocket" in window){//192.168.100.7:8080/webSocket = new WebSocket(document.getElementById('path').value +document.getElementById('username').value);//连通之后的回调事件webSocket.onopen = function(){miqx.html(miqx.html()+" <li style='text-align: center'>系统消息:[登陆成功]</li>")};//接收后台服务端的消息webSocket.onmessage = function (evt){var received_msg = evt.data; //接收到的数据var obj = JSON.parse(received_msg); //json数据var messageType = obj.messageType; //数据类型(1上线/2下线/3在线名单/4发信息)var onlineName = obj.username; //用户名var number = obj.number; //在线人数//上线通知+在线列表刷新if(obj.messageType==1){if((onlineName != $("#username").val())){ //展示除不等于自己的所有用户miqx.html(miqx.html()+" <li style='text-align: center'>系统消息:["+ onlineName+"]上线了"+"</li>");onLineUser.html(onLineUser.html()+"<option value='"+ onlineName +"'>"+ onlineName +"</option>");}var onlineName = obj.onlineUsers; //所有在线用户miax.html("<li style='text-align: center'>在线用户--["+ onlineName.length +"]</li>");for(var i=0;i<onlineName.length;i++){if((onlineName[i] != $("#username").val())){ //展示除不等于自己的所有用户miax.html(miax.html()+"<li style='text-align: left'>---"+ onlineName[i] +"</li>" );}}//miax.html(miax.html()+" <li style='text-align: center'>"+ onlineName +"</li>");}//下线通知+在线列表刷新else if(obj.messageType==2){if((onlineName != $("#username").val())){ //展示除不等于自己的所有用户miqx.html(miqx.html()+" <li style='text-align: center'>系统消息:["+ onlineName+"]下线了"+"</li>");}var onlineName = obj.onlineUsers; //剩余所有在线用户miax.html("<li style='text-align: center'>在线用户--["+ onlineName.length +"]</li>");onLineUser.html("<option value='所有人'>所有人</option>");for(var i=0;i<onlineName.length;i++){if((onlineName[i] != $("#username").val())){ //展示除不等于自己的所有用户miax.html(miax.html()+"<li style='text-align: left'>---"+ onlineName[i] +"</li>" );onLineUser.html(onLineUser.html()+"<option value='"+ onlineName[i] +"'>"+ onlineName[i] +"</option>");}}}//在线列表else if(obj.messageType==3){var onlineName = obj.onlineUsers; //所有在线用户miax.html("<li style='text-align: center'>在线用户--["+ onlineName.length +"]</li>");onLineUser.html("<option value='所有人'>所有人</option>");for(var i=0;i<onlineName.length;i++){if(onlineName[i] != $("#username").val()){ //展示除不等于自己的所有用户miax.html(miax.html()+ " <li style='text-align: left'>---"+ onlineName[i] +"</li>" );onLineUser.html(onLineUser.html()+"<option value='"+ onlineName[i] +"'>"+ onlineName[i] +"</option>");}}}//信息接收else{var time2 = new Date();var date = time2.getHours()+":"+time2.getMinutes()+":"+ time2.getSeconds(); //时间if(obj.fromusername != $("#username").val() ){ //自己不接自己的消息if(obj.tousername=="所有人"){//发给所有人miqx.html(miqx.html()+" <li style='text-align: left'>["+ obj.fromusername+"]说:-"+obj.textMessage +"</li>");}else {//发给指定人mizx.html(mizx.html()+" <li style='text-align: left'>["+ obj.fromusername+"]说:-"+obj.textMessage+"</li>");}}//setMessageInnerHTML(obj.fromusername+"对"+obj.tousername+"说:"+obj.textMessage);}};//连接关闭的回调事件webSocket.onclose = function(){console.log("连接已关闭...");setMessageInnerHTML("连接已经关闭....");};}else{// 浏览器不支持 WebSocketalert("您的浏览器不支持 WebSocket!");}//将消息显示在网页上function setMessageInnerHTML(innerHTML) {document.getElementById('message').innerHTML += innerHTML + '<br/>';}function closeWebSocket() {//直接关闭websocket的连接webSocket.close();}//信息发送+ 页面显示发送信息$(document).keyup(function(event){//浏览器适应if(event.ctrlKey && event.which == 13 || event.which == 10) {send();} else if (event.shiftKey && event.which==13 || event.which == 10) {send();}});//信息发送+ 页面显示发送信息function send() {var usernameX = $("#username").val() //发送数据人var usernameY = $("#onLineUser").val(); //接收数据人var message = $("#text").val(); //发送的数据if(usernameY=="所有人"){usernameY = "All";/* <li style="text-align: center">群聊信息</li><li style="text-align: right">靠右</li><li style="text-align: left" >靠左</li>*/miqx.html(miqx.html()+" <li style='text-align: right'>"+ message+" -- ["+usernameX +"]</li>");}else{mizx.html(mizx.html()+" <li style='text-align: right'>"+ "你对-["+usernameY+"]说:-"+message+"</li>");}var message = {"message":message,"username":usernameX,"to":usernameY};//发送数据webSocket.send(JSON.stringify(message));$("#text").val("");}layui.use(['form', 'layedit', 'laydate'], function () {var form = layui.form, layer = layui.layer, layedit = layui.layedit, laydate = layui.laydate;//监听指定开关form.on('switch(switchTest)', function (data) {layer.msg('你以' + (this.checked ? '上线' : '下线'), {offset: '6px'});//layer.tips('温馨提示:请注意开关状态的文字可以随意定义,而不仅仅是ON|OFF', data.othis)});});
</script>
</html>
springboot -- 整合websocket 实现在线聊天相关推荐
- SpringBoot与webSocket实现在线聊天室——实现私聊+群聊+聊天记录保存
SpringBoot与webSocket实现在线聊天室--实现私聊+群聊+聊天记录保存 引用参考:原文章地址:https://blog.csdn.net/qq_41463655/article/det ...
- SpringBoot整合websocket实现在线客服聊天
websocket最伟大之处在于服务器和客户端可以在给定的时间范围内的任意时刻,相互推送信息. 浏览器和服务器只需要要做一个握手的动作,在建立连接之后,服务器可以主动传送数据给客户端,客户端也可以随时 ...
- SpringBoot 使用WebSocket打造在线聊天室(基于注解)
点击上方"好好学java",选择"置顶公众号" 优秀学习资源.干货第一时间送达! 精彩内容 java实战练习项目教程 2018微服务资源springboot.s ...
- SpringBoot集成WebSocket实现在线聊天
文章目录 前言 1.WebSocket引入 2.环境搭配 2.1.工程创建 2.2.依赖导入 2.3.配置类 3.具体实现 3.1.前置知识 3.2.数据封装 3.3.思路分析 3.4.服务构建 3. ...
- SpringBoot整合WebSocket实现简易聊天室
文章目录 什么是WebSocket ? WebSocket通信模型 为什么需要WebSocket Websocket与http的关系 SpringBoot集成WebSocket 什么是WebSocke ...
- SpringBoot应用WebSocket实现在线聊天
目录 一.简介 二.java服务端 1.引入包 2.配置 3.代码实现 三.H5客户端 1.代码实现 一.简介 WebSocket是一种在单个TCP连接上进行全双工通信的协议.WebSocket通信协 ...
- 在线聊天室的消息单聊的实现——springboot整合WebSocket(二)
一.声明 项目的搭建请大家移步到:在线聊天室的消息群聊的实现--springboot整合WebSocket(一) 单聊的实现是在群聊项目上进行延申改造的. 二.引入依赖 <dependency& ...
- 【SpringBoot框架篇】18.使用Netty加websocket实现在线聊天功能
文章目录 1.简介 2.最终功能实现的效果图 2.1.pc端 2.2.移动端 3.实战应用 3.1.引入依赖 3.2.配置文件 3.3.测试demo 3.3.1.消息内容实体类 3.3.2.处理请求的 ...
- Springboot + WebSocket 实现在线聊天
一.后端 1.在Springboot项目的pom.xml中添加依赖 <!--websocket协议--> <dependency><groupId>org.spri ...
最新文章
- 【项目管理】聊聊项目管理几点实践和理解(2)
- Python字符串拼接的十种方式
- arch linux arm下载_arm开发板运行hello word的详细过程
- Direct3D提高篇:HLSL编程实现PhotoShop滤镜效果 - 伪 HDR/Blow
- 光电转换模块_光模块:PIN光电二极管和APD光电二极管
- linux学习之路(1)
- python记录(5)- find() 与 rfind()
- jQuery formValidator表单校验代码生成器ver1.1,一键产生所有代码
- 如何写好 Java 业务代码?这也是有很多规范的!
- 系统的性能与压力测试
- 华为2019实习生专业面试经历——通信算法工程师
- 看图写英语作文关于计算机,终于懂了看图写英语作文模板
- C语言atan2()函数:求y/x的反正切值
- console和nsh的区别
- 怎么扫描图片存为电子版?只需要几步小操作
- 5_ARM Cortex-M汇编
- switch、break与continue的用法
- 八皇后(例题:洛谷P1219)
- 整体厨房效果图软件测试,新手必看!几款做饭软件测评,为你打造专属美食之旅...
- flutter ios打包_安卓开发者如何使用Flutter打包IOS应用