websocket业务接入示例

1.项目架构没目录

2.maven

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.admin</groupId>
        <artifactId>admin-project</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>admin-websocket</artifactId>
    <name>【${project.artifactId}】socket模块</name>


    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <dependencies>
        <!-- 通用工具-->
        <dependency>
            <groupId>com.admin</groupId>
            <artifactId>admin-common</artifactId>
        </dependency>
        <dependency>
            <groupId>com.admin</groupId>
            <artifactId>admin-framework</artifactId>
        </dependency>
        <dependency>
            <groupId>com.admin</groupId>
            <artifactId>admin-system</artifactId>
        </dependency>


        <!-- SpringBoot WebSocket -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <!-- Web工具包 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 工具类 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.16</version>
        </dependency>

    </dependencies>

</project>

3.WebSocketConfig

复制代码
package com.admin.websocket.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * WebSocket配置,开启WebSocket支持
 * @author wangwei
 * @date 2026-04-16
 **/
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}
  1. Task

    package com.admin.websocket.entity;

    import com.admin.common.annotation.Excel;
    import com.alibaba.excel.annotation.ExcelIgnore;
    import com.fasterxml.jackson.annotation.JsonFormat;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    import java.util.Date;

    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public class Task {

    //内容。。。。。
    }

  2. UserRoleEnum

    package com.admin.websocket.enums;

    /**

    • 用户角色枚举

    • @author wangwei

    • @date 2026-04-16
      /
      public enum UserRoleEnum {
      /
      SUPER_ADMIN, // 超级管理员:看所有消息
      DEPT_ADMIN, // 部门管理员:看本部门所有消息
      USER; // 普通用户:只看自己消息
      /

      SUPER_ADMIN("超级管理员"), // 超级管理员
      DEPT_ADMIN("部门管理员"), // 部门管理员
      USER("普通用户"); // 普通用户

      private final String roleName;

      UserRoleEnum(String roleName) {
      this.roleName = roleName;
      }

      // 【核心】根据中文 匹配 枚举
      public static UserRoleEnum getByRoleName(String roleName) {
      for (UserRoleEnum e : values()) {
      if (e.roleName.equals(roleName)) {
      return e;
      }
      }
      // 找不到默认普通用户
      return USER;
      }
      }

  3. MessagePushService

    package com.admin.websocket.service;

    import org.springframework.stereotype.Service;

    import javax.annotation.Resource;
    import java.util.HashMap;
    import java.util.Map;

    /***

    • 消息推送服务层,用于向客户端推送消息,如:实时通知、实时聊天等
    • @author wangwei
    • @date 2026-04-16
      **/

    @Service
    public class MessagePushService {
    @Resource
    private WebSocketServer webSocketServer;

    复制代码
     /**
      * 构造统一消息格式
      */
     private Map<String, Object> buildMessage(String type, String content, String fromUser) {
         Map<String, Object> msg = new HashMap<>();
         msg.put("type", type);
         msg.put("content", content);
         msg.put("from", fromUser);
         msg.put("time", System.currentTimeMillis());
         return msg;
     }
    
     // ===================== 对外推送接口 =====================
    
     /**
      * 推送给所有超级管理员
      */
     public void pushToSuperAdmin(String content, String fromUser) {
         Map<String, Object> message = buildMessage("SUPER_ADMIN_MSG", content, fromUser);
         webSocketServer.sendToSuperAdmin(message);
     }
    
     /**
      * 推送给指定部门(部门管理员+部门用户)
      */
     public void pushToDept(String deptId, String content, String fromUser) {
         Map<String, Object> message = buildMessage("DEPT_MSG", content, fromUser);
         webSocketServer.sendToDept(deptId, message);
     }
    
     /**
      * 推送给单个用户
      */
     public void pushToUser(String userId, String content, String fromUser) {
         Map<String, Object> message = buildMessage("USER_MSG", content, fromUser);
         webSocketServer.sendToUser(userId, message);
     }
    
     /**
      * 推送给所有人(超管专用)
      */
     public void pushToAll(String content, String fromUser) {
         Map<String, Object> message = buildMessage("BROADCAST", content, fromUser);
         webSocketServer.sendToAll(message);
     }

    }

  4. TaskCountProvider

    package com.admin.websocket.service;

    import com.admin.common.entity.DeptOnlineVO;

    import java.util.List;
    import java.util.Map;
    import java.util.Set;

    /**

    • 任务数提供者接口

    • @author wangwei

    • @date 2026-04-16
      **/
      public interface TaskCountProvider {
      // 定义你需要的方法:根据用户ID查任务数
      int getUnFinishTaskCount(String userId);

      List<DeptOnlineVO> onDeptLogin(Map<String, Set<String>> deptUsers);
      }

  5. WebSocketServer

    package com.admin.websocket.service;

    import cn.hutool.json.JSONUtil;
    import com.admin.common.core.domain.entity.SysUser;
    import com.admin.common.entity.DeptOnlineVO;
    import com.admin.common.utils.DateUtils;
    import com.admin.common.utils.SecurityUtils;
    import com.admin.framework.socket.UserLoginEvent;
    import com.admin.websocket.entity.Task;
    import com.admin.websocket.enums.UserRoleEnum;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.context.event.EventListener;
    import org.springframework.stereotype.Component;

    import javax.websocket.OnClose;
    import javax.websocket.OnError;
    import javax.websocket.OnOpen;
    import javax.websocket.Session;
    import javax.websocket.server.PathParam;
    import javax.websocket.server.ServerEndpoint;
    import java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    import java.util.concurrent.ConcurrentHashMap;

    /**

    • WebSocket 核心服务

    • 连接地址:ws://localhost:8080/ws/{用户ID}/{角色}/{部门ID}

    • @author wangwei

    • @date 2026-04-16
      **/
      @Slf4j
      @Component
      @ServerEndpoint("/ws/{userId}/{role}/{deptId}")
      public class WebSocketServer {

      // 在线用户会话
      private static final Map<String, Session> SESSION_POOL = new ConcurrentHashMap<>();
      private static final Map<String, UserRoleEnum> USER_ROLE_MAP = new ConcurrentHashMap<>();
      private static final Map<String, String> USER_DEPT_MAP = new ConcurrentHashMap<>();

      // ===================== 新增:静态回调接口 =====================
      public static TaskCountProvider taskCountProvider;

      // ===================== 【新增】在线状态监控 =====================
      private static final Map<String, String> ONLINE_USER_DEPT = new ConcurrentHashMap<>(); // userId -> deptId
      private static final Map<String, Set<String>> DEPT_ONLINE_USERS = new ConcurrentHashMap<>();

      /**

      • 连接建立
        */
        @OnOpen
        public void onOpen(Session session,
        @PathParam("userId") String userId,
        @PathParam("role") String roleStr,
        @PathParam("deptId") String deptId) {
        SimpleDateFormat sdfTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        // 将字符串转换为枚举类型
        // UserRoleEnum role = UserRoleEnum.valueOf(roleStr);
        UserRoleEnum role = UserRoleEnum.getByRoleName(roleStr);

        SESSION_POOL.put(userId, session);
        USER_ROLE_MAP.put(userId, role);
        USER_DEPT_MAP.put(userId, deptId);
        log.info("用户[{}] 在[{}]已连接WebSocket,角色[{}],在线数:{}", userId, sdfTime.format(DateUtils.getNowDate()), role, SESSION_POOL.size());

        // ===================== 加这一行:用户一上线,自动推送未完成任务 =====================

        //todo 接收 buss 业务子模块传过来的参数
        int count = WebSocketServer.taskCountProvider.getUnFinishTaskCount(userId);

        // ===================== 【新增】维护在线状态 =====================
        ONLINE_USER_DEPT.put(userId, deptId);
        DEPT_ONLINE_USERS.computeIfAbsent(deptId, k -> ConcurrentHashMap.newKeySet()).add(userId);

        // 维护在线用户-部门关系
        ONLINE_USER_DEPT.put(userId, deptId);
        DEPT_ONLINE_USERS.computeIfAbsent(deptId, k -> ConcurrentHashMap.newKeySet()).add(userId);
        List<DeptOnlineVO> onDeptUserNumList = WebSocketServer.taskCountProvider.onDeptLogin(DEPT_ONLINE_USERS);

        // 关键:用户上线后 → 立即推送最新部门在线人数给前端
        //pushDeptOnlineStatus();
        log.info("用户[{}] 部门[{}] 已连接,在线数:{}", userId, deptId, SESSION_POOL.size());

        // 合并JSON
        Map<String, Object> result = new HashMap<>();
        result.put("num", count);
        result.put("deptList", onDeptUserNumList);
        String jsonMsg = JSONUtil.toJsonStr(result);
        log.info("建立连接,给所有用户发送消息");
        // 发送
        this.sendToAll(jsonMsg);
        }

      /**

      • 关闭连接
        */
        @OnClose
        public void onClose(@PathParam("userId") String userId) {
        SESSION_POOL.remove(userId);
        USER_ROLE_MAP.remove(userId);
        USER_DEPT_MAP.remove(userId);
        log.info("用户[{}]已断开", userId);

        // ===================== 【新增】下线移除 =====================
        String deptId = ONLINE_USER_DEPT.remove(userId);
        if (deptId != null) {
        Set<String> users = DEPT_ONLINE_USERS.get(deptId);
        if (users != null) {
        users.remove(userId);
        if (users.isEmpty()) {
        DEPT_ONLINE_USERS.remove(deptId);
        }
        }
        }
        log.info("用户[{}] 已断开", userId);
        }

      /**

      • ===================== 核心推送方法 =====================
        */

      /**

        1. 推送给 超级管理员(所有超管都能收到)
          */
          public void sendToSuperAdmin(Object message) {
          SysUser user = SecurityUtils.getLoginUser().getUser();

        String msg = JSONUtil.toJsonStr(message);
        USER_ROLE_MAP.forEach((userId, role) -> {
        if (user.getUserName().equals("admin") || user.getUserName().contains("admin")) {
        sendMessage(SESSION_POOL.get(user.getUserId()), msg);//TODO 所有超管发送有问题
        }
        });
        }

      /**

        1. 推送给 指定部门的所有用户(部门管理员+部门普通用户)
          */
          public void sendToDept(String deptId, Object message) {
          String msg = JSONUtil.toJsonStr(message);
          USER_DEPT_MAP.forEach((userId, userDeptId) -> {
          if (deptId.equals(userDeptId)) {
          sendMessage(SESSION_POOL.get(userId), msg);
          }
          });
          }

      /**

        1. 推送给 单个普通用户
          */
          public void sendToUser(String userId, Object message) {
          String msg = JSONUtil.toJsonStr(message);
          Session session = SESSION_POOL.get(userId);
          if (session != null) {
          sendMessage(session, msg);
          }
          }

      /**

        1. 推送给 所有人(超管专用)
          */
          public void sendToAll(Object message) {
          String msg = JSONUtil.toJsonStr(message);
          SESSION_POOL.values().forEach(session -> sendMessage(session, msg));
          }

      /**

      • 发送消息工具方法
        */
        private void sendMessage(Session session, String message) {
        try {
        if (session != null && session.isOpen()) {
        session.getBasicRemote().sendText(message);
        }
        } catch (IOException e) {
        log.error("发送消息失败", e);
        }
        }

      /**

      • 异常
        */
        @OnError
        public void onError(Throwable error) {
        log.error("WebSocket异常", error);
        }

      // ===================== 【核心】按权限推送任务 =====================

      /****

      • 数量

      • 被发送人的信息

      • @param taskJson
        */
        public void pushTask(String taskJson, Task task) {
        // 遍历所有在线用户,根据角色推送
        SESSION_POOL.forEach((userId, session) -> {
        Map<String, String> pathParameters = session.getPathParameters();
        String role = pathParameters.get("role") == null ? "" : pathParameters.get("role");
        String deptId = pathParameters.get("deptId") == null ? "" : pathParameters.get("deptId");

        复制代码
         if (session == null || !session.isOpen()) return;
        
         try {
             // 1. 超级管理员(用户名包含admin)= 全部推送
             if (role.equals("超级管理员")) {
                 //消息体推送
                 session.getBasicRemote().sendText(taskJson);
                 sendToSuperAdmin("todo 超级管理员接收到信息✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ");
                 log.info("推送任务给超级管理员,userId: {}", userId);
             }
             // 2. 部门管理员 = 只推本部门
             else if (role.equals("部门管理员")) {
                 String userDeptId = USER_DEPT_MAP.get(userId);
                 int count = WebSocketServer.taskCountProvider.getUnFinishTaskCount(userId);
                 session.getBasicRemote().sendText("{\num\":" + count + "}\n");
                 log.info("推送任务给部门管理员,userId: {}, deptId: {}", userId, userDeptId);
             }
             // 3. 普通用户 = 只推自己的任务
             else if (role.equals("普通用户")) {
        
                 int count = WebSocketServer.taskCountProvider.getUnFinishTaskCount(userId);
                 session.getBasicRemote().sendText("{\num\":" + count + "}\n");
                 log.info("推送任务给普通用户,userId: {}", userId);
             }
        
         } catch (IOException e) {
             log.error("推送任务失败,用户ID:{}", userId, e);
         }

        });
        }

      // ===================== 监听登录事件,自动推送 过期=====================
      @EventListener
      public void onUserLogin(UserLoginEvent event) {
      String userId = event.getUserId();
      log.info("【用户登录】userId:{}", userId);

      复制代码
       // 推送任务(你原有功能)
       pushTaskCountAfterLogin(userId);
      
       // ===================== 【新增】登录后实时推送给前端:部门在线状态 =====================
       pushDeptOnlineStatus(userId);

      }

      // ===================== 【新增】推送部门在线状态给前端 =====================
      public void pushDeptOnlineStatus(String userId) {
      /* Map<String, Integer> deptOnline = getDeptOnlineStatus();11111
      String msg = JSONUtil.toJsonStr(MapUtil.of("deptOnline", deptOnline));
      sendToAll(msg); // 推给所有人*/
      int count = WebSocketServer.taskCountProvider.getUnFinishTaskCount(userId);
      List<DeptOnlineVO> onDeptUserNumList = WebSocketServer.taskCountProvider.onDeptLogin(DEPT_ONLINE_USERS);
      Map<String, Object> result = new HashMap<>();
      result.put("num", count);
      result.put("deptList", onDeptUserNumList);
      String jsonMsg = JSONUtil.toJsonStr(result);
      log.info("【实时推送】部门在线状态,以及待办任务数量信息:{}", jsonMsg);
      // 发送
      this.sendToAll(jsonMsg);
      }

      /**

      • 获取所有部门在线情况
      • key: deptId
      • value: 在线人数
        */
        public static Map<String, Integer> getDeptOnlineStatus() {
        Map<String, Integer> result = new HashMap<>();
        DEPT_ONLINE_USERS.forEach((deptId, userSet) -> {
        result.put(deptId, userSet.size());
        });
        return result;
        }

      /**

      • 用户登录成功后,主动调用这个方法推送任务数量

      • @param userId 用户ID
        */
        public void pushTaskCountAfterLogin(String userId) {
        try {
        // 1. 获取用户会话
        Session session = SESSION_POOL.get(userId);
        if (session == null || !session.isOpen()) {
        log.info("用户[{}] 未连接WebSocket,不推送", userId);
        return;
        }

        复制代码
         // 2. 获取任务数量
         if (taskCountProvider == null) {
             log.error("taskCountProvider 未注册");
             return;
         }
        
         int count = taskCountProvider.getUnFinishTaskCount(userId);
        
         // 3. 推送给当前登录用户
         String msg = "{\"num\": " + count + "}";
         session.getBasicRemote().sendText(msg);
        
         log.info("【登录推送】用户[{}] 未完成任务数:{}", userId, count);

        } catch (Exception e) {
        log.error("【登录推送】失败 userId:{}", userId, e);
        }
        }
        }

  6. 测试html

    <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>WebSocket 调试版(控制台打印全信息)</title> <style> .task-box { border: 1px solid #e4e7ed; border-radius: 6px; padding: 12px 15px; margin: 10px 0; background: #ffffff; } .task-finish { background: #f7f7f7; color: #999; } #socketMsg { background: #f8f9fa; padding: 10px; border: 1px solid #ddd; border-radius: 6px; height: 300px; overflow-y: auto; white-space: pre-wrap; font-size: 12px; margin-bottom: 20px; } </style> </head> <body>

    📋 待办任务(控制台可查看所有Socket信息)

    复制代码
     <h3>📡 WebSocket 实时返回数据</h3>
     <div id="socketMsg"></div>
    
     <div id="taskContainer"></div>
    
     <script>
         // ===================== 【你的用户信息】 =====================
         const userId = "1";
         const userRole = "超级管理员";
         const deptId = "100";
    
         const taskMap = {};
         let ws = null;
    
         // ===================== 页面加载完 → 立即主动连接 WebSocket =====================
         window.onload = function () {
             console.log("页面加载完成,开始主动连接 WebSocket...");
             addMsgToPage("页面加载完成 → 主动连接 WebSocket...");
             connectWebSocket(); // 主动请求
         };
    
         function connectWebSocket() {
             const wsUrl = "ws://192.168.2.30:7070/pdxjzhapi/ws/" + userId + "/" + userRole + "/" + deptId;
    
             console.log("======================================");
             console.log("✅ WebSocket 连接地址:", wsUrl);
             console.log("✅ userId:", userId);
             console.log("✅ role:", userRole);
             console.log("✅ deptId:", deptId);
    
             addMsgToPage("主动连接:" + wsUrl);
             addMsgToPage("参数 → 用户:" + userId + " 角色:" + userRole + " 部门:" + deptId);
    
             // ===================== 主动创建连接 =====================
             ws = new WebSocket(wsUrl);
    
             ws.onopen = function () {
                 console.log("🔌 WebSocket 连接成功!");
                 addMsgToPage("✅ 连接成功!");
             };
    
             ws.onmessage = function (evt) {
                 console.log("📥 收到消息:", evt.data);
                 addMsgToPage("📥 收到返回数据:\n" + evt.data);
    
                 try {
                     const task = JSON.parse(evt.data);
                     taskMap[task.ctId] = task;
                     renderList();
                 } catch (e) {
                     console.error("解析失败", e);
                 }
             };
    
             ws.onclose = function () {
                 console.log("🔌 断开,2秒重连");
                 addMsgToPage("🔌 连接断开,2秒后自动重连...");
                 setTimeout(connectWebSocket, 2000);
             };
    
             ws.onerror = function (err) {
                 console.error("❌ 连接错误");
                 addMsgToPage("❌ 连接失败!");
             };
         }
    
         // ===================== 把消息显示到页面 =====================
         function addMsgToPage(msg) {
             let time = new Date().toLocaleString();
             let dom = document.getElementById("socketMsg");
             dom.innerHTML = `[${time}] ${msg}\n` + dom.innerHTML;
         }
    
         // ===================== 渲染列表 =====================
         function renderList() {
             let html = "";
             Object.values(taskMap).forEach(task => {
                 const isFinish = task.ctFinish === "1";
                 const className = isFinish ? "task-box task-finish" : "task-box";
                 const status = isFinish ? "【已结束】" : "【待处理】";
    
                 html += `
                 <div class="${className}">
                     <div><strong>${status} ${task.ctName}</strong></div>
                     <div>备注:${task.ctMark || '无'}</div>
                     <div>发送人:${task.ctSendName || '系统'}</div>
                 </div>`;
             });
             document.getElementById("taskContainer").innerHTML = html;
         }
     </script>
    </body> </html>

10.DeptOnlineVO

复制代码
package com.admin.common.entity;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class DeptOnlineVO {
    private String deptId;      // 部门ID
    private String deptName;    // 部门名称
    private Integer onlineCount;// 在线人数
    private String state;      // 状态
}

11.业务代码模块 * 接口 + 静态回调 给webSocket项目模块 传参 业务数据的任务信息

WebSocketTaskRegister

复制代码
package com.admin.business.common;


import com.admin.business.domain.TbTask;
import com.admin.business.domain.TbTechnologyOrg;
import com.admin.business.mapper.TbTaskMapper;
import com.admin.business.mapper.TbTechnologyOrgMapper;
import com.admin.common.core.domain.entity.SysUser;
import com.admin.common.exception.CustomException;
import com.admin.common.utils.StringUtils;
import com.admin.system.mapper.SysUserMapper;
import com.admin.websocket.service.TaskCountProvider;
import com.admin.websocket.service.WebSocketServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.*;


/***
 * 接口 + 静态回调     给webSocket项目模块  传参    业务数据的任务信息
 * 不让 websocket 直接依赖 business 的任何类,而是让 business 主动把方法 "注册" 给 websocket。
 * 解决子模块之间依赖循环的问题
 *
 * @author wangwei
 * @date 2026-04-16
 **/



@Component
public class WebSocketTaskRegister {
    // 这里可以正常注入,因为在 business 内部
    @Autowired
    private TbTaskMapper tbTaskMapper;
    @Autowired
    private SysUserMapper userMapper;
    @Autowired
    private TbTechnologyOrgMapper tbTechnologyOrgMapper;

    // 项目启动时,自动把查询方法注册给 websocket
    @PostConstruct
    public void register() {
        WebSocketServer.taskCountProvider = new TaskCountProvider() {

            @Override
            public int getUnFinishTaskCount(String userId) {
                // 直接调用你的 mapper

                SysUser sysUser = userMapper.selectUserById(Long.valueOf(userId));
                if(sysUser==null){
                    throw new CustomException("websocket获取到的用户编号有误,请联系管理员处理!");
                }

                //TODO 代办任务查询    task表的 ctFinish != 88
                String roleStr = "";
                if(StringUtils.isEmpty(sysUser.getRemark()) || sysUser.getRemark().equals("普通用户")){
                    roleStr = "普通用户";
                    TbTask task = new TbTask();
                    task.setCtInceptP(userId);
                    List<TbTask> taskList = tbTaskMapper.selectTbTaskDBList(task);
                    return taskList.size();
                }else if(sysUser.getRemark().equals("部门管理员")){
                    roleStr = "部门管理员";
                    TbTask task = new TbTask();
                    task.setBy5(sysUser.getDeptId().toString());//任务表中的  by5 表示任务接收人的所属单位
                    List<TbTask> taskList = tbTaskMapper.selectTbTaskDBList(task);
                    return taskList.size();

                }else if(sysUser.getUserName().equals("admin") || sysUser.getRemark().equals("超级管理员")){
                    roleStr = "超级管理员";
                    TbTask task = new TbTask();
                    List<TbTask> taskList = tbTaskMapper.selectTbTaskDBList(task);
                    return taskList.size();
                }
                return 0;
            }


            /***
             * 部门用户在线状态,在线人数信息
             * @param deptUsers
             * @return
             */
            public List<com.admin.common.entity.DeptOnlineVO> onDeptLogin(Map<String, Set<String>> deptUsers) {
                List<com.admin.common.entity.DeptOnlineVO> result = new ArrayList<>();

                // 1. 先查询 所有单位/部门/小组(以这个顺序为准)
                TbTechnologyOrg tbTechnologyOrg = new TbTechnologyOrg();
                List<TbTechnologyOrg> orgList = tbTechnologyOrgMapper.selectTbTechnologyOrgList(tbTechnologyOrg);

                // 2. 遍历【标准机构列表】→ 以它顺序为准
                for (TbTechnologyOrg org : orgList) {
                    String deptId = org.getDeptId();       // 部门ID
                    String deptName = org.getCtOrgName();  // 部门名称

                    // 3. 匹配在线状态
                    if (deptUsers.containsKey(deptId)) {
                        // 匹配到 → 在线
                        int count = deptUsers.get(deptId).size();
                        result.add(new com.admin.common.entity.DeptOnlineVO(
                                deptId, deptName, count, "在线"
                        ));
                    } else {
                        // 匹配不到 → 离线、数量0
                        result.add(new com.admin.common.entity.DeptOnlineVO(
                                deptId, deptName, 0, "离线"
                        ));
                    }
                }

                return result;
            }

        };
    }
}

11.业务中主动触发,发送websocket消息

复制代码
        //TODO socket任务推送1111
        //     * 推送单条任务(新增/更新时调用)

        TbTask tbTask = new TbTask();
        List<TbTask> taskList = tbTaskMapper.selectTbTaskDBList(tbTask);
        String taskJson = "{\"num\":" + taskList.size() + "}\n";
        WebSocketServer webSocketServer = ApplicationContextUtils.getBean(WebSocketServer.class);
        webSocketServer.pushTask(taskJson, null);

12.用户登录后 主动触发socket消息

复制代码
   // 发布登录事件(不依赖 websocket) 接处警监控   各个科室在线状态
        eventPublisher.publishEvent(new UserLoginEvent(this, user.getUserId().toString()));

14.效果示例

相关推荐
DianSan_ERP2 小时前
淘宝订单接口集成中如何正确处理消费者敏感信息的安全与合规问题?
大数据·运维·网络·人工智能·安全·servlet
IMPYLH2 小时前
Linux 的 sha256sum 命令
linux·运维·服务器·网络·bash·哈希算法
笨熊呆呆瓜2 小时前
【网络基础科普】交换机 MAC 地址全解析:查询方法、System MAC 与 Bridge MAC 的区别,以及“为什么只差 1”
网络
Full Stack Developme3 小时前
Hutool StrUtil 教程
开发语言·网络·python
数字供应链安全产品选型3 小时前
2026智能体行为安全深度解析:从提示词注入到工具调用劫持,悬镜灵境AIDR的实时防护机制
网络
优化Henry3 小时前
新建LTE站点光功率劣化分析与处理案例
运维·网络·5g·信息与通信
positive_zpc3 小时前
计算机网络——网络层(一)
网络·计算机网络
Lanren的编程日记3 小时前
Flutter鸿蒙应用开发:网络请求优化实战,全方位提升请求稳定性与性能
网络·flutter·harmonyos
WJ.Polar3 小时前
Ansible任务控制
linux·运维·网络·python·ansible
hj2862513 小时前
网络基础知识day03
网络·智能路由器