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

}
相关推荐
逆回10 小时前
升级 Boot 4 后,我的 mock 全红了
spring boot
学长毕设13 小时前
基于SpringBoot的野生动物公益保护平台设计与实现-附源码
java·spring boot·后端
啾咪orJIUMI13 小时前
Vue 3 + 高德地图封装实战:点位、区域、Loca 流光与 Vue 信息窗体
前端·vue.js
FRing0314 小时前
vue2干货总结8(路由模块封装、router-link、声明式导航、路由重定向、编程式导航)
开发语言·前端·vue.js·vue2
她的男孩14 小时前
三人会签只批了一个就往下走:Forge Admin 把 all / any / ratio 写成 completionCondition
spring boot·低代码·工作流引擎
无懈可击14 小时前
Vue 可视化AI表单设计器 FcDesigner v3.6 版本发布,支持导出 SQL功能!
vue.js·开源·ai编程
徐小夕15 小时前
JitArchives,一款基于JitWord协同AI文档打造的企业级电子档案系统
前端·vue.js·github
vipxieliang15 小时前
ValidX vs 手写验证代码:开发效率对比实测
java·spring boot·后端
vipxieliang16 小时前
虚拟线程与 GraalVM:Spring Boot 3.x 云原生性能跃迁
java·spring boot·后端
头发还在的女程序员17 小时前
基于 Spring Boot + Vue 3 + uni-app 的灵活用工系统:四端架构与业务流程设计
vue.js·spring boot·uni-app·灵活用工·灵工系统