Commit 2c47c8c86b0a685e92b0a605ae6f96901cf10555

Authored by 648540858
Committed by GitHub
2 parents 1b44ba33 8da6906e

Merge pull request #42 from lawrencehj/wvp-28181-2.0

增加报警事件处理功能等
README.md
@@ -33,7 +33,8 @@ https://gitee.com/18010473990/wvp-GB28181.git @@ -33,7 +33,8 @@ https://gitee.com/18010473990/wvp-GB28181.git
33 16. 支持直接输出RTSP、RTMP、HTTP-FLV、Websocket-FLV、HLS多种协议流地址 33 16. 支持直接输出RTSP、RTMP、HTTP-FLV、Websocket-FLV、HLS多种协议流地址
34 17. 支持国标网络校时 34 17. 支持国标网络校时
35 18. 支持公网部署, 支持wvp与zlm分开部署 35 18. 支持公网部署, 支持wvp与zlm分开部署
36 -19. 支持播放h265, g.711格式的流(需要将closeWaitRTPInfo设为false). 36 +19. 支持播放h265, g.711格式的流(需要将closeWaitRTPInfo设为false)
  37 +20. 报警信息处理,支持向前端推送报警信息
37 38
38 # 2.0 支持特性 39 # 2.0 支持特性
39 - [ ] 国标通道向上级联 40 - [ ] 国标通道向上级联
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceAlarm.java
@@ -11,7 +11,7 @@ public class DeviceAlarm { @@ -11,7 +11,7 @@ public class DeviceAlarm {
11 /** 11 /**
12 * 报警级别, 1为一级警情, 2为二级警情, 3为三级警情, 4为四级 警情- 12 * 报警级别, 1为一级警情, 2为二级警情, 3为三级警情, 4为四级 警情-
13 */ 13 */
14 - private String alarmPriorit; 14 + private String alarmPriority;
15 15
16 /** 16 /**
17 * 报警方式 , 1为电话报警, 2为设备报警, 3为短信报警, 4为 GPS报警, 5为视频报警, 6为设备故障报警, 17 * 报警方式 , 1为电话报警, 2为设备报警, 3为短信报警, 4为 GPS报警, 5为视频报警, 6为设备故障报警,
@@ -53,12 +53,12 @@ public class DeviceAlarm { @@ -53,12 +53,12 @@ public class DeviceAlarm {
53 this.deviceId = deviceId; 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 public String getAlarmMethod() { 64 public String getAlarmMethod() {
src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java
@@ -6,6 +6,8 @@ import org.springframework.beans.factory.annotation.Autowired; @@ -6,6 +6,8 @@ import org.springframework.beans.factory.annotation.Autowired;
6 import org.springframework.context.ApplicationEventPublisher; 6 import org.springframework.context.ApplicationEventPublisher;
7 import org.springframework.stereotype.Component; 7 import org.springframework.stereotype.Component;
8 8
  9 +import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
  10 +import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEvent;
9 import com.genersoft.iot.vmp.gb28181.event.offline.OfflineEvent; 11 import com.genersoft.iot.vmp.gb28181.event.offline.OfflineEvent;
10 import com.genersoft.iot.vmp.gb28181.event.online.OnlineEvent; 12 import com.genersoft.iot.vmp.gb28181.event.online.OnlineEvent;
11 13
@@ -52,5 +54,15 @@ public class EventPublisher { @@ -52,5 +54,15 @@ public class EventPublisher {
52 PlatformNotRegisterEvent platformNotRegisterEvent = new PlatformNotRegisterEvent(this); 54 PlatformNotRegisterEvent platformNotRegisterEvent = new PlatformNotRegisterEvent(this);
53 platformNotRegisterEvent.setPlatformGbID(platformGbId); 55 platformNotRegisterEvent.setPlatformGbID(platformGbId);
54 applicationEventPublisher.publishEvent(platformNotRegisterEvent); 56 applicationEventPublisher.publishEvent(platformNotRegisterEvent);
55 - } 57 + }
  58 +
  59 + /**
  60 + * 设备报警事件
  61 + * @param deviceAlarm
  62 + */
  63 + public void deviceAlarmEventPublish(DeviceAlarm deviceAlarm) {
  64 + AlarmEvent alarmEvent = new AlarmEvent(this);
  65 + alarmEvent.setAlarmInfo(deviceAlarm);
  66 + applicationEventPublisher.publishEvent(alarmEvent);
  67 + }
56 } 68 }
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
@@ -174,7 +174,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { @@ -174,7 +174,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
174 SipUri uri = (SipUri) address.getURI(); 174 SipUri uri = (SipUri) address.getURI();
175 String platformId = uri.getUser(); 175 String platformId = uri.getUser();
176 // if (deviceListElement == null) { // 存在DeviceList则为响应 catalog, 不存在DeviceList则为查询请求 176 // if (deviceListElement == null) { // 存在DeviceList则为响应 catalog, 不存在DeviceList则为查询请求
177 - if (name == "Query") { // 区分是Response——查询响应,还是Query——查询请求 177 + if (name.equalsIgnoreCase("Query")) { // 区分是Response——查询响应,还是Query——查询请求
178 // TODO 后续将代码拆分 178 // TODO 后续将代码拆分
179 ParentPlatform parentPlatform = storager.queryParentPlatById(platformId); 179 ParentPlatform parentPlatform = storager.queryParentPlatById(platformId);
180 if (parentPlatform == null) { 180 if (parentPlatform == null) {
@@ -324,19 +324,41 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { @@ -324,19 +324,41 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
324 // storager.queryChannel(deviceId) 324 // storager.queryChannel(deviceId)
325 return; 325 return;
326 } 326 }
327 - device.setName(XmlUtil.getText(rootElement, "DeviceName"));  
328 - device.setManufacturer(XmlUtil.getText(rootElement, "Manufacturer"));  
329 - device.setModel(XmlUtil.getText(rootElement, "Model"));  
330 - device.setFirmware(XmlUtil.getText(rootElement, "Firmware"));  
331 - if (StringUtils.isEmpty(device.getStreamMode())) {  
332 - device.setStreamMode("UDP"); 327 +
  328 + DeviceAlarm deviceAlarm = new DeviceAlarm();
  329 + deviceAlarm.setDeviceId(deviceId);
  330 + deviceAlarm.setAlarmPriority(XmlUtil.getText(rootElement, "AlarmPriority"));
  331 + deviceAlarm.setAlarmMethod(XmlUtil.getText(rootElement, "AlarmMethod"));
  332 + deviceAlarm.setAlarmTime(XmlUtil.getText(rootElement, "AlarmTime"));
  333 + if (XmlUtil.getText(rootElement, "AlarmDescription") == null) {
  334 + deviceAlarm.setAlarmDescription("");
  335 + } else {
  336 + deviceAlarm.setAlarmDescription(XmlUtil.getText(rootElement, "AlarmDescription"));
333 } 337 }
334 - storager.updateDevice(device); 338 + if (XmlUtil.getText(rootElement, "Longitude") == null || XmlUtil.getText(rootElement, "Longitude") == "") {
  339 + deviceAlarm.setLongitude(0.00);
  340 + } else {
  341 + deviceAlarm.setLongitude(Double.parseDouble(XmlUtil.getText(rootElement, "Longitude")));
  342 + }
  343 + if (XmlUtil.getText(rootElement, "Latitude") == null || XmlUtil.getText(rootElement, "Latitude") =="") {
  344 + deviceAlarm.setLatitude(0.00);
  345 + } else {
  346 + deviceAlarm.setLatitude(Double.parseDouble(XmlUtil.getText(rootElement, "Latitude")));
  347 + }
  348 +
  349 + // device.setName(XmlUtil.getText(rootElement, "DeviceName"));
  350 + // device.setManufacturer(XmlUtil.getText(rootElement, "Manufacturer"));
  351 + // device.setModel(XmlUtil.getText(rootElement, "Model"));
  352 + // device.setFirmware(XmlUtil.getText(rootElement, "Firmware"));
  353 + // if (StringUtils.isEmpty(device.getStreamMode())) {
  354 + // device.setStreamMode("UDP");
  355 + // }
  356 + // storager.updateDevice(device);
335 //cmder.catalogQuery(device, null); 357 //cmder.catalogQuery(device, null);
336 // 回复200 OK 358 // 回复200 OK
337 responseAck(evt); 359 responseAck(evt);
338 if (offLineDetector.isOnline(deviceId)) { 360 if (offLineDetector.isOnline(deviceId)) {
339 - publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE); 361 + publisher.deviceAlarmEventPublish(deviceAlarm);
340 } 362 }
341 } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { 363 } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
342 // } catch (DocumentException e) { 364 // } catch (DocumentException e) {
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/ParentPlatformList.vue
@@ -137,7 +137,7 @@ export default { @@ -137,7 +137,7 @@ export default {
137 }); 137 });
138 }, 138 },
139 chooseChannel: function(platform) { 139 chooseChannel: function(platform) {
140 - this.$refs.chooseChannelDialog.openDialog(platform.deviceGBId, ()=>{ 140 + this.$refs.chooseChannelDialog.openDialog(platform.serverGBId, ()=>{
141 this.initData() 141 this.initData()
142 }) 142 })
143 }, 143 },
web_src/src/components/UiHeader.vue
@@ -3,7 +3,8 @@ @@ -3,7 +3,8 @@
3 <el-menu router :default-active="this.$route.path" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b" mode="horizontal"> 3 <el-menu router :default-active="this.$route.path" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b" mode="horizontal">
4 <el-menu-item index="/">控制台</el-menu-item> 4 <el-menu-item index="/">控制台</el-menu-item>
5 <el-menu-item index="/videoList">设备列表</el-menu-item> 5 <el-menu-item index="/videoList">设备列表</el-menu-item>
6 - <el-menu-item index="/parentPlatformList/15/1">国标级联</el-menu-item> 6 + <el-menu-item index="/parentPlatformList/15/1">国标级联</el-menu-item>
  7 + <el-switch v-model="alarmNotify" active-text="报警信息推送" style="display: block float: right" @change="sseControl"></el-switch>
7 <el-menu-item style="float: right;" @click="loginout">退出</el-menu-item> 8 <el-menu-item style="float: right;" @click="loginout">退出</el-menu-item>
8 </el-menu> 9 </el-menu>
9 </div> 10 </div>
@@ -12,14 +13,63 @@ @@ -12,14 +13,63 @@
12 <script> 13 <script>
13 export default { 14 export default {
14 name: "UiHeader", 15 name: "UiHeader",
  16 + components: { Notification },
  17 + data() {
  18 + return {
  19 + alarmNotify: true,
  20 + sseSource: null,
  21 + };
  22 + },
15 methods:{ 23 methods:{
16 -  
17 loginout(){ 24 loginout(){
18 // 删除cookie,回到登录页面 25 // 删除cookie,回到登录页面
19 this.$cookies.remove("session"); 26 this.$cookies.remove("session");
20 this.$router.push('/login'); 27 this.$router.push('/login');
  28 + this.sseSource.close();
  29 + },
  30 + beforeunloadHandler() {
  31 + this.sseSource.close();
21 }, 32 },
22 - }  
23 -} 33 + sseControl() {
  34 + let that = this;
  35 + if (this.alarmNotify) {
  36 + this.sseSource = new EventSource('/api/emit');
  37 + this.sseSource.addEventListener('message', function(evt) {
  38 + that.$notify({
  39 + title: '收到报警信息',
  40 + dangerouslyUseHTMLString: true,
  41 + message: evt.data,
  42 + type: 'warning'
  43 + });
  44 + console.log("收到信息:" + evt.data);
  45 + });
  46 + this.sseSource.addEventListener('open', function(e) {
  47 + console.log("SSE连接打开.");
  48 + }, false);
  49 + this.sseSource.addEventListener('error', function(e) {
  50 + if (e.target.readyState == EventSource.CLOSED) {
  51 + console.log("SSE连接关闭");
  52 + } else {
  53 + console.log(e.target.readyState);
  54 + }
  55 + }, false);
  56 + } else {
  57 + this.sseSource.removeEventListener('open', null);
  58 + this.sseSource.removeEventListener('message', null);
  59 + this.sseSource.removeEventListener('error', null);
  60 + this.sseSource.close();
  61 + }
  62 + }
  63 + },
  64 + mounted() {
  65 + window.addEventListener('beforeunload', e => this.beforeunloadHandler(e))
  66 + // window.addEventListener('unload', e => this.unloadHandler(e))
  67 + this.sseControl();
  68 + },
  69 + destroyed() {
  70 + window.removeEventListener('beforeunload', e => this.beforeunloadHandler(e))
  71 + // window.removeEventListener('unload', e => this.unloadHandler(e))
  72 + },
  73 + }
24 74
25 </script> 75 </script>
web_src/src/main.js
@@ -9,10 +9,13 @@ import VueCookies from &#39;vue-cookies&#39;; @@ -9,10 +9,13 @@ import VueCookies from &#39;vue-cookies&#39;;
9 import echarts from 'echarts'; 9 import echarts from 'echarts';
10 10
11 import VueClipboard from 'vue-clipboard2' 11 import VueClipboard from 'vue-clipboard2'
  12 +import { Notification } from 'element-ui';
  13 +
12 Vue.use(VueClipboard) 14 Vue.use(VueClipboard)
13 Vue.use(ElementUI); 15 Vue.use(ElementUI);
14 Vue.use(VueCookies); 16 Vue.use(VueCookies);
15 Vue.prototype.$axios = axios; 17 Vue.prototype.$axios = axios;
  18 +Vue.prototype.$notify = Notification;
16 19
17 axios.defaults.baseURL = (process.env.NODE_ENV === 'development') ? process.env.BASE_API : ""; 20 axios.defaults.baseURL = (process.env.NODE_ENV === 'development') ? process.env.BASE_API : "";
18 21