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: 8090
servlet:
context-path: /chatroom
spring:
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
@Bean
public 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);
@OnOpen
public 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();
}
@OnMessage
public 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);
}
@OnClose
public 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();
}
}
@OnError
public 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){
//判断是否需要同步ajax
if (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()
});
//监听浏览器关闭,关闭前先关闭webSocket
window.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="+content
commonFunc.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在线聊天程序记录分享结束。