上一篇写了《若依(ruoyi)使用websocket推送数据到前端 - 简书 (jianshu.com)
》,猿友指出缺少身份识别,无法精准命中给谁推送,本文来继续解决这个问题。
既然想知道消息推送给谁,那肯定需要知道发送者、接受者、消息内容,三个最基本的东西,我简单定义为sendUserId、receiveUserId、msg。假设有三个人(路飞、索隆、艾斯)互相发消息,为了方便,我将发送者放到url中,实际项目上使用需要根据各项目情况从token、request等解析获取,这里只聊思路。
场景
三个人可以互相发消息,也可以给自己发消息,界面如下,接收到的消息会在“消息接收面板”展示出来。
-
当“路飞”对“索隆”说:跟你说过多少遍不要拿我的帽子!,这时候可以看到,索隆收到了消息,艾斯没有。
-
当“索隆”对“艾斯”说:是你拿了那个家伙的帽子?此时路飞视角是没有收到任何消息的
具体实现
1、添加websocket依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2、添加配置
@Configuration
@EnableWebSocket
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
3、消息体
非常简单,包括消息内容,发送者和接受者
@Data
public class MsgEntity implements Serializable {
String msg;
String userId;
String receiveUserId;
}
4、定向发送
@Component
@ServerEndpoint(value = "/mos/websocket/{userId}")
@Slf4j
public class WebSocket {
private static Map<String, Session> livingSession = new ConcurrentHashMap<>();
/**
* 客户端与服务端连接成功
*
* @param session
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
livingSession.put(userId, session);
}
/**
* 客户端与服务端连接关闭
*
* @param session
*/
@OnClose
public void onClose(Session session, @PathParam("userId") String userId) {
livingSession.remove(userId);
}
/**
* 客户端与服务端连接异常
*
* @param error
* @param session
*/
@OnError
public void onError(Throwable error, Session session) {
error.printStackTrace();
}
/**
* 客户端向服务端发送消息
* 主要消息发送在这里,找到接受者的session,并推送消息内容
* @param message
* @throws IOException
*/
@OnMessage
public void onMsg(String msg) throws IOException {
MsgEntity msgEntity = JSONUtil.toBean(msg,MsgEntity.class);
Session session = livingSession.get(msgEntity.getReceiveUserId());
session.getAsyncRemote().sendText(msgEntity.getMsg());
}
}
5、前端
前端为了界面稍微好看一些,使用了layui,无论什么都是相通的,vue、jquery都可以。
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>socket消息推送</title>
<div th:replace="~{common/links::header}"></div>
<div th:replace="~{common/script::js_footer}"></div>
</head>
<body>
<div class="layui-bg-gray" style="padding: 16px;">
<div class="layui-row layui-col-space15">
<div class="layui-col-md6">
<div class="layui-card">
<div class="layui-card-header">消息发送面板(发送人:<span id="sender"></span>)</div>
<div class="layui-card-body">
<form class="layui-form layui-form-pane" id="searchForm">
<div class="layui-form-item" pane>
<label class="layui-form-label">发送给</label>
<div class="layui-input-block">
<input type="radio" name="receiveUserId" value="路飞" title="路飞" checked>
<input type="radio" name="receiveUserId" value="索隆" title="索隆">
<input type="radio" name="receiveUserId" value="艾斯" title="艾斯">
</div>
</div>
<div class="layui-form-item layui-form-text">
<div class="layui-input-block">
<textarea placeholder="请输入需要发送的消息" class="layui-textarea" name="msg" ></textarea>
</div>
</div>
<div class="layui-form-item">
<button class="layui-btn" lay-submit="" lay-filter="add" >发送消息</button>
</div>
</form>
</div>
</div>
</div>
<div class="layui-col-md6">
<div class="layui-card">
<div class="layui-card-header">消息接收面板</div>
<div class="layui-card-body">
<span id="content"></span>
</div>
</div>
</div>
</div>
</div>
</body>
<script th:inline="javascript">
layui.use('form', function () {
var $ = layui.jquery,form = layui.form;
const urlParams = new URLSearchParams(window.location.search);
const sendUserId = urlParams.get('sendUserId');
const receiveUserId = urlParams.get('receiveUserId');
$("#sender").html(sendUserId)
form.on('submit(add)', function (data) {
let param = {userId:sendUserId}
Object.assign(param,data.field);
Common.ajaxFormSubmit('/websocket/send', param, function (data) {
layer.msg('消息已发送')
});
return false;
});
let webSocket = null;
if ('WebSocket' in window){
webSocket = new WebSocket("ws://localhost:8888/mos/websocket/"+sendUserId);
}else{
layer.msg('您的浏览器不支持websocket')
}
webSocket.onopen = function () {
layer.msg('连接成功')
}
webSocket.onerror = function (error) {
layer.msg('连接失败',error)
}
webSocket.onclose = function () {
layer.msg('连接关闭')
}
webSocket.onmessage = function (event) {
$("#content").html(event.data)
}
});
</script>
</html>
其他说明
- 没有进行鉴权,需要视具体项目情况而定
- 默认三个会话都已创建,否则会报“ because "session" is null”的错,只是简单演示使用,实际项目可能还需要考虑接收方离线时怎么办等等。
- 代码已上传gitee,需要的童鞋可以自行获取。
MosSimple: 功能示例 (gitee.com)