- Spring使用WebSocket,发送图片、表情、消息、心跳机制
- 项目地址:https://gitee.com/BestJohnny/spring-web-socket
IndexController.java
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.johnny.websocket.WebSocket;
@Controller
public class IndexController {
@Autowired
WebSocket webSocket;
@GetMapping("/ws")
public String webSocket(HttpServletRequest request, HttpServletResponse response) {
request.setAttribute("rootPath", request.getContextPath());
return "webSocket";
}
@GetMapping("/index1")
public String index1() {
return "index1";
}
@GetMapping("/index2")
public String index2() {
return "index2";
}
@ResponseBody
@GetMapping("/getUserMenu")
public String index3() {
return null;
}
@ResponseBody
@GetMapping("/sendToOne")
public void sendToOne(@RequestParam("from") String from, @RequestParam("to") String to, @RequestParam("text") String text, @RequestParam("type") String type) throws IOException {
JSONObject json = new JSONObject();
json.put("from", from);
json.put("to", to);
json.put("text", text);
json.put("type", type);
webSocket.sendMessageTo(to, json.toString());
}
@ResponseBody
@GetMapping("/sendToAll")
public void sendToAll(@RequestParam("from") String from, @RequestParam("to") String to, @RequestParam("text") String text, @RequestParam("type") String type) throws IOException {
JSONObject json = new JSONObject();
json.put("from", from);
json.put("to", to);
json.put("text", text);
json.put("type", type);
webSocket.sendMessageAll(json.toString());
}
}
WebSocketConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
// 这个bean的注册,用于扫描带有@ServerEndpoint的注解成为websocket ,如果你使用外置的tomcat就不需要该配置文件
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
WebSocket.java
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
/**
* WebSocketServer接收请求https://blog.csdn.net/qq_42402854/article/details/130948270
*
* @Contacts 171471869@163.com
* @Author Johnny_阿阳
* @Date 2023-04-10 10:42:19
*/
@Component
@ServerEndpoint("/webSocket/{userName}")
public class WebSocket {
public static final Logger log = LogManager.getLogger(WebSocket.class);
// 心跳机制
private Timer heartBeatTimer;
// 是否已关闭
private boolean isClosed;
// 用户名称
private String userName;
// 会话
private Session session;
// 在线人数
private static AtomicInteger onlineSessionClientCount = new AtomicInteger(0);
// 存放所有在线的客户端
private static Map<String, Session> onlineSessionClientMap = new ConcurrentHashMap<>();
// 以用户的姓名为key,WebSocket为对象保存起来
private static Map<String, WebSocket> clients = new ConcurrentHashMap<String, WebSocket>();
public WebSocket() {
this.isClosed = false;
}
/**
* 连接建立成功调用的方法。由前端<code>new WebSocket</code>触发
*
* @param userName 每次页面建立连接时传入到服务端的id,比如用户id等。可以自定义。
* @param session 与某个客户端的连接会话,需要通过它来给客户端发送消息
*/
@OnOpen
public void onOpen(@PathParam("userName") String userName, Session session) {
this.userName = userName;
this.session = session;
this.session.setMaxIdleTimeout(5 * 60 * 1000);
this.startHeartBeat();
String sessionId = session.getId();
clients.put(userName, this);// 把自己的信息加入到map当中去
onlineSessionClientMap.put(userName, session);// 将页面的userName和session绑定或者session.getId()与session
onlineSessionClientCount.incrementAndGet();// 在线数加1
// 给所有人发送上线通知type=0,from=userName
Message message1 = new Message(userName, "", "给所有人发送上线通知", "0");
String msg1 = JSON.toJSONString(message1, true);
sendTextToAll(msg1);
// 给自己发送在线人员type=0,from==to,online=[...]
Set<String> online = onlineSessionClientMap.keySet();
Message message2 = new Message(userName, userName, "给自己发送在线人员", "0", null, online);
String msg2 = JSON.toJSONString(message2, true);
sendTextToOne(userName, msg2);
// 给自己发送未读消息..
// Message message3 = new Message(null, userName, msg, "1", "-1", null);
// String msg3 = JSON.toJSONString(message3, true);
// sendTextToOne(userName, msg3);
log.debug("连接建立成功,当前在线数为:{} ==> 开始监听新连接:sessionId = {}, userName = {}", onlineSessionClientCount, sessionId, userName);
}
/**
* 连接关闭调用的方法。由前端<code>socket.close()</code>触发
*
* @param userName
* @param session
*/
@OnClose
public void onClose(@PathParam("userName") String userName, Session session) {
this.isClosed = true;
this.stoptHeartBeat();
clients.remove(userName);
onlineSessionClientMap.remove(userName);// 从 Map中移除
onlineSessionClientCount.decrementAndGet();// 在线数减1
// 给所有人发送下线通知type=-2,from=userName
Message message = new Message(userName, null, "给所有人发送下线通知", "-2");
String msg = JSON.toJSONString(message, true);
sendTextToAll(msg);
log.debug("连接关闭成功,当前在线数为:{} ==> 关闭该连接信息:sessionId = {}, userName = {}", onlineSessionClientCount, session.getId(), userName);
}
/**
* 发生错误调用的方法
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
// 给自己发送失败消息..
this.stoptHeartBeat();
String sessionId = session.getId();
Message message = new Message(null, null, "给自己发送失败消息,sessionId=" + sessionId, "-1", null, null);
String err = JSON.toJSONString(message, true);
sendTextToOne(userName, err);// 通知用户
error.printStackTrace();
}
/**
* 收到客户端消息后调用的方法。由前端<code>socket.send</code>触发 * 当服务端执行toSession.getAsyncRemote().sendText(xxx)后,前端的socket.onmessage得到监听。
*
* @param message
* @param session
*/
@OnMessage
public void onMessage(String message, Session session) {
// html界面传递来得数据格式,可以自定义message{"from":"user1","to":"user2","text":"hello","type":"0","online":"[user1,user2...]"}
JSONObject jsonObject = JSON.parseObject(message);
String text = jsonObject.getString("text");
String from = jsonObject.getString("from");
String to = jsonObject.getString("to");
log.debug("服务端收到客户端消息 ==> from = {}, to = {}, message = {}", from, to, message);
if (to == null || to == "" || "".equalsIgnoreCase(to)) {
sendTextToAll(text);
} else {
sendTextToOne(to, text);
}
}
/**
* 群发消息<后端>
*
* @param message 消息
*/
public void sendTextToAll(String message) {
onlineSessionClientMap.forEach((onlineSid, toSession) -> {// 遍历在线map集合
if (!userName.equalsIgnoreCase(onlineSid)) {
synchronized (toSession) {
log.debug("用户向服务器发送广播 ==> message = {}", message);
toSession.getAsyncRemote().sendText(message);
}
}
});
}
/**
* 指定用户发送消息<后端>
*
* @param to
* @param message
*/
public void sendTextToOne(String to, String message) {
Session toSession = onlineSessionClientMap.get(to);
synchronized (toSession) {
log.debug("用户向{}发送消息 ==> message = {}", to, message);
toSession.getAsyncRemote().sendText(message);// 异步发送
}
// try {
// toSession.getBasicRemote().sendText(message);// 同步发送
// } catch (IOException e) {
// e.printStackTrace();
// }
}
/**
* 指定用户发送消息
*
* @param message
* @param to
* @throws IOException
*/
public void sendMessageTo(String to, String message) {
for (WebSocket item : clients.values()) {
if (item.userName.equals(to)) {
log.debug("用户向{}发送消息 ==> message = {}", to, message);
item.session.getAsyncRemote().sendText(message);// 异步发送
break;
}
}
}
/**
* 群发消息
*
* @param message
* @throws IOException
*/
public void sendMessageAll(String message) {
for (WebSocket item : clients.values()) {
if (!item.userName.equalsIgnoreCase(userName)) {
log.debug("用户向服务器发送广播 ==> message = {}", message);
item.session.getAsyncRemote().sendText(message);// 异步发送
}
}
}
/**
* 启动心跳定时器
*/
private void startHeartBeat() {
this.heartBeatTimer = new Timer();
this.heartBeatTimer.schedule(new TimerTask() {
@Override
public void run() {
if (!isClosed) {
session.getAsyncRemote().sendText("");
// send();
}
}
}, 60000, 60000);
}
/**
* 停止心跳定时器
*/
private void stoptHeartBeat() {
if (this.heartBeatTimer != null) {
this.heartBeatTimer.cancel();
this.heartBeatTimer = null;
}
}
}
Message.java
import java.util.Set;
/**
* WebSocketMsg发送的消息详情
*
* @Contacts 171471869@163.com
* @Author Johnny_阿阳
* @Date 2023-04-10 10:42:19
*/
public class Message {
public String from;// 发送者name
public String to;// 接收者name
public String text;// 发送的文本
public String type;// 消息类型(-2[下线],-1[失败],0[上线],1[正常消息],2[图片])
public String status;// 消息状态(失败[-1],未读[0],已读[1]])
public Set<String> online;// 在线用户
public Message() {
super();
}
/**
*
* @param from
* @param to
* @param text
* @param type 消息类型(-2[下线],-1[失败],0[上线],1[正常消息])
*/
public Message(String from, String to, String text, String type) {
super();
this.from = from;
this.to = to;
this.text = text;
this.type = type;
}
/**
*
* @param from
* @param to
* @param text
* @param type 消息类型(-2[下线],-1[失败],0[上线],1[正常消息])
* @param status 消息状态([-1]失败,[0]未读,[1]已读])
* @param online 在线用户
*/
public Message(String from, String to, String text, String type, String status, Set<String> online) {
super();
this.from = from;
this.to = to;
this.text = text;
this.type = type;
this.status = status;
this.online = online;
}
public String getFrom() {
return from;
}
public String getTo() {
return to;
}
public String getText() {
return text;
}
public String getType() {
return type;
}
public String getStatus() {
return status;
}
public Set<String> getOnline() {
return online;
}
public void setFrom(String from) {
this.from = from;
}
public void setTo(String to) {
this.to = to;
}
public void setText(String text) {
this.text = text;
}
public void setType(String type) {
this.type = type;
}
public void setStatus(String status) {
this.status = status;
}
public void setOnline(Set<String> online) {
this.online = online;
}
@Override
public String toString() {
return "Message [from=" + from + ", to=" + to + ", text=" + text + ", type=" + type + ", status=" + status + ", online=" + online + "]";
}
}
webSocket.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title>Insert title here</title>
<link rel="stylesheet" th:href="@{/static/FrameworkModule/pear/css/pear.css}">
<link rel="stylesheet" th:href="@{/static/admin/css/load.css}"/>
<link rel="stylesheet" th:href="@{/static/admin/css/admin.css}"/>
<link rel="stylesheet" th:href="@{/static/users/css/index.css}"/>
<link rel="stylesheet" th:href="@{/static/users/css/sphere.css}">
<link rel="stylesheet" th:href="@{/static/users/css/chat.css}">
<link rel="stylesheet" th:href="@{/static/FrameworkModule/emoji/dist/css/jquery.mCustomScrollbar.min.css}">
<link rel="stylesheet" th:href="@{/static/FrameworkModule/emoji/dist/css/jquery.emoji.css}">
</head>
<body>
<div id="id-layer-wrapper" >
<div class="layout">
<!-- 左侧 -->
<div class="layout-left">
<ul>
<!-- 头像 -->
<li >
<div class="header-img">
<img src="./static/chat/dist/media/img/avatar1.jpg" class="my-header-img rounded-circle" alt="image">
</div>
</li>
<!-- 用户 -->
<li class="left-menu active" title="用户">
<div class="layui-icon layui-icon-user"></div>
</li>
<!-- 声音 -->
<li class="left-menu" title="声音">
<div class="layui-icon layui-icon-notice"></div>
</li>
<!-- 菜单 -->
<li class="left-menu" title="菜单">
<div class="layui-icon layui-icon-app"></div>
</li>
<!-- 退出 -->
<li class="left-menu" title="退出">
<div class="layui-icon layui-icon-logout"></div>
</li>
</ul>
</div>
<!-- 中间 -->
<div class="layout-middle">
<!-- 在线列表 -->
<div id="online" class="online-group">
<ul class="list-group" id="online_list" ></ul>
</div>
</div>
<!-- 右侧 -->
<div class="layout-right">
<!-- 右侧头部 -->
<div class="chat-header">
<div id="chat-header" title="群聊" class="chat-header-user">
<div class="header-img">
<img src="./static/chat/dist/media/img/chat.png" class="rounded-circle" alt="image">
</div>
<div>
<h5>群聊</h5>
</div>
</div>
</div>
<!-- 右侧中间 -->
<div class="chat-body" id="messages">
<div class="messages active" title="群聊" ></div>
</div>
<!-- 右侧底部 -->
<div class="chat-footer">
<div>
<textarea id="send-Chat-Msg" class="form-control" placeholder="发送消息..."></textarea>
<div class="form-buttons">
<button title="表情" id="send-Chat-face" onclick="chatOperation(this)" class=" layui-icon layui-icon-face-smile-fine" ></button>
<button title="语言" id="send-Chat-mike" onclick="chatOperation(this)" class=" layui-icon layui-icon-mike" ></button>
<button title="发送" id="send-Chat-release" onclick="chatOperation(this)" class=" layui-icon layui-icon-release" ></button>
<button title="相机" id="send-Chat-camera" onclick="chatOperation(this)" class=" layui-icon layui-icon-camera" ></button>
<button title="文件" id="send-Chat-file" onclick="chatOperation(this)" class=" layui-icon layui-icon-file" ><input id="upload-file" type="file" name="file"/></button>
<button title="定位" id="send-Chat-location" onclick="chatOperation(this)" class=" layui-icon layui-icon-location" ></button>
</div>
</div>
</div>
</div>
</div>
</div>
<script th:src="@{/static/FrameworkModule/jquery.min.js}"></script>
<script th:src="@{/static/FrameworkModule/layui2_8/layui.js}"></script>
<script th:src="@{/static/FrameworkModule/pear/pear.js}"></script>
<script th:src="@{/static/users/js/myutil.js}"></script>
<script th:src="@{/static/FrameworkModule/emoji/dist/js/highlight.pack.js}"></script>
<script th:src="@{/static/FrameworkModule/emoji/dist/js/jquery.mousewheel-3.0.6.min.js}"></script>
<script th:src="@{/static/FrameworkModule/emoji/dist/js/jquery.mCustomScrollbar.min.js}"></script>
<script th:src="@{/static/FrameworkModule/emoji/dist/js/jquery.emoji.min.js}"></script>
<script type="text/javascript">
var ws = null;
var music = null;
var sendFrom = null;
let rootPath="[[${rootPath}]]";
var singleMsg = './static/users/music/singleMsg.mp3';
var groupMsg = './static/users/music/groupMsg.mp3';
var online = './static/users/music/online.mp3';
layui.use(['jquery','layer','element','admin','form','popup','util'], function () {
let $ = layui.jquery;
let util = layui.util;
let form = layui.form;
let layer = layui.layer;
let admin = layui.admin;
let element = layui.element;
let popup = layui.popup;
var num1 = Math.floor(Math.random()*9999+1);
var nickName = "user"+num1;
if ("WebSocket" in window) {//localhost:8080/springWebSocket自己改
ws = new WebSocket("ws:localhost:8080/springWebSocket/webSocket/"+nickName);
} else if ("MozWebSocket" in window) {
ws = new MozWebSocket("ws:localhost:8080/springWebSocket/webSocket/"+nickName);
} else {
//ws = new SockJS(wsUrl + nickName);
layer.msg('Not support websocket', {icon: 2, time: 2000});
}
//新建连接
ws.onopen = function (event) {
var num = Math.floor(Math.random()*9+1);
var img = './static/chat/dist/media/img/avatar' + num + '.jpg';
$('.my-header-img').attr('src',img);
var html = '<li title="群聊" οnclick="sendTo(this)" class="list-group-item" data-navigation-target="online-msg">';
html += '<div><figure class="avatar"><img src="./static/chat/dist/media/img/chat.png" class="rounded-circle" alt="image"></figure></div>';
html += '<div class="users-list-body"><div><h5 >群聊</h5><p title="群聊">空闲...</p></div></div></li>';
document.getElementById('online_list').innerHTML = html;
};
//监听消息
ws.onmessage = function (event) {
var data = JSON.parse(event.data);
if (data.type == 1 || data.type == 2) { //图片消息
doReceiveMsg(data);
//layer.msg('正常消息', {icon: 1, time: 1000});
} else if (data.type == 0 && data.from == data.to && data.to.length > 0) { //自己获取在线人员
onlineUser(data.online);
//layer.msg('自己获取在线人员', {icon: 1, time: 10000});
} else if (data.type == 0 && data.from != data.to && data.to.length == 0) { //通知所有人xx上线了
addOnlineUser(data.from);
//layer.msg('通知所有人xx上线了', {icon: 1, time: 10000});
} else if (data.type == -1) { //错误消息
layer.msg('错误消息', {icon: 1, time: 1000});
} else if (data.type == -2) { //下线消息
delOnlineUser(data.from);
//layer.msg('下线消息', {icon: 1, time: 1000});
}
};
//发送失败
ws.onerror = function () {
layer.msg('发送失败', {icon: 2, time: 10000});
};
//断开连接
ws.onclose = function (e) {
var data = '断开连接: [错误码:'+e.code+'; 断开原因:'+e.reason+'; 正常关闭:'+e.wasClean+']';
//console.log(data);
layer.msg(data, {icon: 2, time: 1000});
};
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function(){
close();
}
//关闭浏览器
window.close = function () {
ws.close();
};
//聊天框按钮
window.chatOperation = function (obj) {
var title = $(obj).attr("title");
if ('发送'==title) {
doSendText();
var mmmm = $("#messages .messages .message-item .message-content");
matchEmoji(mmmm);
}else if ('文件'==title) {
var myfile = $("#upload-file");
myfile[0].addEventListener('change',function (e) {
var fileList = document.getElementById("upload-file").files;
//console.log(fileList);
if ('image/jpeg'!=fileList[0].type) {
layer.msg('紧支持发送图片', {icon: 2, time: 1000});
}else {
doSendImages();
}
},{once:true});
}else if ('表情'==title) {
loadEmoji();
}
}
<!-- 在线户名 -->
window.onlineUser = function (data){
for (var i = 0; i < data.length; i++) {
var num = Math.floor(Math.random()*9+1);
var img = './static/chat/dist/media/img/avatar' + num + '.jpg';
var name = (data[i]==nickName) ? '记忆助手(我)' : data[i];
img = (data[i]==nickName) ? ($('.my-header-img').attr('src')) : img;
var html = '<li title="' + name + '" οnclick="sendTo(this)" class="list-group-item" data-navigation-target="online-msg">';
html += '<div><figure class="avatar"><img src="'+img+'" class="rounded-circle" alt="image"></figure></div>';
html += '<div class="users-list-body"><div><h5 >'+name+'</h5><p title="' + data[i] + '">空闲...</p></div></div></li>';
$('#online_list').append(html);
var html = '<div class="messages" title="' + name + '" ></div>';
$('#messages').append(html);
}
}
<!-- 增加在线户名 -->
window.addOnlineUser = function (name){
var num = Math.floor(Math.random()*9+1);
var img = './static/chat/dist/media/img/avatar' + num + '.jpg';
var html = '<li title="' + name + '" οnclick="sendTo(this)" class="list-group-item" data-navigation-target="online-msg">';
html += '<div><figure class="avatar"><img src="'+img+'" class="rounded-circle" alt="image"></figure></div>';
html += '<div class="users-list-body"><div><h5 >'+name+'</h5><p title="' + name + '">空闲...</p></div></div></li>';
$('#online_list').append(html);
var html = '<div class="messages" title="' + name + '" ></div>';
$('#messages').append(html);
}
<!-- 移除下线户名 -->
window.delOnlineUser = function (name){
var li = $('li[title="' + name + '"]');
var div = $('.messages[title="' + name + '"]');
li.addClass('logout');
$('.logout .users-list-body div p').html('用户已离开');
setTimeout(() => {
li.remove();
div.remove();
var src = $('li[title="群聊"] .avatar img').attr('src');
$('#chat-header').find('img').attr("src",src);
$('#chat-header').attr("title","群聊");
$('#chat-header').find('h5').text("群聊");
$('#messages .messages[title="群聊"]').addClass('active');
}, 60*1000);
}
<!-- 选择发送人 -->
window.sendTo = function (obj){
var title = $(obj).attr("title");
var src = $(obj).find('img').attr("src");
$('#chat-header').attr("title",title);
$('#chat-header').find('img').attr("src",src);
$('#chat-header').find('h5').text(title);
$('#messages .messages').removeClass('active');
$('#messages .messages[title="'+title+'"]').addClass('active');
$(obj).removeClass('new-msg');
}
<!-- 发送文字消息 -->
window.doSendText = function () {
var sentTime = new Date().format('yyyy-MM-dd hh:mm:ss');
var title = $('#chat-header').attr("title");
var msg = $('#send-Chat-Msg').val();
var img = $('.my-header-img').attr('src');
var html = '<div class="message-item outgoing-message"><div class="message-avatar">';
html += '<figure class="avatar"><img src="'+img+'" class="rounded-circle" alt="image"></figure>';
html += '<div><h5>'+ nickName +'</h5><div class="time">'+sentTime+'</div></div>';
html += '</div><div class="message-content">'+msg+'</div></div>';
if ("群聊" == title && msg.length > 0) {//群聊
$('.messages[title="'+title+'"] ').append(html);
var data = {"from":nickName,"to":"群聊","text":msg,"type":"1"};
var url = rootPath+"/sendToAll";
ajaxGetData(url, data);
} else if (msg.length > 0){
$('.messages[title="'+title+'"] ').append(html);
var data = {"from":nickName,"to":title,"text":msg,"type":"1"};
var url = rootPath+"/sendToOne";
ajaxGetData(url, data);
}
$('#send-Chat-Msg').val("");
}
<!-- 发送图片消息 -->
window.doSendImages = function() {
var fileList = document.getElementById("upload-file").files;
var sentTime = new Date().format('yyyy-MM-dd hh:mm:ss');
var title = $('#chat-header').attr("title");
var img = $('.my-header-img').attr('src');
if(fileList.length > 0){
var fileReader = new FileReader();
fileReader.readAsDataURL(fileList[0]);
fileReader.onload = function (e) {
var msg = e.target.result;
var sendImg = '<img class="chat-img" src="' + msg + '"';
var html = '<div class="message-item outgoing-message"><div class="message-avatar">';
html += '<figure class="avatar"><img src="'+img+'" class="rounded-circle" alt="image"></figure>';
html += '<div><h5>'+ nickName +'</h5><div class="time">'+sentTime+'</div></div>';
html += '</div><div class="message-content">'+sendImg+'</div></div>';
if ("群聊" == title) {//群聊
var data = {"from":nickName,"to":"群聊","text":msg,"type":"2"};
var url = rootPath+"/sendToAll";
ajaxGetData(url, data);
$('.messages[title="'+title+'"] ').append(html);
} else {
var data = {"from":nickName,"to":title,"text":msg,"type":"2"};
var url = rootPath+"/sendToOne";
ajaxGetData(url, data);
$('.messages[title="'+title+'"] ').append(html);
}
}
}
}
<!-- 接收文字/图片消息 -->
window.doReceiveMsg = function (data){
var from = data.from;
var to = data.to;
var text = data.text;
var type = data.type;
var title = $('#chat-header').attr("title");
var receiveTime = new Date().format('yyyy-MM-dd hh:mm:ss');;
var img = $('li[title="' + from + '"]').find('img').attr('src');
var receiveImg = '<img class="chat-img" src="' + text + '"';
text = type==2 ? receiveImg : text;// 图片?/文字?
var html = '<div class="message-item"><div class="message-avatar">';
html += '<figure class="avatar"><img src="'+img+'" class="rounded-circle" alt="image"></figure>';
html += '<div><h5>'+from+'</h5><div class="time">'+receiveTime+'</div></div>';
html += '</div><div class="message-content">'+text+'</div></div>';
music = new Audio();
if (nickName != from && to !="群聊") {
music.src = singleMsg;
$('p[title="' + from + '"]').html(text);
$('li[title="' + from + '"]').addClass('new-msg');
$('.messages[title="' + from + '"] ').append(html);
}else if (nickName != from && to =="群聊") {
music.src = groupMsg;
$('p[title="群聊"]').html(text);
$('li[title="群聊"]').addClass('new-msg');
$('.messages[title="群聊"]').append(html);
}
var mmmm = $("#messages .messages .message-item .message-content");
matchEmoji(mmmm);
var playPromise = music.play();
if (playPromise) {
playPromise.then(() => {
// 音频的播放需要耗时
setTimeout(() => {
// 后续操作
}, music.duration * 1000); // music.duration 为音频的时长单位为秒
}).catch((e) => {
// 音频加载失败
});
}
}
//菜单.unbind('click')
$(document).on("click", '.left-menu ', function () {
$(".left-menu").removeClass("active");
var active = $(this).addClass("active");;
var title = $(this).attr("title");
});
})
</script>
</body>
</html>
js、css懒得删,全部搞进来了
<script th:src="@{/static/FrameworkModule/jquery.min.js}"></script>
<script th:src="@{/static/FrameworkModule/layui2_8/layui.js}"></script>
<script th:src="@{/static/FrameworkModule/pear/pear.js}"></script>
<script th:src="@{/static/users/js/myutil.js}"></script>
<script th:src="@{/static/FrameworkModule/emoji/dist/js/highlight.pack.js}"></script>
<script th:src="@{/static/FrameworkModule/emoji/dist/js/jquery.mousewheel-3.0.6.min.js}"></script>
<script th:src="@{/static/FrameworkModule/emoji/dist/js/jquery.mCustomScrollbar.min.js}"></script>
<script th:src="@{/static/FrameworkModule/emoji/dist/js/jquery.emoji.min.js}"></script>
<link rel="stylesheet" th:href="@{/static/FrameworkModule/pear/css/pear.css}">
<link rel="stylesheet" th:href="@{/static/admin/css/load.css}"/>
<link rel="stylesheet" th:href="@{/static/admin/css/admin.css}"/>
<link rel="stylesheet" th:href="@{/static/users/css/index.css}"/>
<link rel="stylesheet" th:href="@{/static/users/css/sphere.css}">
<link rel="stylesheet" th:href="@{/static/users/css/chat.css}">
<link rel="stylesheet" th:href="@{/static/FrameworkModule/emoji/dist/css/jquery.mCustomScrollbar.min.css}">
<link rel="stylesheet" th:href="@{/static/FrameworkModule/emoji/dist/css/jquery.emoji.css}">
效果展示: