diff --git a/ALOps_sys_backend/alops-admin/src/main/java/com/alops/web/controller/exceptionController/AlertMessageController.java b/ALOps_sys_backend/alops-admin/src/main/java/com/alops/web/controller/exceptionController/AlertMessageController.java index 04ae0b6d..f6ca0cba 100644 --- a/ALOps_sys_backend/alops-admin/src/main/java/com/alops/web/controller/exceptionController/AlertMessageController.java +++ b/ALOps_sys_backend/alops-admin/src/main/java/com/alops/web/controller/exceptionController/AlertMessageController.java @@ -44,26 +44,26 @@ public class AlertMessageController extends BaseController /** * 立即执行预警(带规则 ID 列表) */ -// @PreAuthorize("@ss.hasPermi('equipment:rules:execute')") -// @ApiOperation("立即执行预警") -// @Log(title = "【立即执行预警】", businessType = BusinessType.DELETE) -// @PostMapping("/executeImmediate") -// public AjaxResult executeImmediate(@RequestBody Map> paramMap) { -// try { -// List ruleIds = paramMap.get("ruleIds"); -// if (ruleIds == null || ruleIds.isEmpty()) { -// return AjaxResult.error("请选择至少一条规则"); -// } -// -// iAlertLaunchService.executeImmediateAlerts(); // 调用 Service 执行 -// return AjaxResult.success("立即预警任务已触发,存入成功,请查看"); -// -// } catch (Exception e) { -// e.printStackTrace(); -// return AjaxResult.error("执行立即预警失败: " + e.getMessage()); -// } -// -// } + @PreAuthorize("@ss.hasPermi('equipment:rules:execute')") + @ApiOperation("立即执行预警") + @Log(title = "【立即执行预警】", businessType = BusinessType.DELETE) + @PostMapping("/executeImmediate") + public AjaxResult executeImmediate(@RequestBody Map> paramMap) { + try { + List ruleIds = paramMap.get("ruleIds"); + if (ruleIds == null || ruleIds.isEmpty()) { + return AjaxResult.error("请选择至少一条规则"); + } + + iAlertLaunchService.executeImmediateAlerts(); // 调用 Service 执行 + return AjaxResult.success("立即预警任务已触发,存入成功,请查看"); + + } catch (Exception e) { + e.printStackTrace(); + return AjaxResult.error("执行立即预警失败: " + e.getMessage()); + } + + } /** * 修改预警信息 @@ -78,11 +78,11 @@ public class AlertMessageController extends BaseController } /** - * 查询预警信息统计列表 + * 首页查询预警信息统计列表 */ @PreAuthorize("@ss.hasPermi('inMonitoring:alertMessage:statistic:list')") @GetMapping ("/statistic/list") - @ApiOperation("查询预警信息") + @ApiOperation("首页查询预警信息") @Log(title = "查询预警信息", businessType = BusinessType.UPDATE) public TableDataInfo homeList() { @@ -93,7 +93,7 @@ public class AlertMessageController extends BaseController /** - * 首页查询预警信息统计列表 + * 查询预警信息统计列表 */ @PreAuthorize("@ss.hasPermi('inMonitoring:alertMessage:list')") @GetMapping ("/list") diff --git a/ALOps_sys_backend/alops-framework/src/main/java/com/alops/framework/config/SecurityConfig.java b/ALOps_sys_backend/alops-framework/src/main/java/com/alops/framework/config/SecurityConfig.java index 58059c7e..b10bb94a 100644 --- a/ALOps_sys_backend/alops-framework/src/main/java/com/alops/framework/config/SecurityConfig.java +++ b/ALOps_sys_backend/alops-framework/src/main/java/com/alops/framework/config/SecurityConfig.java @@ -115,7 +115,9 @@ public class SecurityConfig // 静态资源,可匿名访问 .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll() .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**","/swagger-ui/**").permitAll() - // 除上面外的所有请求全部需要鉴权认证 + .antMatchers("/ws/**").permitAll() + + // 除上面外的所有请求全部需要鉴权认证 .anyRequest().authenticated(); }) // 添加Logout filter diff --git a/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/config/WebSocketConfig.java b/ALOps_sys_backend/alops-framework/src/main/java/com/alops/framework/config/WebSocketConfig.java similarity index 54% rename from ALOps_sys_backend/alops-system/src/main/java/com/alops/system/config/WebSocketConfig.java rename to ALOps_sys_backend/alops-framework/src/main/java/com/alops/framework/config/WebSocketConfig.java index 85956d61..54960b75 100644 --- a/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/config/WebSocketConfig.java +++ b/ALOps_sys_backend/alops-framework/src/main/java/com/alops/framework/config/WebSocketConfig.java @@ -1,20 +1,27 @@ -package com.alops.system.config; +package com.alops.framework.config; -import com.alops.system.hander.WebSocketServer; + +import com.alops.framework.hander.WebSocketServer; +import org.springframework.beans.factory.annotation.Autowired; 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; - -//理解为WebSocket的controller +//注册端点,允许跨域 @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { + + @Autowired + private WebSocketServer webSocketServer; + + @Autowired + private WebSocketHandshakeInterceptor handshakeInterceptor; + @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { - - registry.addHandler(new WebSocketServer(), "/ws/onlineMessage") + registry.addHandler(webSocketServer, "/ws/onlineMessage") + .addInterceptors(handshakeInterceptor) .setAllowedOrigins("*"); - } -} \ No newline at end of file +} diff --git a/ALOps_sys_backend/alops-framework/src/main/java/com/alops/framework/config/WebSocketHandshakeInterceptor.java b/ALOps_sys_backend/alops-framework/src/main/java/com/alops/framework/config/WebSocketHandshakeInterceptor.java new file mode 100644 index 00000000..5e937dde --- /dev/null +++ b/ALOps_sys_backend/alops-framework/src/main/java/com/alops/framework/config/WebSocketHandshakeInterceptor.java @@ -0,0 +1,65 @@ +package com.alops.framework.config; + +import com.alops.common.core.domain.model.LoginUser; +import com.alops.framework.web.service.TokenService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; + +import org.springframework.stereotype.Component; +import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.server.HandshakeInterceptor; + +import java.util.List; +import java.util.Map; +//拦截器设置,首先在springscrity放行 +@Slf4j +@Component +public class WebSocketHandshakeInterceptor implements HandshakeInterceptor { + + @Autowired + private TokenService tokenService; + + @Override + public boolean beforeHandshake(ServerHttpRequest request, + ServerHttpResponse response, + WebSocketHandler wsHandler, + Map attributes) { + + try { + List protocols = request.getHeaders().get("Sec-WebSocket-Protocol"); + if (protocols == null || protocols.isEmpty()) { + log.warn("【WS握手失败】未携带Token"); + return false; + } + + String token = protocols.get(0); + LoginUser loginUser = tokenService.getLoginUser(token); + if (loginUser == null) { + log.warn("【WS握手失败】无效Token"); + return false; + } + + // 验证并刷新 Token + tokenService.verifyToken(loginUser); + + // 设置返回协议头(必须,否则浏览器报错) + response.getHeaders().add("Sec-WebSocket-Protocol", token); + + // 把用户信息写入 session attributes + attributes.put("loginUser", loginUser); + log.info("【WS握手成功】用户:{}", loginUser.getUsername()); + return true; + + } catch (Exception e) { + log.error("【WS握手异常】", e); + return false; + } + } + + @Override + public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, + WebSocketHandler wsHandler, Exception exception) { + } +} diff --git a/ALOps_sys_backend/alops-framework/src/main/java/com/alops/framework/hander/WebSocketServer.java b/ALOps_sys_backend/alops-framework/src/main/java/com/alops/framework/hander/WebSocketServer.java new file mode 100644 index 00000000..774cf020 --- /dev/null +++ b/ALOps_sys_backend/alops-framework/src/main/java/com/alops/framework/hander/WebSocketServer.java @@ -0,0 +1,43 @@ +package com.alops.framework.hander; + +import com.alops.common.core.domain.model.LoginUser; + +import com.alops.system.service.impl.WebSocketService; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.CloseStatus; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.handler.TextWebSocketHandler; +import org.slf4j.LoggerFactory; +@Component +public class WebSocketServer extends TextWebSocketHandler { + + @Autowired + private WebSocketService webSocketService; + + + private final Logger logger = LoggerFactory.getLogger(WebSocketServer.class); + @Override + public void afterConnectionEstablished(WebSocketSession session) throws Exception { + LoginUser loginUser = (LoginUser) session.getAttributes().get("loginUser"); + if (loginUser != null && loginUser.getUser() != null) { + Long userId = loginUser.getUser().getUserId(); + webSocketService.addOnlineUser(userId, session); + logger.info("WebSocket 连接成功,用户上线: {}", userId); + } else { + logger.warn("无效连接,关闭 session: {}", session.getId()); + session.close(); + } + } + + @Override + public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { + LoginUser loginUser = (LoginUser) session.getAttributes().get("loginUser"); + if (loginUser != null && loginUser.getUser() != null) { + Long userId = loginUser.getUser().getUserId(); + webSocketService.removeOnlineUser(userId); + logger.info("WebSocket 连接关闭,用户下线: {}, 状态: {}", userId, status); + } + } +} diff --git a/ALOps_sys_backend/alops-framework/src/main/java/com/alops/framework/web/service/TokenService.java b/ALOps_sys_backend/alops-framework/src/main/java/com/alops/framework/web/service/TokenService.java index 7461d0f8..14c024ad 100644 --- a/ALOps_sys_backend/alops-framework/src/main/java/com/alops/framework/web/service/TokenService.java +++ b/ALOps_sys_backend/alops-framework/src/main/java/com/alops/framework/web/service/TokenService.java @@ -31,8 +31,7 @@ import io.jsonwebtoken.SignatureAlgorithm; * @author ruoyi */ @Component -public class TokenService -{ +public class TokenService { private static final Logger log = LoggerFactory.getLogger(TokenService.class); // 令牌自定义标识 @@ -58,17 +57,14 @@ public class TokenService /** * 获取用户身份信息 - * + * * @return 用户信息 */ - public LoginUser getLoginUser(HttpServletRequest request) - { + public LoginUser getLoginUser(HttpServletRequest request) { // 获取请求携带的令牌 String token = getToken(request); - if (StringUtils.isNotEmpty(token)) - { - try - { + if (StringUtils.isNotEmpty(token)) { + try { Claims claims = parseToken(token); // 解析对应的权限以及用户信息 String uuid = (String) claims.get(Constants.LOGIN_USER_KEY); @@ -78,22 +74,42 @@ public class TokenService LoginUser user = JSON.parseObject(userJson, LoginUser.class); return user; - } - catch (Exception e) - { + } catch (Exception e) { log.error("获取用户信息异常'{}'", e.getMessage()); } } return null; } + + public LoginUser getLoginUser(String token) { + + if (StringUtils.isEmpty(token)) { + return null; + } + + // 去掉可能的 "token-" 前缀 + if (token.startsWith("token-")) { + token = token.substring(6); + } + try { + Claims claims = parseToken(token); + String uuid = (String) claims.get(Constants.LOGIN_USER_KEY); + String userKey = getTokenKey(uuid); + Object userObj = redisCache.getCacheObject(userKey); + String userJson = JSON.toJSONString(userObj); + return JSON.parseObject(userJson, LoginUser.class); + } catch (Exception e) { + log.error("获取用户信息异常'{}'", e.getMessage()); + return null; + } + } + /** * 设置用户身份信息 */ - public void setLoginUser(LoginUser loginUser) - { - if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken())) - { + public void setLoginUser(LoginUser loginUser) { + if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken())) { refreshToken(loginUser); } } @@ -101,10 +117,8 @@ public class TokenService /** * 删除用户身份信息 */ - public void delLoginUser(String token) - { - if (StringUtils.isNotEmpty(token)) - { + public void delLoginUser(String token) { + if (StringUtils.isNotEmpty(token)) { String userKey = getTokenKey(token); redisCache.deleteObject(userKey); } @@ -112,12 +126,11 @@ public class TokenService /** * 创建令牌 - * + * * @param loginUser 用户信息 * @return 令牌 */ - public String createToken(LoginUser loginUser) - { + public String createToken(LoginUser loginUser) { String token = IdUtils.fastUUID(); loginUser.setToken(token); setUserAgent(loginUser); @@ -131,27 +144,24 @@ public class TokenService /** * 验证令牌有效期,相差不足20分钟,自动刷新缓存 - * + * * @param loginUser 登录信息 * @return 令牌 */ - public void verifyToken(LoginUser loginUser) - { + public void verifyToken(LoginUser loginUser) { long expireTime = loginUser.getExpireTime(); long currentTime = System.currentTimeMillis(); - if (expireTime - currentTime <= MILLIS_MINUTE_TWENTY) - { + if (expireTime - currentTime <= MILLIS_MINUTE_TWENTY) { refreshToken(loginUser); } } /** * 刷新令牌有效期 - * + * * @param loginUser 登录信息 */ - public void refreshToken(LoginUser loginUser) - { + public void refreshToken(LoginUser loginUser) { loginUser.setLoginTime(System.currentTimeMillis()); loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE); // 根据uuid将loginUser缓存 @@ -161,11 +171,10 @@ public class TokenService /** * 设置用户代理信息 - * + * * @param loginUser 登录信息 */ - public void setUserAgent(LoginUser loginUser) - { + public void setUserAgent(LoginUser loginUser) { UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent")); String ip = IpUtils.getIpAddr(); loginUser.setIpaddr(ip); @@ -180,8 +189,7 @@ public class TokenService * @param claims 数据声明 * @return 令牌 */ - private String createToken(Map claims) - { + private String createToken(Map claims) { String token = Jwts.builder() .setClaims(claims) .signWith(SignatureAlgorithm.HS512, secret).compact(); @@ -194,8 +202,7 @@ public class TokenService * @param token 令牌 * @return 数据声明 */ - private Claims parseToken(String token) - { + private Claims parseToken(String token) { return Jwts.parser() .setSigningKey(secret) .parseClaimsJws(token) @@ -208,8 +215,7 @@ public class TokenService * @param token 令牌 * @return 用户名 */ - public String getUsernameFromToken(String token) - { + public String getUsernameFromToken(String token) { Claims claims = parseToken(token); return claims.getSubject(); } @@ -220,18 +226,16 @@ public class TokenService * @param request * @return token */ - private String getToken(HttpServletRequest request) - { + private String getToken(HttpServletRequest request) { String token = request.getHeader(header); - if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) - { + if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) { token = token.replace(Constants.TOKEN_PREFIX, ""); } return token; } - private String getTokenKey(String uuid) - { + private String getTokenKey(String uuid) { return CacheConstants.LOGIN_TOKEN_KEY + uuid; } -} + +} \ No newline at end of file diff --git a/ALOps_sys_backend/alops-system/pom.xml b/ALOps_sys_backend/alops-system/pom.xml index 8fb697ec..a5d3d345 100644 --- a/ALOps_sys_backend/alops-system/pom.xml +++ b/ALOps_sys_backend/alops-system/pom.xml @@ -94,6 +94,7 @@ + \ No newline at end of file diff --git a/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/AlertMessage.java b/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/AlertMessage.java index ce625b13..3af74c24 100644 --- a/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/AlertMessage.java +++ b/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/AlertMessage.java @@ -5,6 +5,7 @@ import java.util.Date; import com.alops.common.annotation.Excel; import com.alops.common.core.domain.BaseEntity; import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; @@ -73,6 +74,9 @@ public class AlertMessage @Excel(name ="预警信息") private String message; + @JsonIgnore + @Excel(name ="预警规则id") + private Long alertRuleId; diff --git a/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/EquBase.java b/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/EquBase.java index 60a8f6b2..7ba6f50d 100644 --- a/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/EquBase.java +++ b/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/EquBase.java @@ -56,7 +56,8 @@ public class EquBase @Excel(name = "设备类型 id") private String equTypeId; - + @Excel(name = "楼层位置") + private String floor; public EquType getEquTypeVO() { return equTypeVO; diff --git a/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/vo/homeEquAlertMessageVo.java b/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/vo/homeEquAlertMessageVo.java index 81d7bcf9..b0a622b1 100644 --- a/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/vo/homeEquAlertMessageVo.java +++ b/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/vo/homeEquAlertMessageVo.java @@ -26,12 +26,14 @@ public class homeEquAlertMessageVo { @Excel(name = "处理状态") private String status; - @Excel(name = "处理状态") + @Excel(name = "设备名称") private String name; - @Excel(name = "处理状态") + @Excel(name = "设备位置") private String location; + @Excel(name = "预警规则名称") + private String ruleName; } diff --git a/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/vo/queryEquBaseVO.java b/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/vo/queryEquBaseVO.java index 365eb167..9a10c7ea 100644 --- a/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/vo/queryEquBaseVO.java +++ b/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/domain/vo/queryEquBaseVO.java @@ -99,6 +99,9 @@ public class queryEquBaseVO { @Excel(name = "设备编号") private String equNumber; + @Excel(name = "楼层位置") + private String floor; + public void setId(String id) diff --git a/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/hander/WebSocketServer.java b/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/hander/WebSocketServer.java deleted file mode 100644 index db358635..00000000 --- a/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/hander/WebSocketServer.java +++ /dev/null @@ -1,153 +0,0 @@ -package com.alops.system.hander; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.util.MultiValueMap; -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 org.springframework.web.util.UriComponentsBuilder; -import com.fasterxml.jackson.databind.ObjectMapper; - -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -@Component -public class WebSocketServer extends TextWebSocketHandler { - private static final Logger logger = LoggerFactory.getLogger(WebSocketServer.class); - // 存储在线用户 (Key: 用户ID, Value: WebSocketSession) - public static final ConcurrentHashMap onlineUsers = new ConcurrentHashMap<>(); - - - private static ObjectMapper objectMapper; - - - @Autowired - public void setObjectMapper(ObjectMapper mapper) { - WebSocketServer.objectMapper = mapper; - } - - @Override - public void afterConnectionEstablished(WebSocketSession session) throws Exception { - Long userId = getUserIdFromSession(session); - if (userId != null) { - logger.info("WebSocket 连接成功,用户上线: " + userId); - onlineUsers.put(userId, session); - } else { - logger.warn("无效的用户连接,关闭连接: " + session.getId()); - session.close(); // 没有 userId 的连接直接关闭 - } - } - - @Override - public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { - Long userId = getUserIdFromSession(session); - if (userId != null) { - - logger.info("WebSocket 连接关闭,用户下线: " + userId + ", 关闭状态: " + status); - onlineUsers.remove(userId); - - } - } - - // 获取 WebSocketSession 中的 userId,并转换为 Long 类型 - public static Long getUserIdFromSession(WebSocketSession session) { - String query = session.getUri().getQuery(); - logger.info("WebSocket连接查询参数: {}", query); - - if (query != null) { - MultiValueMap params = UriComponentsBuilder.newInstance() - .query(query) - .build() - .getQueryParams(); - String userIdStr = params.getFirst("userId"); - if (userIdStr != null) { - try { - return Long.parseLong(userIdStr); - } catch (NumberFormatException e) { - logger.error("WebSocket连接无效的用户ID: {}", userIdStr, e); - } - } else { - logger.warn("WebSocket连接没有 userId 参数"); - } - } else { - logger.warn("WebSocket连接没有查询参数"); - } - return null; - } -// -// // 发送消息给指定用户 -// public void sendMessageToUser(Long userId, String content, String title) throws Exception { -// // 获取对应用户的 WebSocket session -// WebSocketSession session = onlineUsers.get(userId); -// -// // 检查 session 是否有效且连接未关闭 -// if (session != null && session.isOpen()) { -// // 创建一个 Map 来构建消息内容 -// Map messageMap = new HashMap<>(); -// messageMap.put("from UserName", fromUserName); // 发送者姓名 -// messageMap.put("content", content); // 消息内容 -// -// // 使用 Jackson ObjectMapper 将 Map 转换为 JSON 字符串 -// ObjectMapper objectMapper = new ObjectMapper(); -// String jsonMessage = objectMapper.writeValueAsString(messageMap); -// -// // 发送 JSON 格式的消息 -// session.sendMessage(new TextMessage(jsonMessage)); -// } -// } - - - /** - * 发送通知到指定用户 - * @param messageId 数据库中站内信的ID - * @param title 通知标题,例如 "设备异常预警" - * @param content 通知内容 - */ - public static void sendAlertMessage(Long userId, Long messageId, String title, String content) { - WebSocketSession session = onlineUsers.get(userId); - try { - if (session != null && session.isOpen()) { - - // 构建消息内容 - Map messageMap = new HashMap<>(); - messageMap.put("messageId", messageId); // 对应数据库ID - messageMap.put("title", title); // 弹窗标题 - messageMap.put("content", content); // 弹窗内容 - messageMap.put("timestamp", new Date()); // 发送时间 - - // 转换为 JSON - String jsonMessage = objectMapper.writeValueAsString(messageMap); - - // 发送 - session.sendMessage(new TextMessage(jsonMessage)); - logger.info("成功向用户 [{}] 发送预警消息: {}", session.getId(), jsonMessage); - } - } catch (Exception e) { - logger.error("发送预警消息失败: messageId=" + messageId, e); - } - } - - - public void sendMessageToUser1(Long userId, String message) throws Exception { - WebSocketSession session = onlineUsers.get(userId); - if (session != null && session.isOpen()) { - session.sendMessage(new TextMessage(message)); - } - } - - // 获取所有在线用户 ID (Long 类型) - public Set getOnlineUserIds() { - return onlineUsers.keySet(); - } - - - -} diff --git a/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/AlertLaunchServiceImpl.java b/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/AlertLaunchServiceImpl.java index aa52820e..5fbc1b34 100644 --- a/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/AlertLaunchServiceImpl.java +++ b/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/AlertLaunchServiceImpl.java @@ -154,6 +154,7 @@ public class AlertLaunchServiceImpl implements IAlertLaunchService { msg.setBatch(currentBatch); msg.setMessage(msgdes); + msg.setAlertRuleId(rule.getId()); messages.add(msg); msgs.add(msgdes); diff --git a/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/AlertSenderServiceImpl.java b/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/AlertSenderServiceImpl.java index bc0f7243..e0662387 100644 --- a/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/AlertSenderServiceImpl.java +++ b/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/AlertSenderServiceImpl.java @@ -1,13 +1,16 @@ package com.alops.system.service.impl; import com.alops.common.core.domain.entity.SysUser; -import com.alops.system.domain.AlertMessage; + import com.alops.system.domain.InternalMessage; -import com.alops.system.hander.WebSocketServer; + import com.alops.system.mapper.InternalMessageMapper; import com.alops.system.mapper.SysUserMapper; import com.alops.system.service.IAlertSenderService; + + + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -31,6 +34,8 @@ public class AlertSenderServiceImpl implements IAlertSenderService { @Autowired private InternalMessageMapper messageMapper; // 站内信 Mapper + @Autowired + private WebSocketService webSocketService; @Value("${spring.mail.username}") private String from; @@ -127,7 +132,7 @@ public class AlertSenderServiceImpl implements IAlertSenderService { Long messageId = (Long) item.get("id"); // 调用 WebSocket 工具发送 - WebSocketServer.sendAlertMessage(userId, messageId, title, content); + webSocketService.sendAlertMessage(userId, messageId, title, content); } log.info("共发送站内信 {} 条(角色ID={})", result.size(), roleId); diff --git a/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/ScheduleRulesServiceImpl.java b/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/ScheduleRulesServiceImpl.java index ecf3d3b0..60c4a0c2 100644 --- a/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/ScheduleRulesServiceImpl.java +++ b/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/ScheduleRulesServiceImpl.java @@ -360,25 +360,74 @@ public class ScheduleRulesServiceImpl implements IScheduleRulesService { executor.shutdown(); - // ✅ 完整性校验:找出所有子表为空的设备 - List invalidDevices = successList.stream() - .filter(g -> g.getSubEntities() == null - || g.getSubEntities().isEmpty() - || g.getSubEntities().values().stream().anyMatch(list -> list == null || list.isEmpty())) - .map(g -> g.getEquGather().getEquId()) - .collect(Collectors.toList()); +// // ✅ 完整性校验:找出所有子表为空的设备 +// List invalidDevices = successList.stream() +// .filter(g -> g.getSubEntities() == null +// || g.getSubEntities().isEmpty() +// || g.getSubEntities().values().stream().anyMatch(list -> list == null || list.isEmpty())) +// .map(g -> g.getEquGather().getEquId()) +// .collect(Collectors.toList()); +// +// // 如果全部失败或者发现不完整设备,抛异常 +// if (successList.isEmpty() || !invalidDevices.isEmpty()) { +// String msg = "本次采集失败,保持旧数据完好。失败设备:" + +// String.join(", ", failed) + +// (invalidDevices.isEmpty() ? "" : ",采集数据不完整设备:" + String.join(", ", invalidDevices)); +// log.error(msg); +// throw new RuntimeException(msg); // 异常抛出去,外层可捕获发送邮件 +// } + // ✅ 完整性校验:找出所有子表为空的设备及对应子表 + Map> invalidDeviceMap = successList.stream() + .map(g -> { + String equId = g.getEquGather().getEquId(); + + // 找出这个设备下不完整的子表 + List emptyTables = new ArrayList<>(); + + // subEntities 为空或没有数据 + if (g.getSubEntities() == null || g.getSubEntities().isEmpty()) { + emptyTables.add("所有子表为空"); + } else { + // 检查每个子表的值 + g.getSubEntities().forEach((tableName, list) -> { + if (list == null || list.isEmpty()) { + emptyTables.add(tableName); + } + }); + } + + // 如果有任何空子表,返回 (设备ID, 空表列表) + return emptyTables.isEmpty() ? null : Map.entry(equId, emptyTables); + }) + .filter(Objects::nonNull) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + +// ✅ 提取不完整设备ID列表 + List invalidDevices = new ArrayList<>(invalidDeviceMap.keySet()); - // 如果全部失败或者发现不完整设备,抛异常 +// ✅ 如果全部失败或有不完整设备,抛异常 if (successList.isEmpty() || !invalidDevices.isEmpty()) { - String msg = "本次采集失败,保持旧数据完好。失败设备:" + - String.join(", ", failed) + - (invalidDevices.isEmpty() ? "" : ",采集数据不完整设备:" + String.join(", ", invalidDevices)); - log.error(msg); - throw new RuntimeException(msg); // 异常抛出去,外层可捕获发送邮件 + StringBuilder msg = new StringBuilder("本次采集失败,保持旧数据完好。"); + + if (!failed.isEmpty()) { + msg.append("失败设备:").append(String.join(", ", failed)); + } + + if (!invalidDeviceMap.isEmpty()) { + msg.append(";采集数据不完整设备如下:"); + invalidDeviceMap.forEach((equId, tables) -> + msg.append("\n设备[").append(equId).append("] 缺少表:") + .append(String.join(", ", tables))); + } + + log.error(msg.toString()); + throw new RuntimeException(msg.toString()); } - // 事务内:删除旧表 + 插入成功设备数据 + + // 事务内:删除旧表 + 插入成功设备数据+执行预警 deleteAllEquipmentData(); // 删除依附表,不含 equ_gather - int inserted = persistAndUpdate(successList); // 插入成功设备数据 + + int inserted = persistAndUpdate(successList); if (inserted <= 0) { throw new RuntimeException("成功采集设备写入失败,回滚事务"); diff --git a/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/WebSocketService.java b/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/WebSocketService.java new file mode 100644 index 00000000..08540ba0 --- /dev/null +++ b/ALOps_sys_backend/alops-system/src/main/java/com/alops/system/service/impl/WebSocketService.java @@ -0,0 +1,63 @@ +package com.alops.system.service.impl; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketSession; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +//负责在线用户 +@Service +public class WebSocketService { + + private final Map onlineUsers = new ConcurrentHashMap<>(); + + @Autowired + private ObjectMapper objectMapper; + + // 添加在线用户 + public void addOnlineUser(Long userId, WebSocketSession session) { + onlineUsers.put(userId, session); + } + + // 移除在线用户 + public void removeOnlineUser(Long userId) { + onlineUsers.remove(userId); + } + + // 获取在线用户 + public Set getOnlineUserIds() { + return onlineUsers.keySet(); + } + + // 给指定用户发送通知 + public void sendAlertMessage(Long userId, Long messageId, String title, String content) { + WebSocketSession session = onlineUsers.get(userId); + try { + if (session != null && session.isOpen()) { + Map messageMap = new HashMap<>(); + messageMap.put("messageId", messageId); + messageMap.put("title", title); + messageMap.put("content", content); + messageMap.put("timestamp", new Date()); + + String jsonMessage = objectMapper.writeValueAsString(messageMap); + session.sendMessage(new TextMessage(jsonMessage)); + + LoggerFactory.getLogger(WebSocketService.class) + .info("成功向用户 [{}] 发送通知: {}", userId, jsonMessage); + } + } catch (Exception e) { + LoggerFactory.getLogger(WebSocketService.class) + .error("发送通知失败: messageId=" + messageId, e); + } + } +} + diff --git a/ALOps_sys_backend/alops-system/src/main/resources/mapper/system/AlertMessageMapper.xml b/ALOps_sys_backend/alops-system/src/main/resources/mapper/system/AlertMessageMapper.xml index f5483bd9..1b51f2e1 100644 --- a/ALOps_sys_backend/alops-system/src/main/resources/mapper/system/AlertMessageMapper.xml +++ b/ALOps_sys_backend/alops-system/src/main/resources/mapper/system/AlertMessageMapper.xml @@ -20,6 +20,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + + + + + + + + + + + + + + + @@ -452,6 +454,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" create_by, create_date, equ_number, + floor, status, equ_image, @@ -475,6 +478,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{createBy}, #{createDate}, #{equNumber}, + #{floor}, COALESCE(#{status,jdbcType=INTEGER}, 0), #{equImage}, COALESCE(#{failureFrequency,jdbcType=BIGINT}, 0), @@ -503,6 +507,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" supplier_id = #{supplierId}, equ_image = #{equImage}, equ_number = #{equNumber}, + floor = #{floor}, where id = #{id}