前端(Vue):
<
template
>
<
div
></
div
>
</
template
>
<
script
>
export default {
name:
"chatRoomSurvey",
data() {
return {
chatRoomWebsocket:
null
}
},
computed: {
// ...
},
created() {
// 初始化 websocket
this.
initWebSocket()
},
methods: {
// 初始化 websocket 连接
initWebSocket() {
if (
typeof
WebSocket !=
'undefined') {
this.
supported =
"支持 websocket"
}
else {
this.
supported =
"不支持 websocket"
}
//ws地址
const
wsuri =
"ws://" +
this.
currentUrlPath +
"/websocket/" +
this.
$route.
params.
chatRoomId +
"/" +
this.
$store.
state.
user.
token +
"/" +
this.
chatRoomData.hostUser;
this.
chatRoomWebsocket =
new
WebSocket(
wsuri);
this.
chatRoomWebsocket.
onerror =
this.
websocketOnError
this.
chatRoomWebsocket.
onmessage =
this.
websocketOnMessage
this.
chatRoomWebsocket.
onclose =
this.
websocketOnClose
},
//连接发生错误的回调方法
websocketOnError() {
console.
log(
"WebSocket 连接发生错误")
},
//接收到消息的回调方法
websocketOnMessage(event) {
// 接收消息
let
data =
JSON.
parse(event.
data)
// ...
},
//连接关闭的回调方法
websocketOnClose(e) {
console.
log(
"WebSocket 连接关闭", e)
console.
log(
this.
chatRoomWebsocket)
},
//关闭 WebSocket 连接
websocketClose() {
this.
chatRoomWebsocket.
close()
},
// 判断是否是 url
isURL(str_url) {
var
strRegex =
/^((https|http|ftp|rtsp|mms)?:\/\/)?(([0-9a-z_!~*'().&=+$%-]+: )?[0-9a-z_!~*'().&=+$%-]+@)?((\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5]$)|([0-9a-z_!~*'()-]+\.)*([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\.[a-z]{2,6})(:[0-9]{1,4})?((\/?)|(\/[0-9a-zA-Z_!~*'().;?:@&=+$,%#-]+)+\/?)$/;
var
re =
new
RegExp(
strRegex);
return
re.
test(str_url)
},
// 发送消息
sendContent() {
let
messageData = {
chatRoomId:
this.
$route.
params.
chatRoomId,
chatUser:
this.
$store.
state.
user.
token,
chatAvatar:
this.
userInfo.
userAvatar,
chatNickName:
this.
userInfo.
userNickNameTem +
this.
backgroundInfo,
chatContent:
this.
text,
chatType:
"1"
}
if (
this.
chatRoomWebsocket.
readyState !=
'1') {
// 如果按下按钮时socket 不是连接状态,重连并等到连接成功再发送消息
this.
initWebSocket()
this.
chatRoomWebsocket.
onopen = () => {
this.
chatRoomWebsocket.
send(
JSON.
stringify(
messageData));
this.
content.
push({
askImg:
this.
userInfo.
userAvatar,
askContent:
this.
text,
askNickName:
this.
userInfo.
userNickNameTem +
this.
backgroundInfo,
userId:
this.
chatRoomData.hostUser
})
this.
$refs.sTest.
value =
''
// 清空输入框的内容
// viewbox 移动到最底部
this.
viewboxScrollToBottom()
}
}
else {
this.
chatRoomWebsocket.
send(
JSON.
stringify(
messageData));
this.
content.
push({
askImg:
this.
userInfo.
userAvatar,
askContent:
this.
text,
askNickName:
this.
userInfo.
userNickNameTem +
this.
backgroundInfo,
userId:
this.
chatRoomData.hostUser
})
this.
$refs.sTest.
value =
''
// 清空输入框的内容
// viewbox 移动到最底部
this.
viewboxScrollToBottom()
}
},
// viewbox 移动到最底部
viewboxScrollToBottom() {
if (
this.
$refs.
viewBox) {
this.
$nextTick(() => {
// DOM 更新后再执行
this.
$refs.
viewBox.
scrollTo(
this.
$refs.
viewBox.
getScrollBody().scrollHeight +
"55")
})
}
},
},
components: {}
}
</
script
>
<
style
scoped
>
</
style
>
后端(Java):
package com.firefly.wx.controller;
import com.firefly.chatRoomRecode.domain.ChatRoomRecode;
import com.firefly.chatRoomRecode.service.IChatRoomRecodeService;
import
com.firefly.common.SpringCtx;
import net.sf.json.JSONObject;
import org.springframework.stereotype.
Component;
import org.springframework.web.socket.server.standard.SpringConfigurator;
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.util.Date;
import java.util.concurrent.ConcurrentHashMap;
/**
*
@date
2017/12/11 13:23
*/
@ServerEndpoint(value =
"/websocket/{chatRoomId}/{userId}/{hostUserId}")
@Component
public class MyWebSocket {
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int
onlineCount =
0;
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
private static ConcurrentHashMap<String, MyWebSocket>
webSocketSet =
new ConcurrentHashMap<String, MyWebSocket>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session
session;
//当前发消息的聊天室编号
private String
chatRoomId =
"";
//当前发消息的用户编号
private String
userId =
"";
//该次连接所属的聊天室的主持人 id
private String
hostUserId =
"";
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(
@PathParam(value =
"chatRoomId") String param1,
@PathParam(value =
"userId") String param2,
@PathParam(value =
"hostUserId") String param3, Session session)
throws Exception {
chatRoomId = param1;
userId = param2;
hostUserId = param3;
this.
session = session;
webSocketSet.put(
"room" + param1 +
"-" +
"user" + param2,
this);
//加入 map 中
addOnlineCount();
//在线数加1
System.
out.println(
"有新连接加入!当前在线人数为" +
getOnlineCount());
// 若该用户不是主持人
if (!
userId.equals(
hostUserId)) {
// 普通用户上线时给主持人发送当前房间在线情况
System.
out.println(
"普通用户上线时给主持人发送当前房间在线情况");
sendOnlinePersonnel(
chatRoomId,
hostUserId);
// 遍历 hashmap 查询主持人是否上线
for (String key :
webSocketSet.keySet()) {
if (key.equals(
"room" + param1 +
"-" +
"user" +
hostUserId)) {
// 给自己发主持人已上线
JSONObject jso =
new JSONObject();
jso.put(
"messageType",
"2");
jso.put(
"data",
true);
System.
out.println(
"自己不是主持人,主持人已上线");
sendMessage(jso.toString());
return;
}
}
// 给自己发主持人未上线
JSONObject jso =
new JSONObject();
jso.put(
"messageType",
"2");
jso.put(
"data",
false);
System.
out.println(
"自己不是主持人,主持人未上线");
sendMessage(jso.toString());
}
else {
// 群发主持人已上线
JSONObject jso =
new JSONObject();
jso.put(
"messageType",
"2");
jso.put(
"data",
true);
System.
out.println(
"自己是主持人,主持人已上线");
sendInfoForAll(
chatRoomId,
userId, jso.toString());
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose()
throws Exception {
System.
out.println(
"当前想要删除的webSocketSet:" +
"room" +
chatRoomId +
"-" +
"user" +
userId);
if (!
userId.equals(
"")) {
webSocketSet.remove(
"room" +
chatRoomId +
"-" +
"user" +
userId);
//从set中删除
subOnlineCount();
//在线数减1
System.
out.println(
"有一连接关闭!当前在线人数为" +
getOnlineCount());
// 若该用户是主持人
if (
userId.equals(
hostUserId)) {
// 给所有人群发发主持人已下线
JSONObject jso =
new JSONObject();
jso.put(
"messageType",
"2");
jso.put(
"data",
false);
sendInfoForAll(
chatRoomId,
userId, jso.toString());
}
else {
// 普通用户离线时给主持人发送当前房间在线情况
System.
out.println(
"普通用户下线时给主持人发送当前房间在线情况");
sendOnlinePersonnel(
chatRoomId,
hostUserId);
}
}
}
/**
* 收到客户端消息后调用的方法
*
*
@param
message
客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, Session session)
throws Exception {
JSONObject jsStr = JSONObject.
fromObject(message);
System.
out.println(
"-------------------------------------------");
// 发来的不是查询在线情况的,也不是公告相关
if (!jsStr.get(
"chatType").toString().equals(
"3") && !jsStr.get(
"chatType").toString().equals(
"2")) {
// 普通文字消息需要保存到数据库中,视频或者图片另有别的后台 api 保存
if (jsStr.get(
"chatType").toString().equals(
"1")) {
System.
out.println(
"来自客户端的消息:" + jsStr.get(
"chatContent").toString());
// 发来的是聊天消息
ChatRoomRecode chatRoomRecode =
new ChatRoomRecode();
chatRoomRecode.setChatContent(jsStr.get(
"chatContent").toString());
chatRoomRecode.setChatRoomId(Long.
valueOf(jsStr.get(
"chatRoomId").toString()));
chatRoomRecode.setChatUser(Long.
valueOf(jsStr.get(
"chatUser").toString()));
chatRoomRecode.setChatTime(
new java.sql.Date(
new Date().getTime()));
chatRoomRecode.setChatType(jsStr.get(
"chatType").toString());
chatRoomRecode.setChatNickName(jsStr.get(
"chatNickName").toString());
chatRoomRecode.setChatAvatar(jsStr.get(
"chatAvatar").toString());
// 往数据库中存入聊天的信息
IChatRoomRecodeService chatRoomRecodeService = SpringCtx.
getBeanByClass(IChatRoomRecodeService.
class);
Boolean isOK = chatRoomRecodeService.insert(chatRoomRecode);
}
// 发送消息
JSONObject jso =
new JSONObject();
jso.put(
"chatContent", jsStr.get(
"chatContent").toString());
jso.put(
"chatAvatar", jsStr.get(
"chatAvatar").toString());
jso.put(
"chatNickName", jsStr.get(
"chatNickName").toString());
jso.put(
"chatUser", jsStr.get(
"chatUser").toString());
// 普通的消息是 1,主持人上下线的消息是 2
jso.put(
"messageType",
"1");
sendInfoForAll(
chatRoomId,
userId, jso.toString());
}
else if (jsStr.get(
"chatType").toString().equals(
"3")) {
// 发来的是需要查询当前聊天室人员在线情况的消息
sendOnlinePersonnel(
chatRoomId,
hostUserId);
}
}
/**
* 发生错误时调用
*
*
@OnError
*/
public void onError(Session session, Throwable error) {
System.
out.println(
"发生错误");
error.printStackTrace();
}
/**
* 发送消息
*
*
@OnError
*/
public void sendMessage(String message)
throws IOException {
// this.session.getBasicRemote().sendText(message);
this.
session.getAsyncRemote().sendText(message);
}
/**
* 给该聊天室的主持人发送当前聊天室内的人员在线情况
*
*
@OnError
*/
public static void sendOnlinePersonnel(String chatRoomId, String hostUserId)
throws IOException {
JSONObject jsonObject =
new JSONObject();
jsonObject.put(
"messageType",
"3");
JSONObject jsonObjectPersonnel =
new JSONObject();
// 遍历 hashmap
for (String key :
webSocketSet.keySet()) {
String[] keyArr = key.split(
"-");
// 房间号相同
if (keyArr[
0].equals(
"room" + chatRoomId)) {
jsonObjectPersonnel.put(keyArr[
1].substring(
4),
true);
}
}
jsonObject.put(
"onlinePersonnel", jsonObjectPersonnel);
if (!(
webSocketSet.get(
"room" + chatRoomId +
"-" +
"user" + hostUserId) +
"").equals(
"null")) {
webSocketSet.get(
"room" + chatRoomId +
"-" +
"user" + hostUserId).sendMessage(jsonObject.toString());
}
}
/**
* 群发给该聊天室不是自己的所有人
*
*
@OnError
*/
public static void sendInfoForAll(String chatRoomId, String userId, String info)
throws IOException {
// 群发消息
// 遍历 hashmap
for (String key :
webSocketSet.keySet()) {
try {
String[] keyArr = key.split(
"-");
// System.out.println("-------------------------------------------");
// System.out.println("keyArr[0].equals(\"room\" + chatRoomId)");
// System.out.println(keyArr[0].equals("room" + chatRoomId));
// System.out.println("!keyArr[1].equals(\"user\" + userId)");
// System.out.println(!keyArr[1].equals("user" + userId)); && !keyArr[1].equals("user" + userId)
if (keyArr[
0].equals(
"room" + chatRoomId) && !keyArr[
1].equals(
"user" + userId)) {
webSocketSet.get(key).sendMessage(info);
}
}
catch (IOException e) {
System.
out.println(
"e:" + e);
e.printStackTrace();
}
}
}
/**
* 群发自定义消息
*/
// public static void sendInfo(String message) throws IOException {
// for (MyWebSocket item : webSocketSet) {
// try {
// item.sendMessage(message);
// } catch (IOException e) {
// continue;
// }
// }
// }
public static synchronized int getOnlineCount() {
return
onlineCount;
}
public static synchronized void addOnlineCount() {
MyWebSocket.
onlineCount++;
}
public static synchronized void subOnlineCount() {
MyWebSocket.
onlineCount--;
}
}