Commit abbfef2aef1694b2b2f2b775b216f320ad645482

Authored by Lawrence
1 parent 2b850ba7

添加报警响应、发布和SSE推送功能

README.md
... ... @@ -41,6 +41,7 @@ https://gitee.com/18010473990/wvp-GB28181.git
41 41 11. 支持公网部署, 支持wvp与zlm分开部署
42 42 12. 支持播放h265, g.711格式的流
43 43 13. 支持固定流地址和自动点播,同时支持未点播时直接播放流地址,代码自动发起点播. ( [查看WIKI](https://github.com/648540858/wvp-GB28181-pro/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%E5%9B%BA%E5%AE%9A%E6%92%AD%E6%94%BE%E5%9C%B0%E5%9D%80%E4%B8%8E%E8%87%AA%E5%8A%A8%E7%82%B9%E6%92%AD))
  44 +14. 报警信息处理,支持向前端推送报警信息
44 45  
45 46 # 待实现:
46 47 上级级联
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceAlarm.java
... ... @@ -11,7 +11,7 @@ public class DeviceAlarm {
11 11 /**
12 12 * 报警级别, 1为一级警情, 2为二级警情, 3为三级警情, 4为四级 警情-
13 13 */
14   - private String alarmPriorit;
  14 + private String alarmPriority;
15 15  
16 16 /**
17 17 * 报警方式 , 1为电话报警, 2为设备报警, 3为短信报警, 4为 GPS报警, 5为视频报警, 6为设备故障报警,
... ... @@ -53,12 +53,12 @@ public class DeviceAlarm {
53 53 this.deviceId = deviceId;
54 54 }
55 55  
56   - public String getAlarmPriorit() {
57   - return alarmPriorit;
  56 + public String getAlarmPriority() {
  57 + return alarmPriority;
58 58 }
59 59  
60   - public void setAlarmPriorit(String alarmPriorit) {
61   - this.alarmPriorit = alarmPriorit;
  60 + public void setAlarmPriority(String alarmPriority) {
  61 + this.alarmPriority = alarmPriority;
62 62 }
63 63  
64 64 public String getAlarmMethod() {
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java
... ... @@ -4,6 +4,8 @@ import org.springframework.beans.factory.annotation.Autowired;
4 4 import org.springframework.context.ApplicationEventPublisher;
5 5 import org.springframework.stereotype.Component;
6 6  
  7 +import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
  8 +import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEvent;
7 9 import com.genersoft.iot.vmp.gb28181.event.offline.OfflineEvent;
8 10 import com.genersoft.iot.vmp.gb28181.event.online.OnlineEvent;
9 11  
... ... @@ -31,4 +33,14 @@ public class EventPublisher {
31 33 outEvent.setFrom(from);
32 34 applicationEventPublisher.publishEvent(outEvent);
33 35 }
  36 +
  37 + /**
  38 + * 设备报警事件
  39 + * @param deviceAlarm
  40 + */
  41 + public void deviceAlarmEventPublish(DeviceAlarm deviceAlarm) {
  42 + AlarmEvent alarmEvent = new AlarmEvent(this);
  43 + alarmEvent.setAlarmInfo(deviceAlarm);
  44 + applicationEventPublisher.publishEvent(alarmEvent);
  45 + }
34 46 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/event/alarm/AlarmEvent.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.event.alarm;
  2 +
  3 +import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
  4 +import org.springframework.context.ApplicationEvent;
  5 +
  6 +/**
  7 + * @description: 报警事件
  8 + * @author: lawrencehj
  9 + * @data: 2021-01-20
  10 + */
  11 +
  12 +public class AlarmEvent extends ApplicationEvent {
  13 + public AlarmEvent(Object source) {
  14 + super(source);
  15 + }
  16 +
  17 + private DeviceAlarm deviceAlarm;
  18 +
  19 + public DeviceAlarm getAlarmInfo() {
  20 + return deviceAlarm;
  21 + }
  22 +
  23 + public void setAlarmInfo(DeviceAlarm deviceAlarm) {
  24 + this.deviceAlarm = deviceAlarm;
  25 + }
  26 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/event/alarm/AlarmEventListener.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.event.alarm;
  2 +
  3 +import org.springframework.context.ApplicationListener;
  4 +import org.springframework.stereotype.Component;
  5 +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
  6 +import java.io.IOException;
  7 +import org.slf4j.Logger;
  8 +import org.slf4j.LoggerFactory;
  9 +
  10 +/**
  11 + * @description: 报警事件监听
  12 + * @author: lawrencehj
  13 + * @data: 2021-01-20
  14 + */
  15 +
  16 +@Component
  17 +public class AlarmEventListener implements ApplicationListener<AlarmEvent> {
  18 +
  19 + private final static Logger logger = LoggerFactory.getLogger(AlarmEventListener.class);
  20 +
  21 + private static SseEmitter emitter = new SseEmitter();
  22 +
  23 + public void addSseEmitters(SseEmitter sseEmitter) {
  24 + emitter = sseEmitter;
  25 + }
  26 +
  27 + @Override
  28 + public void onApplicationEvent(AlarmEvent event) {
  29 + if (logger.isDebugEnabled()) {
  30 + logger.debug("设备报警事件触发,deviceId:" + event.getAlarmInfo().getDeviceId() + ", "
  31 + + event.getAlarmInfo().getAlarmDescription());
  32 + }
  33 + try {
  34 + String msg = "<strong>设备编码:</strong> <i>" + event.getAlarmInfo().getDeviceId() + "</i>"
  35 + + "<br><strong>报警描述:</strong> <i>" + event.getAlarmInfo().getAlarmDescription() + "</i>"
  36 + + "<br><strong>报警时间:</strong> <i>" + event.getAlarmInfo().getAlarmTime() + "</i>"
  37 + + "<br><strong>定位经度:</strong> <i>" + event.getAlarmInfo().getLongitude() + "</i>"
  38 + + "<br><strong>定位纬度:</strong> <i>" + event.getAlarmInfo().getLatitude() + "</i>";
  39 + emitter.send(msg);
  40 + } catch (IOException e) {
  41 + if (logger.isDebugEnabled()) {
  42 + logger.debug("SSE 通道已关闭");
  43 + }
  44 + // e.printStackTrace();
  45 + }
  46 + }
  47 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
... ... @@ -21,6 +21,7 @@ import org.springframework.beans.factory.annotation.Autowired;
21 21  
22 22 import com.genersoft.iot.vmp.common.VideoManagerConstants;
23 23 import com.genersoft.iot.vmp.gb28181.bean.Device;
  24 +import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
24 25 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
25 26 import com.genersoft.iot.vmp.gb28181.bean.RecordInfo;
26 27 import com.genersoft.iot.vmp.gb28181.bean.RecordItem;
... ... @@ -289,19 +290,41 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
289 290 // storager.queryChannel(deviceId)
290 291 return;
291 292 }
292   - device.setName(XmlUtil.getText(rootElement, "DeviceName"));
293   - device.setManufacturer(XmlUtil.getText(rootElement, "Manufacturer"));
294   - device.setModel(XmlUtil.getText(rootElement, "Model"));
295   - device.setFirmware(XmlUtil.getText(rootElement, "Firmware"));
296   - if (StringUtils.isEmpty(device.getStreamMode())) {
297   - device.setStreamMode("UDP");
  293 +
  294 + DeviceAlarm deviceAlarm = new DeviceAlarm();
  295 + deviceAlarm.setDeviceId(deviceId);
  296 + deviceAlarm.setAlarmPriority(XmlUtil.getText(rootElement, "AlarmPriority"));
  297 + deviceAlarm.setAlarmMethod(XmlUtil.getText(rootElement, "AlarmMethod"));
  298 + deviceAlarm.setAlarmTime(XmlUtil.getText(rootElement, "AlarmTime"));
  299 + if (XmlUtil.getText(rootElement, "AlarmDescription") == null) {
  300 + deviceAlarm.setAlarmDescription("");
  301 + } else {
  302 + deviceAlarm.setAlarmDescription(XmlUtil.getText(rootElement, "AlarmDescription"));
298 303 }
299   - storager.updateDevice(device);
  304 + if (XmlUtil.getText(rootElement, "Longitude") == null || XmlUtil.getText(rootElement, "Longitude") == "") {
  305 + deviceAlarm.setLongitude(0.00);
  306 + } else {
  307 + deviceAlarm.setLongitude(Double.parseDouble(XmlUtil.getText(rootElement, "Longitude")));
  308 + }
  309 + if (XmlUtil.getText(rootElement, "Latitude") == null || XmlUtil.getText(rootElement, "Latitude") =="") {
  310 + deviceAlarm.setLatitude(0.00);
  311 + } else {
  312 + deviceAlarm.setLatitude(Double.parseDouble(XmlUtil.getText(rootElement, "Latitude")));
  313 + }
  314 +
  315 + // device.setName(XmlUtil.getText(rootElement, "DeviceName"));
  316 + // device.setManufacturer(XmlUtil.getText(rootElement, "Manufacturer"));
  317 + // device.setModel(XmlUtil.getText(rootElement, "Model"));
  318 + // device.setFirmware(XmlUtil.getText(rootElement, "Firmware"));
  319 + // if (StringUtils.isEmpty(device.getStreamMode())) {
  320 + // device.setStreamMode("UDP");
  321 + // }
  322 + // storager.updateDevice(device);
300 323 //cmder.catalogQuery(device, null);
301 324 // 回复200 OK
302 325 responseAck(evt);
303 326 if (offLineDetector.isOnline(deviceId)) {
304   - publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
  327 + publisher.deviceAlarmEventPublish(deviceAlarm);
305 328 }
306 329 } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
307 330 // } catch (DocumentException e) {
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
... ... @@ -59,6 +59,7 @@ public interface DeviceChannelMapper {
59 59 " WHERE 1=1 " +
60 60 " <if test=\"hasSubChannel == true\" > AND subCount >0</if>" +
61 61 " <if test=\"hasSubChannel == false\" > AND subCount=0</if>" +
  62 + " ORDER BY channelId ASC" +
62 63 " </script>"})
63 64 List<DeviceChannel> queryChannelsByDeviceId(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online);
64 65  
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/SEEController/SEEController.java 0 → 100644
  1 +package com.genersoft.iot.vmp.vmanager.SEEController;
  2 +
  3 +import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEventListener;
  4 +import org.springframework.beans.factory.annotation.Autowired;
  5 +import org.springframework.stereotype.Controller;
  6 +import org.springframework.web.bind.annotation.RequestMapping;
  7 +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
  8 +
  9 +/**
  10 + * @description: SSE推送
  11 + * @author: lawrencehj
  12 + * @data: 2021-01-20
  13 + */
  14 +
  15 +@Controller
  16 +@RequestMapping("/api")
  17 +public class SEEController {
  18 + @Autowired
  19 + AlarmEventListener alarmEventListener;
  20 +
  21 + //设置响应
  22 + @RequestMapping("/emit")
  23 + public SseEmitter emit() {
  24 + SseEmitter sseEmitter = new SseEmitter(0L);
  25 + try {
  26 + alarmEventListener.addSseEmitters(sseEmitter);
  27 + }catch (Exception e){
  28 + sseEmitter.completeWithError(e);
  29 + }
  30 + return sseEmitter;
  31 + }
  32 +}
... ...
web_src/src/components/UiHeader.vue
... ... @@ -4,7 +4,7 @@
4 4 <el-menu-item index="/">控制台</el-menu-item>
5 5 <el-menu-item index="/videoList">设备列表</el-menu-item>
6 6 <!-- <el-menu-item index="/videoReplay">录像回看</el-menu-item> -->
7   - <!-- <el-menu-item index="4">级联设置</el-menu-item> -->
  7 + <el-switch v-model="alarmNotify" active-text="报警信息推送" style="display: block float: right" @change="sseControl"></el-switch>
8 8 <el-menu-item style="float: right;" @click="loginout">退出</el-menu-item>
9 9 </el-menu>
10 10 </div>
... ... @@ -13,14 +13,64 @@
13 13 <script>
14 14 export default {
15 15 name: "UiHeader",
  16 + components: { Notification },
  17 + data() {
  18 + return {
  19 + alarmNotify: true,
  20 + sseSource: null,
  21 + };
  22 + },
16 23 methods:{
17 24  
18 25 loginout(){
19 26 // 删除cookie,回到登录页面
20 27 this.$cookies.remove("session");
21 28 this.$router.push('/login');
  29 + this.sseSource.close();
22 30 },
23   - }
24   -}
  31 + beforeunloadHandler() {
  32 + this.sseSource.close();
  33 + },
  34 + sseControl() {
  35 + let that = this;
  36 + if (this.alarmNotify) {
  37 + this.sseSource = new EventSource('/api/emit');
  38 + this.sseSource.addEventListener('message', function(evt) {
  39 + that.$notify({
  40 + title: '收到报警信息',
  41 + dangerouslyUseHTMLString: true,
  42 + message: evt.data,
  43 + type: 'warning'
  44 + });
  45 + console.log("收到信息:" + evt.data);
  46 + });
  47 + this.sseSource.addEventListener('open', function(e) {
  48 + console.log("SSE连接打开.");
  49 + }, false);
  50 + this.sseSource.addEventListener('error', function(e) {
  51 + if (e.target.readyState == EventSource.CLOSED) {
  52 + console.log("SSE连接关闭");
  53 + } else {
  54 + console.log(e.target.readyState);
  55 + }
  56 + }, false);
  57 + } else {
  58 + this.sseSource.removeEventListener('open', null);
  59 + this.sseSource.removeEventListener('message', null);
  60 + this.sseSource.removeEventListener('error', null);
  61 + this.sseSource.close();
  62 + }
  63 + }
  64 + },
  65 + mounted() {
  66 + window.addEventListener('beforeunload', e => this.beforeunloadHandler(e))
  67 + // window.addEventListener('unload', e => this.unloadHandler(e))
  68 + this.sseControl();
  69 + },
  70 + destroyed() {
  71 + window.removeEventListener('beforeunload', e => this.beforeunloadHandler(e))
  72 + // window.removeEventListener('unload', e => this.unloadHandler(e))
  73 + },
  74 + }
25 75  
26 76 </script>
... ...
web_src/src/main.js
... ... @@ -9,10 +9,13 @@ import VueCookies from &#39;vue-cookies&#39;;
9 9 import echarts from 'echarts';
10 10  
11 11 import VueClipboard from 'vue-clipboard2'
  12 +import { Notification } from 'element-ui';
  13 +
12 14 Vue.use(VueClipboard)
13 15 Vue.use(ElementUI);
14 16 Vue.use(VueCookies);
15 17 Vue.prototype.$axios = axios;
  18 +Vue.prototype.$notify = Notification;
16 19  
17 20 axios.defaults.baseURL = (process.env.NODE_ENV === 'development') ? process.env.BASE_API : "";
18 21  
... ...