添加报警订阅白名单功能,允许用户设置接收的报警类型

This commit is contained in:
lin 2026-04-07 09:56:33 +08:00
parent f5f86c40a0
commit d1de343167
6 changed files with 14 additions and 126 deletions

View File

@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.conf;
import com.genersoft.iot.vmp.service.bean.AlarmType;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.annotation.Order;
@ -240,5 +241,10 @@ public class UserSetting {
*/
private boolean snapByPullStream = false;
/**
* 报警订阅白名单设置后只有在此列表中的上级平台才会接收报警订阅消息默认不设置则不限制
*/
private List<AlarmType> allowedAlarmType = new ArrayList<>();
}

View File

@ -104,7 +104,7 @@ public class JwtUtils implements InitializingBean {
}
String jwkFile = userSetting.getJwkFile();
if (jwkFile == null || jwkFile.trim().isEmpty()) {
log.error("[API AUTH] JWK文件路径未配置使用默认配置路径./config/jwk.json");
log.warn("[API AUTH] JWK文件路径未配置使用默认配置路径./config/jwk.json");
jwkFile = "config" + File.separator + "jwk.json"; // 默认外部路径
return createAndPersistDefaultRsaKey(jwkFile);
}

View File

@ -1,42 +0,0 @@
package com.genersoft.iot.vmp.gb28181.controller;
import com.genersoft.iot.vmp.gb28181.session.SseSessionManager;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* SSE 推送.
*
* @author lawrencehj
* @author <a href="mailto:xiaoQQya@126.com">xiaoQQya</a>
* @since 2021/01/20
*/
@Tag(name = "SSE 推送")
@RestController
@RequestMapping("/api")
public class SseController {
@Resource
private SseSessionManager sseSessionManager;
/**
* SSE 推送.
*
* @param browserId 浏览器ID
*/
@GetMapping("/emit")
public SseEmitter emit(HttpServletResponse response, @RequestParam String browserId) throws IOException, InterruptedException {
// response.setContentType("text/event-stream");
// response.setCharacterEncoding("utf-8");
return sseSessionManager.conect(browserId);
}
}

View File

@ -1,83 +0,0 @@
package com.genersoft.iot.vmp.gb28181.session;
import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.gb28181.event.alarm.DeviceAlarmEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
@Slf4j
public class SseSessionManager {
private static final Map<String, SseEmitter> sseSessionMap = new ConcurrentHashMap<>();
@Autowired
private DynamicTask dynamicTask;
public SseEmitter conect(String browserId) {
SseEmitter sseEmitter = new SseEmitter(0L);
sseEmitter.onError((err) -> {
log.error("[SSE推送] 连接错误, 浏览器 ID: {}, {}", browserId, err.getMessage());
sseSessionMap.remove(browserId);
sseEmitter.completeWithError(err);
});
// sseEmitter.onTimeout(() -> {
// log.info("[SSE推送] 连接超时, 浏览器 ID: {}", browserId);
// sseSessionMap.remove(browserId);
// sseEmitter.complete();
// dynamicTask.stop(key);
// });
sseEmitter.onCompletion(() -> {
log.info("[SSE推送] 连接结束, 浏览器 ID: {}", browserId);
sseSessionMap.remove(browserId);
});
sseSessionMap.put(browserId, sseEmitter);
log.info("[SSE推送] 连接已建立, 浏览器 ID: {}, 当前在线数: {}", browserId, sseSessionMap.size());
return sseEmitter;
}
@Scheduled(fixedRate = 1000) //每1秒执行一次
public void execute() {
if (sseSessionMap.isEmpty()) {
return;
}
sendForAll("keepalive", "alive");
}
@Async
@org.springframework.context.event.EventListener
public void onApplicationEvent(DeviceAlarmEvent event) {
event.getDeviceAlarmList().forEach(
notify -> sendForAll("message", notify)
);
}
public void sendForAll(String event, Object data) {
for (String browserId : sseSessionMap.keySet()) {
SseEmitter sseEmitter = sseSessionMap.get(browserId);
if (sseEmitter == null) {
continue;
}
;
try {
sseEmitter.send(SseEmitter.event().name(event).data(data));
} catch (Exception e) {
log.error("[SSE推送] 发送失败: {}", e.getMessage());
sseSessionMap.remove(browserId);
sseEmitter.completeWithError(e);
}
}
}
}

View File

@ -77,6 +77,10 @@ public class AlarmServiceImpl implements IAlarmService {
log.info("收到设备报警事件,数量:{}", event.getDeviceAlarmList().size());
for (DeviceAlarmNotify notify : event.getDeviceAlarmList()) {
Alarm alarm = Alarm.buildFromDeviceAlarmNotify(notify);
if (!userSetting.getAllowedAlarmType().isEmpty() && !userSetting.getAllowedAlarmType().contains(alarm.getAlarmType())) {
log.debug("报警类型不在允许的范围内alarmType{}alarmId{}", alarm.getAlarmType(), alarm.getId());
continue;
}
String key = notify.getDeviceId() + notify.getChannelId();
DeviceChannel deviceChannel = channelCache.get(key, k -> deviceChannelService.getOneForSource(notify.getDeviceId(), notify.getChannelId()));
if (deviceChannel == null) {

View File

@ -270,6 +270,9 @@ user-settings:
alarm-catch-size: 10000
# 是否使用拉流的方式获取快照默认false避免流量大规模消耗开启后则使用拉流的方式获取快照
snap-by-pull-stream: true
# 是否使用拉流的方式获取快照默认false避免流量大规模消耗开启后则使用拉流的方式获取快照
allowed-alarm-type:
- IntrusionDetection
# 关闭在线文档(生产环境建议关闭)
springdoc: