Java+Springboot+Websocket在线聊天室
1、什么是websocket?
websocket是由HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。它是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
2、为啥要实现web在线聊天程序?
最近在学习过程中看到了websocket协议,于是就有了一个想法想使用springboot+websocket实现一个web在线聊天的demo。
花了一点时间,边学习边搭建,最终实现了下面的一个简单的web在线聊天的demo,特在这里记录一下。既是为了分享给大家,也是为了给自己的学习留下一个痕迹,用以不断夯实自己的技术能力。
3、实现结果
先上几个截图,提前展示一下实现结果
4、实现过程
4.1、创建一个springboot项目,命名为chat,并在pom.xml文件中添加需要的maven依赖
<dependencies><!-- springboot依赖包 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- json 工具包 --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>RELEASE</version></dependency><!-- websocket依赖包 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>
</dependencies>
4.2、添加yml配置信息
server:port: 8090servlet:context-path: /chatroomspring:resources:static-locations: classpath:/,classpath:/static/
4.3、修改springboot启动类
package com.crwl.chatroom;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;@SpringBootApplication
public class ChatroomApplication {public static void main(String[] args) {SpringApplication.run(ChatroomApplication.class, args);}//将ServerEndpointExporter 注册为一个spring的bean@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}
4.4、准备websocket的工具类,dto类以及enum类
WsTool .java(websocket工具类)
package com.crwl.chatroom.util;import com.alibaba.fastjson.JSON;
import com.crwl.chatroom.dto.ChatMsg;
import com.crwl.chatroom.dto.ChatUser;
import com.crwl.chatroom.enums.ChatEnum;import javax.websocket.RemoteEndpoint;
import javax.websocket.Session;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;public class WsTool {public static final Map<String, Session> LIVING_SESSIONS_CACHE = new ConcurrentHashMap<>();public static final Map<String, ChatUser> LIVING_USER_CACHE = new ConcurrentHashMap<>();public static void sendMessageAll(ChatMsg chatMsg) {LIVING_SESSIONS_CACHE.forEach((sessionId, session) -> {sendMessage(session, chatMsg);});}/*** 发送给指定用户消息* @param session 用户 session* @param chatMsg 发送内容*/public static void sendMessage(Session session, ChatMsg chatMsg) {if (session == null) {return;}final RemoteEndpoint.Basic basic = session.getBasicRemote();if (basic == null) {return;}try {basic.sendText(JSON.toJSONString(chatMsg));} catch (IOException e) {e.printStackTrace();}}/**** 刷新在线用户*/public static void refreshOnlineUserList(){ChatMsg chatMsg = new ChatMsg();chatMsg.setType(ChatEnum.USER_LIST.getCode());List<ChatUser> userList = new ArrayList<ChatUser>(WsTool.LIVING_USER_CACHE.values());chatMsg.setOnlineUserList(userList);sendMessageAll(chatMsg);}
}
ChatMsg.java(聊天信息Dto)
package com.crwl.chatroom.dto;import java.util.List;public class ChatMsg {//消息类型 1:聊天信息 2:刷新在线用户列表private String sendUserBh;private String sendUserXm;private String type;private String msg;private List<ChatUser> onlineUserList;public String getSendUserBh() {return sendUserBh;}public void setSendUserBh(String sendUserBh) {this.sendUserBh = sendUserBh;}public String getSendUserXm() {return sendUserXm;}public void setSendUserXm(String sendUserXm) {this.sendUserXm = sendUserXm;}public String getType() {return type;}public void setType(String type) {this.type = type;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public List<ChatUser> getOnlineUserList() {return onlineUserList;}public void setOnlineUserList(List<ChatUser> onlineUserList) {this.onlineUserList = onlineUserList;}
}
ChatUser.java(聊天用户信息Dto)
package com.crwl.chatroom.dto;public class ChatUser {private String userBh;private String userName;private String onlineTime;public String getUserBh() {return userBh;}public void setUserBh(String userBh) {this.userBh = userBh;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getOnlineTime() {return onlineTime;}public void setOnlineTime(String onlineTime) {this.onlineTime = onlineTime;}
}
Result.java (封装Http请求的返回对象Dto)
package com.crwl.chatroom.dto;import java.io.Serializable;/*** 返回的对象(统一返回)** @author SmallStrong*/
public class Result implements Serializable {private static final long serialVersionUID = 3337439376898084639L;/*** 处理状态 0成功,-1 失败*/private Integer code;/*** 处理信息*/private String msg;public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}
}
ChatEnum.java(聊天类型枚举类)
package com.crwl.chatroom.enums;public enum ChatEnum {PUBLIC_MSG("1","公共聊天消息"),PRIVATE_MSG("2","私秘聊天信息"),CLOSE_SOCKET("3","关闭socket连接"),USER_LIST("4","在线用户列表"),JOIN_CHAT("5","加入聊天室");private String code;private String data;private ChatEnum(String code, String data) {this.code = code;this.data = data;}public String getCode() {return code;}public void setCode(String code) {this.code = code;}public String getData() {return data;}public void setData(String data) {this.data = data;}
}
ResultEnum.java(返回信息状态枚举类)
websocket工具类package com.crwl.chatroom.enums;public enum ResultEnum {SUCCESS(0,"成功"),FAILURE(-1,"失败");private Integer code;private String data;private ResultEnum(Integer code, String data) {this.code = code;this.data = data;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getData() {return data;}public void setData(String data) {this.data = data;}
}
ChatroomController.java(接收前端请求,并将处理结果返回前端)
package com.crwl.chatroom.controller;import com.crwl.chatroom.dto.ChatMsg;
import com.crwl.chatroom.dto.ChatUser;
import com.crwl.chatroom.dto.Result;
import com.crwl.chatroom.enums.ChatEnum;
import com.crwl.chatroom.enums.ResultEnum;
import com.crwl.chatroom.util.WsTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;//在线聊天室
@RestController
@ServerEndpoint("/connect/{userBh}/{userName}")
public class ChatroomController {private static final Logger log = LoggerFactory.getLogger(ChatroomController.class);@OnOpenpublic void openSession(@PathParam("userBh")String userBh, @PathParam("userName")String userName, Session session) {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");ChatUser chatUser = new ChatUser();chatUser.setUserBh(userBh);chatUser.setUserName(userName);chatUser.setOnlineTime(sdf.format(new Date()));WsTool.LIVING_SESSIONS_CACHE.put(userBh, session);WsTool.LIVING_USER_CACHE.put(userBh,chatUser);ChatMsg chatMsg = new ChatMsg();chatMsg.setSendUserBh(chatUser.getUserBh());chatMsg.setSendUserXm(chatUser.getUserName());chatMsg.setType(ChatEnum.JOIN_CHAT.getCode());WsTool.sendMessageAll(chatMsg);//刷新用户列表WsTool.refreshOnlineUserList();}@OnMessagepublic void onMessage(@PathParam("userBh") String userBh, String message) {log.info(message);//心跳程序if("HeartBeat".equals(message)){return;}ChatUser chatUser = WsTool.LIVING_USER_CACHE.get(userBh);ChatMsg chatMsg = new ChatMsg();chatMsg.setSendUserBh(chatUser.getUserBh());chatMsg.setSendUserXm(chatUser.getUserName());chatMsg.setType(ChatEnum.PUBLIC_MSG.getCode());chatMsg.setMsg(message);WsTool.sendMessageAll(chatMsg);}@OnClosepublic void onClose(@PathParam("userBh")String userBh, Session session) {ChatUser chatUser = WsTool.LIVING_USER_CACHE.get(userBh);//当前的Session 移除WsTool.LIVING_SESSIONS_CACHE.remove(chatUser.getUserBh());WsTool.LIVING_USER_CACHE.remove(chatUser.getUserBh());//并且通知其他人当前用户已经离开聊天室了ChatMsg chatMsg = new ChatMsg();chatMsg.setSendUserBh(chatUser.getUserBh());chatMsg.setSendUserXm(chatUser.getUserName());chatMsg.setType(ChatEnum.CLOSE_SOCKET.getCode());WsTool.sendMessageAll(chatMsg);//刷新用户列表WsTool.refreshOnlineUserList();try {session.close();} catch (IOException e) {e.printStackTrace();}}@OnErrorpublic void onError(Session session, Throwable throwable) {try {session.close();} catch (IOException e) {e.printStackTrace();}throwable.printStackTrace();}//一对一私聊@GetMapping("/privateSend/{sendUserBh}/to/{receiveUserBh}")public Result privateSend(@PathVariable("sendUserBh") String sendUserBh, @PathVariable("receiveUserBh") String receiveUserBh, String message) {Session sendSession = WsTool.LIVING_SESSIONS_CACHE.get(sendUserBh);Session receiveSession = WsTool.LIVING_SESSIONS_CACHE.get(receiveUserBh);ChatUser sendUser = WsTool.LIVING_USER_CACHE.get(sendUserBh);ChatUser receiver = WsTool.LIVING_USER_CACHE.get(receiveUserBh);ChatMsg chatMsg = new ChatMsg();chatMsg.setSendUserBh(sendUser.getUserBh());chatMsg.setSendUserXm(sendUser.getUserName());chatMsg.setType(ChatEnum.PRIVATE_MSG.getCode());chatMsg.setMsg(message);//对发送人发送WsTool.sendMessage(sendSession, chatMsg);//接受人发送WsTool.sendMessage(receiveSession, chatMsg);Result result = new Result();result.setCode(ResultEnum.SUCCESS.getCode());return result;}
}
4.5、前端实现,前端采用iview框架+jquery,聊天输入框使用百度编辑器(ueditor)
chatroom.html
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><title>聊天室</title><link rel="stylesheet" type = "text/css" href="../static/lib/iview/css/iview.css" /><link rel="stylesheet" type = "text/css" href="css/chat.css" /><script src="../static/js/jquery-1.8.2.min.js"></script><script src="../static/lib/iview/vue.min.js"></script><script src="../static/lib/iview/iview.min.js"></script><script src="../static/js/common.js"></script><script type="text/javascript" charset="utf-8" src="../static/lib/ueditor/ueditor.config.js"></script><script type="text/javascript" charset="utf-8" src="../static/lib/ueditor/ueditor.all.js"> </script><script type="text/javascript" charset="utf-8" src="../static/lib/ueditor/lang/zh-cn/zh-cn.js"></script><script src="js/chatroom.js"></script>
</head>
<body><Layout id="app" style="overflow-y:hidden;"><Spin fix v-show="fullScreenloading"><img src="../../static/image/loadm.png" class="demo-spin-icon-load ivu-icon-load-c"></img><div>{{loadMsg}}</div></Spin><row class="chatbody"><row class="toolBar"><i-Button type="primary" icon="ios-add" :disabled="null != ws" @click="openConnectWin()">连接服务器</i-Button><i-Button type="primary" icon="ios-add" :disabled="null == ws" @click="quitServer()">退出</i-Button><div class="clearfix"></div></row><row class="chatArea"><i-col span="19" class="chatLeft"><row class="chatView"><div class="msg" v-for="msg in msgList" v-html="msg"></div></row><row class="inputArea"><row class="inputForm"><script id="editor" type="text/plain" style="width:100%;height:170px;"></script><!--<i-input :size="styleSize" type="textarea" v-model="formData.content" :rows="6"></i-input>--></row><row class="sendTool"><i-Button type="primary" @click="sendMsg()">发送</i-Button></row></row></i-col><i-col span="5" class="chatUserList"><div class="userTitle"><div class="title">成员列表</div><div class="userBtnArea"><i-Button :size="styleSize" type="primary" @click="clearChooseUser()">清除选中</i-Button></div><div class="clearfix"></div></div><ul><li :class="toUser==item.userBh?'selUser':''" @click="chooseUser(item.userBh)" v-for="item in chatUserList">{{item.userName}}<span class="loginDate">{{item.onlineTime}}</span></li></ul></i-col></row></row><Modal id="connectWin" v-model="connectModal" title="连接服务器"width="500" height="200" ><i-form ref="editValidate" :model="sendUser" :rules="editRuleValidate" :label-width="80" style="padding:5px 50px 5px 20px;overflow-y: auto;" ><i-col span="24"><form-item label="用户ID" prop="userBh"><i-input :size="styleSize" v-model="sendUser.userBh" ></i-input></form-item></i-col><i-col span="24"><form-item label="用户昵称" prop="userName"><i-input :size="styleSize" v-model="sendUser.userName" ></i-input></form-item></i-col></i-form><div class="clearfix"></div><div slot="footer"><i-Button :size="styleSize" type="primary" @click="connectServer()">连接</i-Button><i-Button :size="styleSize" type="warning" @click="cancelFunc">取消</i-Button></div></Modal></Layout>
</body>
</html>
chat.css
/*找到html标签、body标签,和挂载的标签都给他们统一设置样式*/
html,body,#app,.el-container,.el-row{/*设置内部填充为0,几个布局元素之间没有间距*/padding: 0px;/*外部间距也是如此设置*/margin: 0px;/*统一设置高度为100%*/height: 100%;
}
.chatbody{height:calc(100%);margin:15px;box-shadow:2px 3px 5px #888888;
}
.toolBar{padding:5px 10px;height:45px
}
.chatArea{height:calc(100% - 45px);margin-top:0px;/***border-top:1px solid #ccc;***/padding:5px;
}
.chatLeft{/*border-right:1px solid #ccc;height:90%;*/height: calc(100% );padding:5px;
}
.chatView{height:calc(100% - 250px);/***border-bottom:1px solid #ccc;**/padding:5px;background:#fff;overflow-y: auto;
}.inputArea{height:240px;
}
.inputForm{height:200px;
}
.sendTool{text-align:right;height:50px;line-height:50px;
}/****
在线用户列表*/
.chatUserList{/***border-bottom:1px solid #ccc;**/height:calc(100% - 10px);margin:5px 0;padding:5px;background:#fff;
}
.userTitle{border-bottom: 1px solid #dfdfdf;font-size:16px;padding:5px 0;clear:both;
}
.clearfix{clear:both;
}
.userTitle .title{float:left;
}
.userBtnArea{float:left;margin-left:10px;margin-top:-5px;
}
.chatUserList ul li{list-style-type:none;height:35px;line-height:35px;cursor:pointer;clear:both;padding: 0 5px;
}
.loginDate{float:right;
}
.selUser{background: #2d8cf0;color: #fff;
}
.iconArea{height:45px;position:relative;
}
.icon{height:25px;width:25px;vertical-align: middle;margin-top: -5px;
}
.fl{float:left;}
.fr{float:right;}
.iconDiv{position: absolute;top:45px;background: #fff;height: 160px;width: 370px;z-index: 10;box-shadow: 1px 2px 15px #888;padding: 5px;
}
.welcome{color: #15c02e;
}
.warning{color:red;
}
.msg{margin:10px 0;position:relative;
}
.userTitleOther{float: left;width: 90px;margin-top: 5px;
}
.otherMsgContent{float:left;margin-left: 10px;padding: 10px 20px;background: #eaeaea;border-radius: 5px;
}
.triangle-left {position: absolute;left: 80px;width: 0;height: 0;border-width: 10px;border-style: solid;border-color:#FFF #eaeaea #FFF #FFF ;top: 5px;
}
.userTitleSelf{float: right;width: 90px;margin-top: 5px;padding-left: 15px;
}
.selfMsgContent{float:right;margin-right: 10px;padding: 10px 20px;background: #18cb2f;color:#fff;border-radius: 5px;
}
.triangle-right {position: absolute;right: 80px;width: 0;height: 0;border-width: 10px;border-style: solid;border-color: #FFF #FFF #FFF #18cb2f;top: 5px;
}
.private{background: red;color: #fff;border-radius: 20px;padding: 3px;
}
common.js
var commonFunc ={};
var constants ={localCurl : "http://localhost:8090/chatroom",styleSize:'small'
}commonFunc.submit=function(url,submitType, parameter, fnSuccess, fnError,contentType, Async){//判断是否需要同步ajaxif (typeof (Async) == "undefined") {Async = true;};if(contentType == "obj"){parameter = JSON.stringify(parameter);contentType = "application/json; charset=utf-8";}else if(contentType == "upload"){//contentType = "application/x-www-form-urlencoded;charset=UTF-8";}else {contentType = "application/x-www-form-urlencoded;charset=UTF-8";}url = constants.localCurl+url;$.ajax({type: submitType,data: parameter,dataType: 'json',contentType:contentType,url: url,cache:false,beforeSend: function(XMLHttpRequest) {},crossDomain: true == !(document.all),xhrFields: {withCredentials: true},async: Async,success: function(data) {//服务器返回响应,根据响应结果,分析是否登录成功;var code=data.code+"";if (code == 1000) {return;} else if(code=="0"){fnSuccess(data);}else{fnError(data);}},complete: function (data) {},error: function (xhr, type, errorThrown) {//异常处理;fnError(xhr, type, errorThrown);console.log(xhr);console.log(type);console.log(JSON.stringify(errorThrown));}});
}
chatroom.js
$(function() {var height = $(window).height()-160;var _this = null;var vue = new Vue({el: '#app',data: {styleSize:constants.styleSize,fullScreenloading: false,loadMsg:'',ws:null,sendUser:{userBh:'',userName:''},formData:{content:''},chatUserList:[],msgList:[],toUser:'',timeoutObj:null,connectModal:false,editRuleValidate: {userBh:{required:true,message:'请输用户Id',trigger: 'blur'},userName:{required:true,message:'请输用户昵称',trigger: 'blur'}},},created:function(){},mounted :function(){var _this = this;this.connectServer();this.startHeart();this.ueditor = UE.getEditor('editor',{toolbars: [['emotion']],wordCount:false, //统计字数elementPathEnabled:false, //元素路径enableAutoSave:false, //自动保存});this.ueditor.ready(function() {$(".edui-editor-messageholder.edui-default").css({ "visibility": "hidden" });_this.ueditor.setHeight(170);_this.ueditor.setContent("<span></span>")_this.ueditor.focus()});//监听浏览器关闭,关闭前先关闭webSocketwindow.onbeforeunload = function () {if(null != this.ws){this.ws.close();}};},methods: {openConnectWin(){this.sendUser.userBh = "";this.sendUser.userName = "";this.connectModal = true;},cancelFunc(){this.connectModal = false;},connectServer(userBh, userName){var _this = this;this.$refs['editValidate'].validate((valid) => {if (valid) {if (null == this.ws) {var urlPrefix = 'ws://localhost:8090/chatroom/connect/';var url = urlPrefix + "/" + this.sendUser.userBh + "/" + this.sendUser.userName;this.ws = new WebSocket(url);this.connectModal = false;this.ws.onopen = function () {console.log("建立 websocket 连接...");};this.ws.onmessage = function (event) {//服务端发送的消息//console.log(event);var data = JSON.parse(event.data);//console.log(data);if (null != data && (data.type == 1 || data.type == 2)) { //聊天信息var msg = data.msg;if (data.sendUserBh == _this.sendUser.userBh) {if (data.type == 1) { //公共聊天信息msg = "<div class=\"triangle-right\"></div><div class='userTitleSelf'>" + _this.sendUser.userName + "</div> " +'<div class="selfMsgContent">' + msg + '</div>';}if (data.type == 2) { //私人聊天信息msg = "<div class=\"triangle-right\"></div><div class='userTitleSelf'><span class='private'>私</span>" + _this.sendUser.userName + "</div> " +'<div class="selfMsgContent">' + msg + '</div>';}_this.msgList.push("<div class='fr'>" + msg + "</div><div class='clearfix'></div>");} else {if (data.type == 1) { //公共聊天信息msg = "<div class=\"triangle-left\"></div><div class='userTitleOther'>" + data.sendUserXm + "</div> " +'<div class="otherMsgContent">' + msg + '</div>';}if (data.type == 2) { //私人聊天信息msg = "<div class=\"triangle-left\"></div><div class='userTitleOther'>" + data.sendUserXm + "<span class='private'>私</span></div> " +'<div class="otherMsgContent">' + msg + '</div>';}_this.msgList.push("<div class='fl'>" + msg + "</div><div class='clearfix'></div>");}//+'<img src="../../static/image/happy.png" class="icon"/>'}//刷新在线列表if (null != data && data.type == 4) {_this.chatUserList = data.onlineUserList;}//用户进入聊天室if (null != data && data.type == 5) {msg = "<div class='welcome'>用户[" + (data.sendUserXm) + "]进入了聊天室!</div>";_this.msgList.push(msg);}//用户离线if (null != data && data.type == 3) {msg = "<div class='warning'>用户[" + (data.sendUserXm) + "]已经离开聊天室!</div>";_this.msgList.push(msg);}_this.toBottom();};this.ws.onclose = function (event) {_this.ws = null;_this.chatUserList.splice(0, _this.chatUserList.length);_this.toBottom();}this.ws.onerror = function (event) {//console.log(event.data);_this.ws = null;_this.sendUser = {userBh: '',userName: ''}};} else {this.$Message.error("已经建立服务器连接,请不要重复连接");}}});},quitServer(){if(null != this.ws){this.ws.close()this.ws = null;}},toBottom(){setTimeout(function(){$('.chatView').scrollTop($('.chatView').get(0).scrollHeight+150);},200)},sendMsg(){var _this =this;if(null != this.ws) {var content = this.ueditor.getContent();if (null == content || "" == content.trim()) {this.$Message.error("请输入聊天信息");return;}content = content.trim();if(null == this.toUser || this.toUser == ""){this.ws.send(content)}else{var sendUserBh = this.sendUser.userBh;var url = "/privateSend/"+sendUserBh+"/to/"+this.toUser+"?message="+contentcommonFunc.submit(url,"get",{},function(data){if(data.code != "0"){_this.$Message.error("发送信息失败");}},function(data){_this.$Message.error("发送信息失败");});}this.ueditor.setContent("")this.ueditor.focus(true);$("#ueditor_0").html("");}else{this.$Message.error("请先点击【连接服务器】建立网络连接");}},chooseUser(toUser){if(toUser != this.sendUser.userBh){this.toUser = toUser;}},clearChooseUser(){if(null != this.toUser && '' != this.toUser){this.toUser='';}else{this.$Message.error("您未选择私聊用户");}},startHeart: function () { //设置心跳程序,避免nginx(设置的5分钟)超时断开长连接var _this = this;this.timeoutObj && clearTimeout(this.timeoutObj);this.timeoutObj = setTimeout(function () {//这里发送一个心跳,后端收到后,返回一个心跳消息,//onmessage拿到返回的心跳就说明连接正常if(null != _this.ws){_this.ws.send("HeartBeat");console.log('ping');_this.startHeart();}}, 5*60*1000)}}});//此处将vue对象作用域上提至window返回,用户实现ueditor的crtl+enter事件window.vue = vue;
});
到此,整个web在线聊天的demo程序就搭建完成。
其中输入框的快捷键发送(crtl+enter)需要在ueditor.all.js文件中的指定位置增加一段内容,先搜索“autosubmit”,在execCommand代码块中加入以下内容
if(null != window.vue){window.vue.sendMsg();
}
5、程序的运行
选中项目启动类ChatroomApplication.java,右键鼠标,单击Run’ChatroomApplication’启动项目。
启动成功后,打开浏览器,输入http://localhost:8090/chatroom/web/chatroom.html即可进入聊天室
点击连接服务器,弹出连接服务器弹窗,输入用户Id以及用户昵称,点击【连接】按钮即可以连接进聊天服务器
直接输入信息,快捷键输入crtl+enter组合键或者点击【发送】按钮直接群发聊天信息,如果需要一对一私聊,可以先在右边在线用户列表中选择需要聊天的用户后输入私聊信息,快捷键输入crtl+enter组合键或者点击【发送】按钮向指定用户私人发送聊天信息
到此,web在线聊天程序记录分享结束。
Java+Springboot+Websocket在线聊天室相关推荐
- java websocket 微服务_微服务-springboot+websocket在线聊天室
一.引入依赖 org.springframework.boot spring-boot-starter-websocket 二.注入ServerEndpointExporter 编写一个WebSock ...
- 视频教程-基于Java的WebSocket的聊天室-Java
基于Java的WebSocket的聊天室 多年 Java 企业级应用开发工作经验,曾参与中国人寿.华夏人寿.泰康人寿.信达财险等保险行业内部业务管理系统以及线上在线产品的开发:参与中国人民银行.清华大 ...
- SpringBoot搭建在线聊天室
Echat-SpringBoot 一款轻量级的基于SpringBoot + WebSocket的在线聊天室项目,在MccreeFei的聊天室基础上,将其升级为SpringBoot版本,去掉了JSP文件 ...
- 简单两步,用Java实现网络在线聊天室
Echat在线聊天室 一款轻量级的基于SpringBoot + WebSocket的在线聊天室项目,在MccreeFei的聊天室基础上,将其升级为SpringBoot版本,去掉了JSP文件,去掉了xm ...
- 嘿从零开始基于SpringBoot 打造在线聊天室(4.4W字最长博文)
文章目录 前言 效果 主页面 消息提示 聊天页面 登录注册 前端 项目构建 依赖 项目结构 登录注册 验证码部分 登录页面 注册页面 主页面 流程 websocket loadmessage 消息发送 ...
- 使用 Springboot websocket 实现聊天室
文章首发于个人博客,欢迎访问关注:https://www.lin2j.tech 通过使用spring集成的websocket和原生H5,实现一个聊天室,以此加深对websocket的了解. 文末会附带 ...
- phoengap–node+websocket在线聊天室
该实验项目基于: phonegap node websocket 可以应用于android 和 ios平台. 已经测试通过.以下是测试的图: 首先是用node 架设服务器. 基本上都node 基 ...
- rudesocket如何使用_[WebSocket入门]手把手搭建WebSocket多人在线聊天室(SpringBoot+WebS...
前言 本文中搭建了一个简易的多人聊天室,使用了WebSocket的基础特性. 源代码来自老外的一篇好文: 本文内容摘要: 初步理解WebSocket的前后端交互逻辑 手把手使用 SpringBoot ...
- SpringBoot 使用WebSocket打造在线聊天室(基于注解)
点击上方"好好学java",选择"置顶公众号" 优秀学习资源.干货第一时间送达! 精彩内容 java实战练习项目教程 2018微服务资源springboot.s ...
最新文章
- 关于MySQL的酸与MVCC和面试官小战三十回合
- MPB:山大倪金凤组-黄翅大白蚁肠道放线菌的分离与培养
- NS4146 D类音频放大电路
- mongodb模糊查询包含特殊字符
- html 地址坐标图标,浏览器地址栏中显示自定义小图标
- “北航Clubs” Beta版本开发目标
- 实数系的基本定理_初中篇1|知实数-为什么0.9的循环等于1?
- python pandas读取txt文件_python Pandas 读取txt表格的实例
- 鸿蒙安卓数据互通吗,假如鸿蒙与安卓之间不能够实现游戏账号互通,你还会为其买单吗?...
- REBOOT Reload - 可安装在优盘的 Windows 和 DOS 启动盘
- c/c++ 基金会(七) 功能覆盖,虚函数,纯虚函数控制
- tshark 解析pcap中带TLS协议的数据包
- 用scrapy框架爬虫时遇到的错误ValueError: Missing scheme in request url: //scpic3.chinaz.net/Files/pic/pic 9/2021
- 移远BC28_opencpu方案_pin脚分配
- 万豪国际集团公布新任首席执行官和总裁
- 2021-01-20
- 移动端知网下文献并投屏PC端阅读
- 【MFC】数据库操作——ODBC(20)
- linux对电子信息工程专业的意义,电子信息工程专业的学生应该考哪些必要的资格证书? (1)...
- 产品经理经典面试题or笔试题
热门文章
- 炉石传说服务器维护有补偿吗,炉石传说2017年服务器故障回档补偿公告
- osgi框架 android,android osgi
- 小程序自定义navigationBar组件以及上滑修改navigationBar
- 【项目精选】百货中心供应链管理系统
- 社会主义核心价值观解码
- 数据库的概念模型,联系,E-R模型的设计方法
- python和cc哪个适合做游戏的背景音乐_好听的歌曲,适合在活动游戏环节的背景音乐...
- ffmpeg 打包TS介绍
- 起底全球收购狂,博通(Broadcom)为什么能这么豪横?
- 机房空调中断多久对服务器影响,机房空调故障之后,大家都惊呆了……