期望是,在用户登录后台后。新的任务到来时能够及时通知到并且去处理。
效果图
前端
html
<template>
<div></div>
</template>
<script>
import { updateRead } from "@/api/system/approval-notification";
export default {
data() {
return {};
},
mounted() {},
methods: {
// 初始化方法
init(userId) {
// 1、websocket接口的url,使用传入的id参数
let ws = `http://localhost:8080/ws/platformAsync/${userId}`;
// 实例化socket
this.socket = new WebSocket(ws);
// 监听socket连接
this.socket.onopen = this.socketopen;
// 监听socket错误信息
this.socket.onerror = this.error;
// 监听socket消息
this.socket.onmessage = this.getMessage;
// 监听socket断开连接的消息
this.socket.onclose = this.close; // 修正为 onclose
},
// 连接成功方法
socketopen() {
console.log("socket连接成功");
},
// 连接错误
error() {
console.log("连接错误");
},
// 接受信息接口
getMessage(message) {
// 当接受到信息之后,就可以做后续的处理了
let data = JSON.parse(message.data);
const h = this.$createElement;
let notificationInstance = this.$notify.info({
title: data.title,
message: h("div", [
h("div", data.message),
h(
"el-button", // 使用 Element UI 的按钮组件
{
props: {
type: "text", // 设置按钮类型为文字按钮
siez: "mini",
},
on: {
click: () => {
this.handleAction(data.path);
notificationInstance.close(); // 关闭通知
},
},
},
"前往处理"
),
h(
"el-button",
{
props: {
type: "text",
siez: "mini",
},
on: {
click: () => {
this.read(data);
notificationInstance.close();
},
},
},
"已读"
),
]),
duration: 10 * 1000,
position: "bottom-right",
});
},
// 关闭处理
close() {
console.log("连接关闭");
},
handleAction(path) {
this.$router.push(path);
},
read(data) {
updateRead(data.id);
},
},
};
</script>
后端
java
@Slf4j
@Component
@ServerEndpoint(value = "/ws/platformAsync/{userId}")
public class PlatformAsyncWebSocket {
// 用来存储每一个客户端对象对应的WsController对象
private static Map<String, PlatformAsyncWebSocket> onlineUsers = new ConcurrentHashMap<>();
// 声明Session对象,通过该对象可以给指定的用户发送请求
private Session session;
/**
* 连接建立时被调用
*/
@OnOpen
public void onOpen(Session session, EndpointConfig config) {
log.info("连接成功");
// 将局部的session对象赋值给成员session对象
this.session = session;
// 这里是因为前端在传数据的时候,会将userId传过来
// 所以使用将userId和websocket对象存储起来,方便下次服务端推送信息的时候使用
Map<String, List<String>> requestParameterMap = this.session.getRequestParameterMap();
List<String> userIds = requestParameterMap.get("userId");
String userId = userIds.get(0);
onlineUsers.put(userId, this);
}
/**
* 接收到客户端消息时被调用
*/
@OnMessage
public void onMessage(String message, Session session) {
// 处理接收到的消息
}
/**
* 连接被关闭时调用
*/
@OnClose
public void onClose(Session session) {
// 关闭时则将map中的用户移除
Map<String, List<String>> requestParameterMap = session.getRequestParameterMap();
List<String> userIds = requestParameterMap.get("userId");
String userId = userIds.get(0);
onlineUsers.remove(userId);
}
/**
* 推送消息,将消息推送给某个指定的用户
*/
public void sendMsg(String userId, String message) {
try {
PlatformAsyncWebSocket wsController = onlineUsers.get(userId);
if (wsController != null && wsController.session.isOpen()) {
wsController.session.getBasicRemote().sendText(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
创建一个定时器做测试
java
@Slf4j
@Component
@AllArgsConstructor(onConstructor = @__(@Autowired))
public class ScheduledTask {
private final PlatformAsyncWebSocket platformAsyncWebSocket;
private final ApprovalNotificationService approvalNotificationService;
@Scheduled(fixedRate = 60 * 1000) // 每x秒执行一次
public void sendQualityCheckNotifications() {
List<ApprovalNotificationDto> approvalNotificationDtoList = approvalNotificationService.getApprovalNotificationDtoList();
for (ApprovalNotificationDto approvalNotificationDto : approvalNotificationDtoList) {
PlatformInfo platformInfo = new PlatformInfo();
String userId = approvalNotificationDto.getRecipientId();
platformInfo.setId(String.valueOf(approvalNotificationDto.getId()));
platformInfo.setTitle(approvalNotificationDto.getTitle());
platformInfo.setMessage(approvalNotificationDto.getContent()); // 自定义消息内容
platformAsyncWebSocket.sendMsg(userId, JSON.toJSONString(platformInfo));
}
}
}