diff --git a/continew-admin-common/pom.xml b/continew-admin-common/pom.xml
index 24e9d5dc..0f66a819 100644
--- a/continew-admin-common/pom.xml
+++ b/continew-admin-common/pom.xml
@@ -135,5 +135,10 @@
top.continew
continew-starter-json-jackson
+
+ org.springframework.boot
+ spring-boot-starter-websocket
+
+
\ No newline at end of file
diff --git a/continew-admin-common/src/main/java/top/continew/admin/common/config/websocket/WebSocketConfig.java b/continew-admin-common/src/main/java/top/continew/admin/common/config/websocket/WebSocketConfig.java
new file mode 100644
index 00000000..089198e5
--- /dev/null
+++ b/continew-admin-common/src/main/java/top/continew/admin/common/config/websocket/WebSocketConfig.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.admin.common.config.websocket;
+
+import jakarta.annotation.Resource;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.socket.config.annotation.EnableWebSocket;
+import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
+import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
+import top.continew.admin.common.handler.MyWebSocketHandler;
+
+/**
+ * WebSocketConfig配置
+ *
+ * @author WeiRan
+ * @since 2024.03.13 16:45
+ */
+@Configuration
+@EnableWebSocket
+public class WebSocketConfig implements WebSocketConfigurer {
+
+ @Resource
+ private WebsocketInterceptor customWebsocketInterceptor;
+
+ @Resource
+ private MyWebSocketHandler myWebSocketHandler;
+
+ /**
+ * 注册WebSocket处理程序并设置必要的配置。
+ *
+ * @param registry 用于注册处理程序的WebSocketHandlerRegistry
+ */
+ @Override
+ public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
+ registry
+ // 设置处理器处理/custom/**
+ .addHandler(myWebSocketHandler, "/ws")
+ // 允许跨越
+ .setAllowedOrigins("*")
+ // 设置监听器
+ .addInterceptors(customWebsocketInterceptor);
+ }
+
+}
diff --git a/continew-admin-common/src/main/java/top/continew/admin/common/config/websocket/WebsocketInterceptor.java b/continew-admin-common/src/main/java/top/continew/admin/common/config/websocket/WebsocketInterceptor.java
new file mode 100644
index 00000000..e521a9cf
--- /dev/null
+++ b/continew-admin-common/src/main/java/top/continew/admin/common/config/websocket/WebsocketInterceptor.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.admin.common.config.websocket;
+
+/**
+ * Created by WeiRan on 2024.03.13 16:43
+ */
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.servlet.JakartaServletUtil;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.http.server.ServletServerHttpRequest;
+import org.springframework.http.server.ServletServerHttpResponse;
+import org.springframework.stereotype.Component;
+import org.springframework.web.socket.WebSocketHandler;
+import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
+import top.continew.admin.common.model.dto.LoginUser;
+import top.continew.admin.common.util.helper.LoginHelper;
+import top.continew.starter.web.util.ServletUtils;
+
+import java.util.Map;
+
+/**
+ * 用来处理webscocket拦截器
+ *
+ * @author WeiRan
+ * @since 2024.03.13 16:45
+ */
+@Component
+@Slf4j
+public class WebsocketInterceptor extends HttpSessionHandshakeInterceptor {
+
+ /**
+ * 在建立 WebSocket 连接之前处理握手过程。
+ *
+ * @param request HTTP 请求对象
+ * @param response HTTP 响应对象
+ * @param wsHandler WebSocket 处理程序
+ * @param attributes 用于存储 WebSocket 会话的自定义属性的映射
+ * @return 如果握手成功则返回 true,否则返回 false
+ * @throws Exception 如果在握手过程中发生错误
+ */
+ @Override
+ public boolean beforeHandshake(ServerHttpRequest request,
+ ServerHttpResponse response,
+ WebSocketHandler wsHandler,
+ Map attributes) throws Exception {
+ ServletServerHttpRequest req = (ServletServerHttpRequest)request;
+ ServletServerHttpResponse res = (ServletServerHttpResponse)response;
+
+ HttpServletRequest httpServletRequest = ServletUtils.getRequest();
+ String ip = JakartaServletUtil.getClientIP(httpServletRequest);
+ String token = req.getServletRequest().getParameter("token");
+ log.info("开始建立连接....token:{}", token);
+ log.info("attributes:{}", attributes);
+ if (StrUtil.isBlank(token)) {
+ res.setStatusCode(HttpStatus.UNAUTHORIZED);
+ res.getServletResponse().setContentType("application/json");
+ String errorMessage = "{\"error\": \"Authentication failed. Please provide valid credentials.\"}";
+ res.getBody().write(errorMessage.getBytes());
+ return false;
+ }
+
+ // 鉴权: 如果返回 false 则表示未通过
+ // response.setStatusCode(HttpStatus.UNAUTHORIZED);
+ //返回 false;
+ LoginUser loginUser = LoginHelper.getLoginUser(token);
+ if (loginUser == null) {
+ res.setStatusCode(HttpStatus.UNAUTHORIZED);
+ res.getServletResponse().setContentType("application/json");
+ String errorMessage = "{\"error\": \"Authentication failed. Please provide valid credentials.\"}";
+ res.getBody().write(errorMessage.getBytes());
+ res.close();
+ return false;
+ }
+ attributes.put("userId", String.valueOf(loginUser.getId()));
+ attributes.put("ip", ip);
+ super.setCreateSession(true);
+ return super.beforeHandshake(request, response, wsHandler, attributes);
+ }
+
+ /**
+ * WebSocket 握手成功完成后调用此方法。
+ * 它记录一条消息指示连接已建立,然后调用
+ * 方法的超类实现。
+ *
+ * @param request 表示传入 HTTP 请求的 ServerHttpRequest 对象
+ * @param response 表示传出 HTTP 响应的 ServerHttpResponse 对象
+ * @param wsHandler 将处理 WebSocket 会话的 WebSocketHandler 对象
+ * @param exception 在握手过程中发生的异常,如果没有异常则为 null
+ */
+ @Override
+ public void afterHandshake(ServerHttpRequest request,
+ ServerHttpResponse response,
+ WebSocketHandler wsHandler,
+ Exception exception) {
+ log.info("连接成功....");
+ //其他业务代码
+ super.afterHandshake(request, response, wsHandler, exception);
+ }
+}
diff --git a/continew-admin-common/src/main/java/top/continew/admin/common/handler/MyWebSocketHandler.java b/continew-admin-common/src/main/java/top/continew/admin/common/handler/MyWebSocketHandler.java
new file mode 100644
index 00000000..3efb5aca
--- /dev/null
+++ b/continew-admin-common/src/main/java/top/continew/admin/common/handler/MyWebSocketHandler.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.admin.common.handler;
+
+/**
+ * Created by WeiRan on 2024.03.13 16:41
+ */
+
+import cn.hutool.core.util.StrUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.web.socket.CloseStatus;
+import org.springframework.web.socket.TextMessage;
+import org.springframework.web.socket.WebSocketSession;
+import org.springframework.web.socket.handler.TextWebSocketHandler;
+import top.continew.admin.common.util.WsUtils;
+
+import java.io.IOException;
+
+/**
+ * @author zhong
+ * webscoket 处理器
+ */
+@Component
+@Slf4j
+public class MyWebSocketHandler extends TextWebSocketHandler {
+
+ /**
+ * 收到客户端消息时触发的回调
+ *
+ * @param session 连接对象
+ * @param message 消息体
+ */
+ @Override
+ protected void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {
+ log.info("接受到会话【{}】的消息:{}", session.getId(), message.getPayload());
+ String jsonPayload = message.getPayload();
+ if (StrUtil.isBlank(jsonPayload)) {
+ log.error("接收到空消息");
+ return;
+ }
+ try {
+ //业务逻辑处理
+ // WsUtils.send(session, "我收到了你的消息");
+ } catch (Exception e) {
+ log.error("WebSocket消息解析失败:{}", e.getMessage(), e);
+ WsUtils.close(session, "消息解析失败:" + e.getMessage());
+ }
+ }
+
+ /**
+ * 建立连接后触发的回调
+ *
+ * @param session 连接对象
+ * @throws Exception
+ */
+ @Override
+ public void afterConnectionEstablished(WebSocketSession session) throws Exception {
+ String userId = String.valueOf(session.getAttributes().get("userId"));
+ // 将新连接添加
+ WsUtils.bindUser(userId, session);
+ //在线数加1
+ WsUtils.onlineCount.incrementAndGet();
+ log.info("与用户【{}】建立了连接 当前在线人数【{}】", userId, WsUtils.onlineCount.get());
+ log.info("attributes:{}", session.getAttributes());
+
+ }
+
+ /**
+ * 断开连接后触发的回调
+ *
+ * @param session 连接对象
+ * @param status 状态
+ * @throws Exception 异常
+ */
+ @Override
+ public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
+ // 关闭连接
+ WsUtils.close(session, "断开连接后触发的回调");
+ log.info("用户【{}】断开连接,status:{},当前剩余在线人数【{}】", WsUtils.getUserId(session), status.getCode(), WsUtils.onlineCount
+ .get());
+ }
+
+ /**
+ * 传输消息出错时触发的回调
+ *
+ * @param session 连接对象
+ * @param exception 异常
+ * @throws Exception 异常
+ */
+ @Override
+ public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
+ log.info("用户【{}】发生错误,exception:{}", session.getId(), exception.getMessage());
+ // 如果发送异常,则断开连接
+ if (session.isOpen()) {
+ WsUtils.close(session, "传输消息出错时触发的回调");
+ }
+ }
+}
diff --git a/continew-admin-common/src/main/java/top/continew/admin/common/model/dto/WsMsg.java b/continew-admin-common/src/main/java/top/continew/admin/common/model/dto/WsMsg.java
new file mode 100644
index 00000000..dc845a77
--- /dev/null
+++ b/continew-admin-common/src/main/java/top/continew/admin/common/model/dto/WsMsg.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.admin.common.model.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class WsMsg implements Serializable {
+ /**
+ * 消息 ID
+ */
+ public String msgId;
+
+ /**
+ * 发送者 ID
+ */
+ public String fromId;
+
+ /**
+ * 发送人名称
+ */
+ public String fromName;
+
+ /**
+ * 接受者ID
+ */
+ public String toId;
+
+ /**
+ * 消息类型
+ */
+ public int msgType;
+
+ /**
+ * 发送消息时间戳
+ */
+ public long sendTime;
+
+ /**
+ * 消息内容
+ */
+ public String content;
+
+}
diff --git a/continew-admin-common/src/main/java/top/continew/admin/common/util/NoticeMsgUtils.java b/continew-admin-common/src/main/java/top/continew/admin/common/util/NoticeMsgUtils.java
new file mode 100644
index 00000000..2a21ce5f
--- /dev/null
+++ b/continew-admin-common/src/main/java/top/continew/admin/common/util/NoticeMsgUtils.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.admin.common.util;
+
+import top.continew.admin.common.enums.MessageTypeEnum;
+import top.continew.admin.common.model.dto.WsMsg;
+import top.continew.admin.common.util.helper.LoginHelper;
+
+public class NoticeMsgUtils {
+ public static WsMsg conversion(String massage, String id) {
+ WsMsg msg = new WsMsg();
+ msg.setMsgId(id);
+ msg.setFromId(LoginHelper.getUserId().toString());
+ msg.setFromName(LoginHelper.getUsername());
+ msg.setContent(massage);
+ msg.setMsgType(MessageTypeEnum.SYSTEM.getValue());
+ msg.setSendTime(System.currentTimeMillis());
+ return msg;
+ }
+}
diff --git a/continew-admin-common/src/main/java/top/continew/admin/common/util/WsUtils.java b/continew-admin-common/src/main/java/top/continew/admin/common/util/WsUtils.java
new file mode 100644
index 00000000..4b3942cf
--- /dev/null
+++ b/continew-admin-common/src/main/java/top/continew/admin/common/util/WsUtils.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package top.continew.admin.common.util;
+
+import com.alibaba.fastjson2.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.socket.CloseStatus;
+import org.springframework.web.socket.TextMessage;
+import org.springframework.web.socket.WebSocketSession;
+import top.continew.admin.common.model.dto.WsMsg;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * WebSocket工具类
+ *
+ * @author WeiRan
+ * @since 2024.03.13 16:45
+ */
+@Slf4j
+public class WsUtils {
+ /**
+ * 静态变量,用来记录当前用户的session,线程安全的类。
+ */
+ public static ConcurrentHashMap webSocketSessionMap = new ConcurrentHashMap<>();
+
+ /**
+ * 静态变量,用来记录当前在线连接数,线程安全的类。
+ */
+ public static AtomicInteger onlineCount = new AtomicInteger(0);
+
+ /**
+ * 绑定用户连接
+ *
+ * @param userId 用户ID
+ * @param session WebSocketSession信息
+ */
+ public static void bindUser(String userId, WebSocketSession session) {
+ webSocketSessionMap.put(userId, session);
+ }
+
+ /**
+ * 删除连接
+ *
+ * @param session WebSocketSession信息
+ */
+ public static void remove(WebSocketSession session) {
+ //在线数减1
+ onlineCount.decrementAndGet();
+ webSocketSessionMap.remove(getUserId(session));
+ }
+
+ /**
+ * 关闭 WebSocket 连接的方法。
+ *
+ * @param webSocketSession WebSocketSession信息,表示当前的 WebSocket 连接。
+ * @param msg 发送消息内容,用于记录关闭连接的原因或相关信息。
+ * @throws IOException 当关闭 WebSocket 连接时可能抛出的 IO 异常。
+ */
+ public static void close(WebSocketSession webSocketSession, String msg) throws IOException {
+ String userId = getUserId(webSocketSession);
+ if (!webSocketSession.isOpen()) {
+ WsUtils.remove(webSocketSession);
+ log.warn("连接对象【{}】已关闭:{}", userId, msg);
+ } else {
+ webSocketSession.close(CloseStatus.SERVER_ERROR);
+ WsUtils.remove(webSocketSession);
+ log.error("服务端主动关闭连接:用户{}信息:{}", userId, msg);
+ }
+ }
+
+ /**
+ * 通过用户ID获取对应的 WebSocketSession。
+ *
+ * @param userId 用户ID,用于查找对应的 WebSocketSession。
+ * @return WebSocketSession 如果存在与给定用户ID对应的 WebSocketSession,则返回该对象;如果不存在,则返回 null。
+ */
+ public static WebSocketSession getWebSocketSession(String userId) {
+ return webSocketSessionMap.get(userId);
+ }
+
+ /**
+ * 获取用户的session
+ *
+ * @param session WebSocketSession对象,包含用户的会话信息
+ * @return 用户的ID,类型为字符串
+ */
+ public static String getUserId(WebSocketSession session) {
+ return (String)session.getAttributes().get("userId");
+ }
+
+ /**
+ * 获取用户的IP地址
+ *
+ * @param session WebSocketSession对象,包含用户的会话信息
+ * @return 用户的IP地址,类型为字符串
+ */
+ public static String getIp(WebSocketSession session) {
+ return (String)session.getAttributes().get("ip");
+ }
+
+ /**
+ * 判断链接是否存在
+ *
+ * @param userId 用户ID,用于查找对应的WebSocket会话
+ * @return 如果映射中存在该用户ID对应的链接,返回true;否则返回false
+ */
+ public static boolean contains(String userId) {
+ return WsUtils.webSocketSessionMap.containsKey(userId);
+ }
+
+ /**
+ * 判断链接是否存在
+ *
+ * @param webSocketSession WebSocketSession对象,包含用户的会话信息
+ * @return 如果映射中存在该用户ID对应的链接,返回true;否则返回false
+ */
+ public static boolean contains(WebSocketSession webSocketSession) {
+ return WsUtils.webSocketSessionMap.containsKey(getUserId(webSocketSession));
+ }
+
+ /**
+ * 获取所有用户连接的用户ID列表。
+ *
+ * @return List 包含所有已连接用户的用户ID的列表。
+ */
+ public static List getUserList() {
+ return Collections.list(webSocketSessionMap.keys());
+ }
+
+ /**
+ * 发送消息给指定用户。
+ *
+ * @param userId 用户ID,用于指定消息接收者。
+ * @param message 消息内容,要发送给指定用户的消息。
+ * @throws IOException 当发送消息时可能抛出的 IO 异常。
+ */
+ public static void sendToUser(String userId, String message) {
+ WebSocketSession webSocketSession = getWebSocketSession(userId);
+
+ if (webSocketSession == null || !webSocketSession.isOpen()) {
+ log.warn("用户【{}】已关闭,无法送消息:{}", userId, message);
+ } else {
+ try {
+ webSocketSession.sendMessage(new TextMessage(message));
+ } catch (IOException e) {
+ log.error("发送消息失败:{}", e.getMessage(), e);
+ }
+ log.info("sendMessage:向{}发送消息:{}", userId, message);
+ }
+ }
+
+ /**
+ * 发送消息给指定用户。
+ *
+ * @param userId 目标用户的ID。
+ * @param message 要发送的消息对象。
+ * @throws IOException 如果发生IO异常。
+ */
+ public static void sendToUser(String userId, WsMsg message) {
+ WebSocketSession webSocketSession = getWebSocketSession(userId);
+ if (webSocketSession == null || !webSocketSession.isOpen()) {
+ log.warn("用户【{}】已关闭,无法送消息:{}", userId, JSONObject.toJSONString(message));
+ } else {
+ try {
+ webSocketSession.sendMessage(new TextMessage(JSONObject.toJSONString(message)));
+ } catch (IOException e) {
+ log.error("发送消息失败:{}", e.getMessage(), e);
+ }
+ log.info("sendMessage:向{}发送消息:{}", userId, JSONObject.toJSONString(message));
+ }
+ }
+
+ /**
+ * 发送消息全部在线用户
+ *
+ * @param message 发送的消息内容
+ * @throws IOException 如果发生IO异常。
+ */
+ public static void sendToAll(String message) {
+ getUserList().forEach(userId -> sendToUser(userId, message));
+ }
+
+ /**
+ * 发送消息全部在线用户
+ *
+ * @param message 发送的消息内容
+ * @throws IOException 如果发生IO异常。
+ */
+ public static void sendToAll(WsMsg message) {
+ getUserList().forEach(userId -> sendToUser(userId, JSONObject.toJSONString(message)));
+ }
+
+ /**
+ * 发送通过webSocketSession发送消息
+ *
+ * @param webSocketSession 对象id
+ * @param message 发送的消息内容
+ * @throws IOException 如果发生IO异常。
+ */
+ public static void send(WebSocketSession webSocketSession, String message) {
+
+ if (webSocketSession == null || !webSocketSession.isOpen()) {
+ log.warn("连接对象【{}】已关闭,无法送消息:{}", webSocketSession.getId(), message);
+ } else {
+ try {
+ webSocketSession.sendMessage(new TextMessage(message));
+ } catch (IOException e) {
+ log.error("发送消息失败:{}", e.getMessage(), e);
+ }
+ log.info("sendMessage:向{}发送消息:{}", webSocketSession.getId(), message);
+ }
+ }
+
+ /**
+ * 通过 WebSocketSession 对象发送消息。
+ *
+ * @param webSocketSession 目标 WebSocketSession 对象。
+ * @param wsMsg 要发送的WsMsg消息对象。
+ * @throws IOException 如果发生IO异常。
+ */
+ public static void send(WebSocketSession webSocketSession, WsMsg wsMsg) {
+ if (webSocketSession == null || !webSocketSession.isOpen()) {
+ log.warn("连接对象【{}】已关闭,无法送消息:{}", webSocketSession.getId(), JSONObject.toJSONString(wsMsg));
+ } else {
+ try {
+ webSocketSession.sendMessage(new TextMessage(JSONObject.toJSONString(wsMsg)));
+ } catch (IOException e) {
+ log.error("发送消息失败:{}", e.getMessage(), e);
+ }
+ log.info("sendMessage:向{}发送消息:{}", webSocketSession.getId(), JSONObject.toJSONString(wsMsg));
+ }
+ }
+
+}
diff --git a/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/MessageServiceImpl.java b/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/MessageServiceImpl.java
index aa067294..9ca9ab0d 100644
--- a/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/MessageServiceImpl.java
+++ b/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/MessageServiceImpl.java
@@ -24,6 +24,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
+import top.continew.admin.common.util.helper.LoginHelper;
import top.continew.admin.system.mapper.MessageMapper;
import top.continew.admin.system.model.entity.MessageDO;
import top.continew.admin.system.model.query.MessageQuery;
@@ -66,6 +67,7 @@ public class MessageServiceImpl implements MessageService {
public void add(MessageReq req, List userIdList) {
CheckUtils.throwIf(() -> CollUtil.isEmpty(userIdList), "消息接收人不能为空");
MessageDO message = BeanUtil.copyProperties(req, MessageDO.class);
+ message.setCreateUser(LoginHelper.getUserId());
baseMapper.insert(message);
messageUserService.add(message.getId(), userIdList);
}
diff --git a/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/MessageUserServiceImpl.java b/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/MessageUserServiceImpl.java
index 1a1a9d4e..fdf103df 100644
--- a/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/MessageUserServiceImpl.java
+++ b/continew-admin-system/src/main/java/top/continew/admin/system/service/impl/MessageUserServiceImpl.java
@@ -20,6 +20,7 @@ import cn.hutool.core.collection.CollUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import top.continew.admin.common.enums.MessageTypeEnum;
+import top.continew.admin.common.util.helper.LoginHelper;
import top.continew.admin.system.mapper.MessageUserMapper;
import top.continew.admin.system.model.entity.MessageUserDO;
import top.continew.admin.system.model.resp.MessageTypeUnreadResp;
@@ -84,6 +85,7 @@ public class MessageUserServiceImpl implements MessageUserService {
.set(MessageUserDO::getIsRead, true)
.set(MessageUserDO::getReadTime, LocalDateTime.now())
.eq(MessageUserDO::getIsRead, false)
+ .eq(MessageUserDO::getUserId, LoginHelper.getUserId())
.in(CollUtil.isNotEmpty(ids), MessageUserDO::getMessageId, ids)
.update();
}
diff --git a/continew-admin-webapi/src/main/java/top/continew/admin/webapi/system/MessageController.java b/continew-admin-webapi/src/main/java/top/continew/admin/webapi/system/MessageController.java
index 10dd1d2a..43984c59 100644
--- a/continew-admin-webapi/src/main/java/top/continew/admin/webapi/system/MessageController.java
+++ b/continew-admin-webapi/src/main/java/top/continew/admin/webapi/system/MessageController.java
@@ -16,6 +16,7 @@
package top.continew.admin.webapi.system;
+import cn.hutool.core.util.IdUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
@@ -23,8 +24,12 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
+import top.continew.admin.common.enums.MessageTypeEnum;
+import top.continew.admin.common.util.NoticeMsgUtils;
+import top.continew.admin.common.util.WsUtils;
import top.continew.admin.common.util.helper.LoginHelper;
import top.continew.admin.system.model.query.MessageQuery;
+import top.continew.admin.system.model.req.MessageReq;
import top.continew.admin.system.model.resp.MessageResp;
import top.continew.admin.system.model.resp.MessageUnreadResp;
import top.continew.admin.system.service.MessageService;
@@ -34,6 +39,7 @@ import top.continew.starter.extension.crud.model.resp.PageResp;
import top.continew.starter.web.model.R;
import top.continew.starter.log.core.annotation.Log;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -81,4 +87,17 @@ public class MessageController {
public R countUnreadMessage(@RequestParam(required = false) Boolean detail) {
return R.ok(messageUserService.countUnreadMessageByUserId(LoginHelper.getUserId(), detail));
}
+
+ @GetMapping("/testSend")
+ public R