基于websocket简易封装一个全局消息通知组件

期望是,在用户登录后台后。新的任务到来时能够及时通知到并且去处理。

效果图

前端

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));
        }
    }

}
相关推荐
知识分享小能手7 分钟前
Vue3 学习教程,从入门到精通,Axios 在 Vue 3 中的使用指南(37)
前端·javascript·vue.js·学习·typescript·vue·vue3
伍哥的传说32 分钟前
Mitt 事件发射器完全指南:200字节的轻量级解决方案
vue.js·react.js·vue3·mitt·组件通信·事件管理·事件发射器
一枚小小程序员哈3 小时前
基于Vue + Node能源采购系统的设计与实现/基于express的能源管理系统#node.js
vue.js·node.js·express
杨DaB6 小时前
【SpringBoot】Swagger 接口工具
java·spring boot·后端·restful·swagger
昵称为空C7 小时前
SpringBoot接口限流的常用方案
服务器·spring boot
hrrrrb8 小时前
【Java Web 快速入门】十一、Spring Boot 原理
java·前端·spring boot
一枚小小程序员哈8 小时前
基于Vue的个人博客网站的设计与实现/基于node.js的博客系统的设计与实现#express框架、vscode
vue.js·node.js·express
定栓8 小时前
vue3入门-v-model、ref和reactive讲解
前端·javascript·vue.js
LIUENG9 小时前
Vue3 响应式原理
前端·vue.js
wycode10 小时前
Vue2实践(3)之用component做一个动态表单(二)
前端·javascript·vue.js