先看效果:这里面demo用的是原生js跟html,方便打包一体化,在效果上我更倾向于使用vue、react等进行页面开发

还有很多可以优化的点,目前的名字我直接使用的获取时间戳并且没有提供名字跟头像的自定义功能,后续再优化吧,在打包的时候遇到了错误:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'serverEndpointExporter' defined in class path resource [com/an/websocket/config/WebSocketConfig.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: javax.websocket.server.ServerContainer not available

很离谱的居然是单元测试类的注解问题

改为

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

就可以打包了


pom文件

我针对上面的文件调整了boot自带的tomcat插件

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-undertow</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>1.3.5.RELEASE</version></dependency><dependency><groupId>net.sf.json-lib</groupId><artifactId>json-lib</artifactId><version>2.4</version><classifier>jdk15</classifier></dependency></dependencies>

后台代码

可以先看我之前的集成websocket的入门文章进行搭建工程,这里我直接粘贴业务代码,config配置不写了

package com.an.websocket.socket;import net.sf.json.JSONObject;
import org.springframework.stereotype.Component;import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;/*** @author * @title: WebSocketChatroom* @projectName me_lab* @description: TODO* @date 2022/2/10 0010下午 17:48*/
@ServerEndpoint(value = "/websocketChatroom/{info}")
@Component
public class WebSocketChatroom {private static SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");//创建时间格式对象//与某个客户端的连接会话,需要通过它来给客户端发送数据private Session session;//创建一个房间的集合,用来存放房间private static ConcurrentHashMap<String,ConcurrentHashMap<String, WebSocketChatroom>> roomList = new  ConcurrentHashMap<String,ConcurrentHashMap<String, WebSocketChatroom>>();//重新加入房间的标示;private int rejoin = 0;static {roomList.put("1704", new ConcurrentHashMap<String, WebSocketChatroom>());}/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(@PathParam(value = "info") String param, Session session) throws IOException {System.out.println(session.getId()+"链接了");System.out.println(param);this.session = session;String flag = param.split("[|]")[0];       //标识String member = param.split("[|]")[1];       //放假idif(flag.equals("join")){String user = param.split("[|]")[2];joinRoom(member,user);JSONObject jsonObject = new JSONObject();jsonObject.put("flag",flag);jsonObject.put("nickname",user);jsonObject.put("message","");jsonObject.put("member",member);this.session.getBasicRemote().sendText(jsonObject.toString());}}//加入房间public void joinRoom(String member,String user){ConcurrentHashMap<String, WebSocketChatroom> r =  roomList.get(member);if(r.get(user) != null){     //该用户有没有出this.rejoin = 1;}r.put(user, this);//将此用户加入房间中}public void sendMessage(String message) throws IOException {this.session.getBasicRemote().sendText(message);}/*** 连接关闭调用的方法*/@OnClosepublic void onClose() {}/*** 收到客户端消息后调用的方法** @param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, Session session) throws IOException {//把用户发来的消息解析为JSON对象JSONObject obj = JSONObject.fromObject(message);if(obj.get("flag").toString().equals("exitroom")){        //退出房间操作String roomid = obj.get("roomid").toString();//将用户从聊天室中移除int f2 = 1;roomList.get(roomid).remove(obj.get("nickname").toString());//将用户直接移除if(roomList.get(roomid).size() == 0){//判断房间该房间是否还有用户,如果没有,则将此房间也移除f2 = 2;}if(f2 == 1){        //证明该房间还有其它成员,则通知其它成员更新列表obj.put("flag","exitroom");String m = obj.get("nickname").toString()+" 退出了房间";obj.put("message", m);ConcurrentHashMap<String, WebSocketChatroom> r =roomList.get(roomid);List<String> uname = new ArrayList<String>();for(String u:r.keySet()){uname.add(u);}obj.put("uname", uname.toArray());for(String i:r.keySet()){  //遍历该房间r.get(i).sendMessage(obj.toString());//调用方法 将消息推送}}}else if(obj.get("flag").toString().equals("chatroom")){      //聊天室的消息 加入房间/发送消息//向JSON对象中添加发送时间obj.put("date", df.format(new Date()));//获取客户端发送的数据中的内容---房间�? 用于区别该消息是来自于哪个房间String roomid = obj.get("target").toString();//获取客户端发送的数据中的内容---用户String username = obj.get("nickname").toString();//从房间列表中定位到该房间ConcurrentHashMap<String, WebSocketChatroom> r =roomList.get(roomid);List<String> uname = new ArrayList<String>();for(String u:r.keySet()){uname.add(u);}obj.put("uname", uname.toArray());if(r.get(username).rejoin == 0){         //证明不是退出重连for(String i:r.keySet()){  //遍历该房间obj.put("isSelf", username.equals(i));//设置消息是否为自己的r.get(i).sendMessage(obj.toString());//调用方法 将消息推送}}else{obj.put("isSelf", true);r.get(username).sendMessage(obj.toString());}r.get(username).rejoin = 0;}}
}

前端代码

css

因为使用的原生html所以使用的样式也是单独的css文件没有进行其他框架的集成,直接粘贴css文件即可

@CHARSET "UTF-8";
html{height: 100%;
}
body{margin: 0;padding:0;height: 100%;overflow: hidden;
}
.body-left{float: left; color: white;
}
.body-right{float: right;
}
.body-left,.body-right{background-color: #101010;display:inline-block;width:25%;height: 100%;
}
.body-center{height: 100%;display:inline-block;width: 50%;
}
.center-info{height: 77%;width:88%;margin: 10px auto;padding: 5px 20px;border:1px #A9A9A9 dashed;border-radius: 15px;overflow: auto;overflow-x:hidden;
}
.center-input{display:block;height: 10%;width:92.2%;margin: 0px auto;padding: 5px 20px;resize: none;font-size: 20px;border:1px #A9A9A9 dashed; border-bottom: none;outline: none;border-radius: 15px 15px 0 0; overflow-x:hidden;
}
.ensure{height:4%;width: 88%;margin: 0px auto;padding:2px 20px;border: 1px #A9A9A9 dashed;border-radius:  0 0 15px 15px; border-top:none;
}
.ensure button{float: right;background-color: #4eacfb;border: none;border-radius: 5px;border-top:none;width: 15%;height: 25px;
}
.basicInfo{clear: both;max-width:80%;/* width: 80%; */margin:10px 0;
}
.basicInfo-left{width: 80px;height: 80px;
}
.basicInfo-left img{width: 100%;height: 100%;border-radius: 50px;
}
.basicInfo-right{max-width:76%;/* width:80%;  */padding:2px 12px;
}
.username{color: #8b8b8b;
}
.context{max-width:99%;padding:0 3px;background-color:#cdd7e2;margin-top: 5px;border-radius: 5px;word-wrap:break-word;word-break:break- all;
}
.welcome{clear:both;text-align: center;
}
.body-right img{width: 22%;position:fixed; bottom:2%;right: 2%;
}
.left-info{padding: 15px 54px;
}
.memberInfo{height: 50px;line-height: 50px;
}
.userpic{border-radius: 20px;height: 50px;float: left;
}
.userpic img{width:50px;height:50px;border-radius: 50px;margin-right: 15px;
}
.exitroom{margin-top: 12px;
}
.exitroom:HOVER {color:red;
}

js

jquery-3.2.1.min.js

页面代码

里面使用了html的append操作来进行内容记录跟样式调整

<html>
<head><base href="<%=basePath%>" /><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><script type="text/javascript" src="js/jquery-3.2.1.min.js"></script><link rel="stylesheet" type="text/css" href="css/chat.css" /><title>聊天室</title>
</head>
<script type="text/javascript">$(function(){$(".uname").append((new Date()).valueOf())var roomid=$(".roomid").html();//房间名var nickname = $(".uname").html();//自己的昵称var flag = "join";var info = flag + "|" +roomid + "|" +nickname;//建立一条与服务器之间的连接var socket = new WebSocket("ws://localhost:8080/websocketChatroom/"+info);var text = "";var welcome = JSON.stringify({           //加入房间时的欢迎消息nickname:nickname,    //用户名content:text,        //消息内容target:roomid,        //推送到目标房间flag:"chatroom"});   //推送标识var exitroom = JSON.stringify({      //退出房间nickname:nickname,flag:"exitroom",roomid:roomid})//接收服务器的消息socket.onmessage=function(ev){var obj = eval(   '('+ev.data+')' );addMessage(obj)};//当服务端执行onopen后触发此方法socket.onopen = function(){socket.send(welcome);};//发送按钮被点击时$(".ensure button").click(function(){ensure();});$("body").keyup(function (event) {//监听回车键if (event.keyCode == "13") {//keyCode=13是回车键$(".ensure button").trigger("click");}});function ensure(){//获取输入框的内容var txt = $(".center-input").val()if(txt==''){alert("不能发送空内容")}else{//构建一个标准格式的JSON对象var obj = JSON.stringify({nickname:nickname,    //用户名content:txt,     //消息内容flag:'chatroom',            //标识--chatroom代表是聊天室的消息target:roomid    //消息推送的目的地});// 向服务器发送消息socket.send(obj);// 清空消息输入框$(".center-input").val("")// 消息输入框获取焦点$(".center-input").focus();}}function addMessage(msg){if(msg.isSelf&&msg.content==""){ //该消息是自己发送的,并且内容为空$(".center-info").append("<div class='welcome'>欢迎你加入群聊</div>");refreshMember(msg.uname);  //刷新成员}if(!msg.isSelf&&msg.content==""){//该消息是别人发送的,并且内容为空$(".center-info").append("<div class='welcome'>欢迎"+msg.nickname+"加入群聊</div>");//刷新成员列表refreshMember(msg.uname)}if(!msg.content==""){            //内容不为空时var align;if(msg.isSelf){align = "right";}else{align = "left";}$(".center-info").append("<div class='basicInfo' style=float:"+align+">"+"<div class='basicInfo-left' style=float:"+align+">"+"<img src='img/touxiang.jpg'>"+"</div>"+"<div class='basicInfo-right' style=float:"+align+">"+"<div class='username' style=text-align:"+align+">"+"<span>"+msg.nickname+"</span>&nbsp;"+"<span>"+msg.date+"</span>"+"</div>"+"<div class='context'>"+"<span>"+msg.content+"</span>"+"</div>"+"</div>"+"</div>");}if(msg.flag == "exitroom"){      //退出房间$(".center-info").append("<div class='welcome'>"+msg.message+"</div>");//刷新成员列表refreshMember(msg.uname)}$(".center-info").scrollTop(999999); //让滚动条始终保持在最下}$(".exitroom").click(function(){            //退出房间socket.send(exitroom); //向服务器发送退出房间的信号location.href="/Chatroom/home/list.do"; //跳转到前一个页面})function refreshMember(data){$(".member").html("");for(var i=0;i<data.length;i++){$(".member").append("<div class='memberInfo'>"+"<div class='userpic'>"+"<img src='img/touxiang.jpg'>"+"</div>"+"<span class='username'>"+data[i]+"</span>"+"</div>")}}})
</script><body>
<div class="body-left"><div class="left-info"><div class="roomname">欢迎来到:<h1 style="display: inline-block;" class="roomid">1704</h1></div><div class="member"><div class="memberInfo"><span class="username">ddd</span></div></div></div>
</div>
<div class="body-center"><div class="center-info"></div><textarea class="center-input"></textarea><div class="ensure"><button>发送</button></div>
</div><div class="body-right">
</div><span class="uname" style="display:none"></span></body></html>

文件布局

Spring Boot使用websocket实现聊天室相关推荐

  1. springboot 使用 Spring Boot WebSocket 创建聊天室 2-11

    什么是 WebSocket WebSocket 协议是基于 TCP 的一种网络协议,它实现了浏览器与服务器全双工(Full-duplex)通信-允许服务器主动发送信息给客户端. 以前,很多网站为了实现 ...

  2. java开发websocket聊天室_java实现基于websocket的聊天室

    [实例简介] java实现基于websocket的聊天室 [实例截图] [核心代码] chatMavenWebapp └── chat Maven Webapp ├── pom.xml ├── src ...

  3. SpringBoot + Vue 实现基于 WebSocket 的聊天室(单聊)

    前言 在前一篇文章SpringBoot 集成 STOMP 实现一对一聊天的两种方法中简单介绍了如何利用 STOMP 实现单聊,本文则将以一个比较完整的示例展示实际应用,不过本文并未使用 STOMP,而 ...

  4. SSM(五)基于webSocket的聊天室

    SSM(五)基于webSocket的聊天室 前言 不知大家在平时的需求中有没有遇到需要实时处理信息的情况,如站内信,订阅,聊天之类的.在这之前我们通常想到的方法一般都是采用轮训的方式每隔一定的时间向服 ...

  5. 基于WebSocket实现聊天室(Node)

    基于WebSocket实现聊天室(Node) WebSocket是基于TCP的长连接通信协议,服务端可以主动向前端传递数据,相比比AJAX轮询服务器,WebSocket采用监听的方式,减轻了服务器压力 ...

  6. spring boot 集成 websocket 实现消息主动推送

    前言 http协议是无状态协议,每次请求都不知道前面发生了什么,而且只可以由浏览器端请求服务器端,而不能由服务器去主动通知浏览器端,是单向的,在很多场景就不适合,比如实时的推送,消息通知或者股票等信息 ...

  7. 基于django channel 实现websocket的聊天室

    websocket ​ 网易聊天室? ​ web微信? ​ 直播? 假如你工作以后,你的老板让你来开发一个内部的微信程序,你需要怎么办?我们先来分析一下里面的技术难点 消息的实时性? 实现群聊 现在有 ...

  8. 视频教程-基于Java的WebSocket的聊天室-Java

    基于Java的WebSocket的聊天室 多年 Java 企业级应用开发工作经验,曾参与中国人寿.华夏人寿.泰康人寿.信达财险等保险行业内部业务管理系统以及线上在线产品的开发:参与中国人民银行.清华大 ...

  9. SpringBoot2.x系列教程(四十五)Spring Boot集成WebSocket实现技术交流群功能

    在上篇文章中,我们了解了WebSocket的基本功能及相关概念.本篇文章中我们以具体的实例来演示,在Spring Boot中整合WebSocket,同时实现一个场景的业务场景功能. 针对在Spring ...

最新文章

  1. android sqlite操作(2)
  2. python编写统计选票的程序_使用python编写微信公众号发稿统计程序
  3. Nsis 使用1-- 依条件显示自定义页面 custom page on condition
  4. OD 快捷键使用大全。非常详细( 游戏逆向分析必看 )+ OD 断点 使用大全
  5. 45 WM配置-作业-库存盘点-清除差异(库存管理接口)
  6. C语言-获取当前时间-格式化输出(完整代码)
  7. 【机器学习】xgboost以及lightgbm资料汇总
  8. C# Winform 实现Ajax效果自定义按钮
  9. MySQL安装配置详解(5.5 For Windows)
  10. 澳大利亚通信软件服务公司 Whispir 完成1175万美元 A 轮融资
  11. EXCEL怎样完整显示身份证号码
  12. 快速启动器工具 Maye(转载)
  13. 好消息!电商工具箱API详情接口,更全面
  14. Android之本地数据存储(SQLite数据库)
  15. excel文件修复工具_Excel文件打开后出错,部分内容丢失的修复技巧
  16. Java Mission Control(JMC)介绍
  17. java无法验证证书_如何解决“证书无效,不能用于验证本网站的身份”错误?...
  18. C++ lock_guard 自动释放锁
  19. 树莓派 zero 通过 max31865 连接 PT100 热电阻 测量温度
  20. java map 参数传递_Java参数传递分析

热门文章

  1. 虚拟语气用法总结及真题解析
  2. [MODIS数据处理#2]常用的Arcmap内置工具(一)
  3. win2008降级为成员服务器_Windows2008R2 AD降级错误解决方案
  4. 华为设备ARP配置命令
  5. C51数字钟程序-ZT(拿来学习用)
  6. 迎风破局·守正创新,2021未来商业生态链接大会暨第六届金陀螺奖颁奖典礼成功举办!...
  7. TimeZone.getTimeZone(GMT-8:00)和TimeZone.getTimeZone(America/Los_Angeles)的区别
  8. 通过AI实现实时数据分析和态势监测,进而让机器能够处理日常决策
  9. 十款英文像素字体下载
  10. android定义颜色数组,android – 我如何保存在array.xml中的颜色,并让它回到Color []数组...