Merge pull request #43 from lawrencehj/master
添加报警响应、发布和SSE推送功能
| | |
| | | 11. 支持公网部署, 支持wvp与zlm分开部署 |
| | | 12. 支持播放h265, g.711格式的流 |
| | | 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)) |
| | | 14. 报警信息处理,支持向前端推送报警信息 |
| | | |
| | | # 待实现: |
| | | 上级级联 |
| | |
| | | /**
|
| | | * 报警级别, 1为一级警情, 2为二级警情, 3为三级警情, 4为四级 警情-
|
| | | */
|
| | | private String alarmPriorit;
|
| | | private String alarmPriority;
|
| | |
|
| | | /**
|
| | | * 报警方式 , 1为电话报警, 2为设备报警, 3为短信报警, 4为 GPS报警, 5为视频报警, 6为设备故障报警,
|
| | |
| | | this.deviceId = deviceId;
|
| | | }
|
| | |
|
| | | public String getAlarmPriorit() {
|
| | | return alarmPriorit;
|
| | | public String getAlarmPriority() {
|
| | | return alarmPriority;
|
| | | }
|
| | |
|
| | | public void setAlarmPriorit(String alarmPriorit) {
|
| | | this.alarmPriorit = alarmPriorit;
|
| | | public void setAlarmPriority(String alarmPriority) {
|
| | | this.alarmPriority = alarmPriority;
|
| | | }
|
| | |
|
| | | public String getAlarmMethod() {
|
| | |
| | | import org.springframework.context.ApplicationEventPublisher;
|
| | | import org.springframework.stereotype.Component;
|
| | |
|
| | | import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
|
| | | import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEvent;
|
| | | import com.genersoft.iot.vmp.gb28181.event.offline.OfflineEvent;
|
| | | import com.genersoft.iot.vmp.gb28181.event.online.OnlineEvent;
|
| | |
|
| | |
| | | outEvent.setFrom(from);
|
| | | applicationEventPublisher.publishEvent(outEvent);
|
| | | }
|
| | | |
| | | /**
|
| | | * 设备报警事件
|
| | | * @param deviceAlarm
|
| | | */
|
| | | public void deviceAlarmEventPublish(DeviceAlarm deviceAlarm) {
|
| | | AlarmEvent alarmEvent = new AlarmEvent(this);
|
| | | alarmEvent.setAlarmInfo(deviceAlarm);
|
| | | applicationEventPublisher.publishEvent(alarmEvent);
|
| | | }
|
| | | }
|
New file |
| | |
| | | package com.genersoft.iot.vmp.gb28181.event.alarm; |
| | | |
| | | import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; |
| | | import org.springframework.context.ApplicationEvent; |
| | | |
| | | /** |
| | | * @description: 报警事件 |
| | | * @author: lawrencehj |
| | | * @data: 2021-01-20 |
| | | */ |
| | | |
| | | public class AlarmEvent extends ApplicationEvent { |
| | | public AlarmEvent(Object source) { |
| | | super(source); |
| | | } |
| | | |
| | | private DeviceAlarm deviceAlarm; |
| | | |
| | | public DeviceAlarm getAlarmInfo() { |
| | | return deviceAlarm; |
| | | } |
| | | |
| | | public void setAlarmInfo(DeviceAlarm deviceAlarm) { |
| | | this.deviceAlarm = deviceAlarm; |
| | | } |
| | | } |
New file |
| | |
| | | package com.genersoft.iot.vmp.gb28181.event.alarm; |
| | | |
| | | import org.springframework.context.ApplicationListener; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; |
| | | import java.io.IOException; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | /** |
| | | * @description: 报警事件监听 |
| | | * @author: lawrencehj |
| | | * @data: 2021-01-20 |
| | | */ |
| | | |
| | | @Component |
| | | public class AlarmEventListener implements ApplicationListener<AlarmEvent> { |
| | | |
| | | private final static Logger logger = LoggerFactory.getLogger(AlarmEventListener.class); |
| | | |
| | | private static SseEmitter emitter = new SseEmitter(); |
| | | |
| | | public void addSseEmitters(SseEmitter sseEmitter) { |
| | | emitter = sseEmitter; |
| | | } |
| | | |
| | | @Override |
| | | public void onApplicationEvent(AlarmEvent event) { |
| | | if (logger.isDebugEnabled()) { |
| | | logger.debug("设备报警事件触发,deviceId:" + event.getAlarmInfo().getDeviceId() + ", " |
| | | + event.getAlarmInfo().getAlarmDescription()); |
| | | } |
| | | try { |
| | | String msg = "<strong>设备编码:</strong> <i>" + event.getAlarmInfo().getDeviceId() + "</i>" |
| | | + "<br><strong>报警描述:</strong> <i>" + event.getAlarmInfo().getAlarmDescription() + "</i>" |
| | | + "<br><strong>报警时间:</strong> <i>" + event.getAlarmInfo().getAlarmTime() + "</i>" |
| | | + "<br><strong>定位经度:</strong> <i>" + event.getAlarmInfo().getLongitude() + "</i>" |
| | | + "<br><strong>定位纬度:</strong> <i>" + event.getAlarmInfo().getLatitude() + "</i>"; |
| | | emitter.send(msg); |
| | | } catch (IOException e) { |
| | | if (logger.isDebugEnabled()) { |
| | | logger.debug("SSE 通道已关闭"); |
| | | } |
| | | // e.printStackTrace(); |
| | | } |
| | | } |
| | | } |
| | |
| | |
|
| | | import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
| | | import com.genersoft.iot.vmp.gb28181.bean.Device;
|
| | | import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
|
| | | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
|
| | | import com.genersoft.iot.vmp.gb28181.bean.RecordInfo;
|
| | | import com.genersoft.iot.vmp.gb28181.bean.RecordItem;
|
| | |
| | | // storager.queryChannel(deviceId)
|
| | | return;
|
| | | }
|
| | | device.setName(XmlUtil.getText(rootElement, "DeviceName"));
|
| | | device.setManufacturer(XmlUtil.getText(rootElement, "Manufacturer"));
|
| | | device.setModel(XmlUtil.getText(rootElement, "Model"));
|
| | | device.setFirmware(XmlUtil.getText(rootElement, "Firmware"));
|
| | | if (StringUtils.isEmpty(device.getStreamMode())) {
|
| | | device.setStreamMode("UDP");
|
| | |
|
| | | DeviceAlarm deviceAlarm = new DeviceAlarm();
|
| | | deviceAlarm.setDeviceId(deviceId);
|
| | | deviceAlarm.setAlarmPriority(XmlUtil.getText(rootElement, "AlarmPriority"));
|
| | | deviceAlarm.setAlarmMethod(XmlUtil.getText(rootElement, "AlarmMethod"));
|
| | | deviceAlarm.setAlarmTime(XmlUtil.getText(rootElement, "AlarmTime"));
|
| | | if (XmlUtil.getText(rootElement, "AlarmDescription") == null) {
|
| | | deviceAlarm.setAlarmDescription("");
|
| | | } else {
|
| | | deviceAlarm.setAlarmDescription(XmlUtil.getText(rootElement, "AlarmDescription"));
|
| | | }
|
| | | storager.updateDevice(device);
|
| | | if (XmlUtil.getText(rootElement, "Longitude") == null || XmlUtil.getText(rootElement, "Longitude") == "") {
|
| | | deviceAlarm.setLongitude(0.00);
|
| | | } else {
|
| | | deviceAlarm.setLongitude(Double.parseDouble(XmlUtil.getText(rootElement, "Longitude")));
|
| | | }
|
| | | if (XmlUtil.getText(rootElement, "Latitude") == null || XmlUtil.getText(rootElement, "Latitude") =="") {
|
| | | deviceAlarm.setLatitude(0.00);
|
| | | } else {
|
| | | deviceAlarm.setLatitude(Double.parseDouble(XmlUtil.getText(rootElement, "Latitude")));
|
| | | }
|
| | |
|
| | | // device.setName(XmlUtil.getText(rootElement, "DeviceName"));
|
| | | // device.setManufacturer(XmlUtil.getText(rootElement, "Manufacturer"));
|
| | | // device.setModel(XmlUtil.getText(rootElement, "Model"));
|
| | | // device.setFirmware(XmlUtil.getText(rootElement, "Firmware"));
|
| | | // if (StringUtils.isEmpty(device.getStreamMode())) {
|
| | | // device.setStreamMode("UDP");
|
| | | // }
|
| | | // storager.updateDevice(device);
|
| | | //cmder.catalogQuery(device, null);
|
| | | // 回复200 OK
|
| | | responseAck(evt);
|
| | | if (offLineDetector.isOnline(deviceId)) {
|
| | | publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
|
| | | publisher.deviceAlarmEventPublish(deviceAlarm);
|
| | | }
|
| | | } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
|
| | | // } catch (DocumentException e) {
|
| | |
| | | " WHERE 1=1 " + |
| | | " <if test=\"hasSubChannel == true\" > AND subCount >0</if>" + |
| | | " <if test=\"hasSubChannel == false\" > AND subCount=0</if>" + |
| | | " ORDER BY channelId ASC" + |
| | | " </script>"}) |
| | | List<DeviceChannel> queryChannelsByDeviceId(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online); |
| | | |
New file |
| | |
| | | package com.genersoft.iot.vmp.vmanager.SEEController; |
| | | |
| | | import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEventListener; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Controller; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; |
| | | |
| | | /** |
| | | * @description: SSE推送 |
| | | * @author: lawrencehj |
| | | * @data: 2021-01-20 |
| | | */ |
| | | |
| | | @Controller |
| | | @RequestMapping("/api") |
| | | public class SEEController { |
| | | @Autowired |
| | | AlarmEventListener alarmEventListener; |
| | | |
| | | //设置响应 |
| | | @RequestMapping("/emit") |
| | | public SseEmitter emit() { |
| | | SseEmitter sseEmitter = new SseEmitter(0L); |
| | | try { |
| | | alarmEventListener.addSseEmitters(sseEmitter); |
| | | }catch (Exception e){ |
| | | sseEmitter.completeWithError(e); |
| | | } |
| | | return sseEmitter; |
| | | } |
| | | } |
| | |
| | | <el-menu-item index="/">控制台</el-menu-item> |
| | | <el-menu-item index="/videoList">设备列表</el-menu-item> |
| | | <!-- <el-menu-item index="/videoReplay">录像回看</el-menu-item> --> |
| | | <!-- <el-menu-item index="4">级联设置</el-menu-item> --> |
| | | <el-switch v-model="alarmNotify" active-text="报警信息推送" style="display: block float: right" @change="sseControl"></el-switch> |
| | | <el-menu-item style="float: right;" @click="loginout">退出</el-menu-item> |
| | | </el-menu> |
| | | </div> |
| | |
| | | <script> |
| | | export default { |
| | | name: "UiHeader", |
| | | components: { Notification }, |
| | | data() { |
| | | return { |
| | | alarmNotify: true, |
| | | sseSource: null, |
| | | }; |
| | | }, |
| | | methods:{ |
| | | |
| | | loginout(){ |
| | | // 删除cookie,回到登录页面 |
| | | this.$cookies.remove("session"); |
| | | this.$router.push('/login'); |
| | | this.sseSource.close(); |
| | | }, |
| | | } |
| | | } |
| | | beforeunloadHandler() { |
| | | this.sseSource.close(); |
| | | }, |
| | | sseControl() { |
| | | let that = this; |
| | | if (this.alarmNotify) { |
| | | this.sseSource = new EventSource('/api/emit'); |
| | | this.sseSource.addEventListener('message', function(evt) { |
| | | that.$notify({ |
| | | title: '收到报警信息', |
| | | dangerouslyUseHTMLString: true, |
| | | message: evt.data, |
| | | type: 'warning' |
| | | }); |
| | | console.log("收到信息:" + evt.data); |
| | | }); |
| | | this.sseSource.addEventListener('open', function(e) { |
| | | console.log("SSE连接打开."); |
| | | }, false); |
| | | this.sseSource.addEventListener('error', function(e) { |
| | | if (e.target.readyState == EventSource.CLOSED) { |
| | | console.log("SSE连接关闭"); |
| | | } else { |
| | | console.log(e.target.readyState); |
| | | } |
| | | }, false); |
| | | } else { |
| | | this.sseSource.removeEventListener('open', null); |
| | | this.sseSource.removeEventListener('message', null); |
| | | this.sseSource.removeEventListener('error', null); |
| | | this.sseSource.close(); |
| | | } |
| | | } |
| | | }, |
| | | mounted() { |
| | | window.addEventListener('beforeunload', e => this.beforeunloadHandler(e)) |
| | | // window.addEventListener('unload', e => this.unloadHandler(e)) |
| | | this.sseControl(); |
| | | }, |
| | | destroyed() { |
| | | window.removeEventListener('beforeunload', e => this.beforeunloadHandler(e)) |
| | | // window.removeEventListener('unload', e => this.unloadHandler(e)) |
| | | }, |
| | | } |
| | | |
| | | </script> |
| | |
| | | import echarts from 'echarts'; |
| | | |
| | | import VueClipboard from 'vue-clipboard2' |
| | | import { Notification } from 'element-ui'; |
| | | |
| | | Vue.use(VueClipboard) |
| | | Vue.use(ElementUI); |
| | | Vue.use(VueCookies); |
| | | Vue.prototype.$axios = axios; |
| | | Vue.prototype.$notify = Notification; |
| | | |
| | | axios.defaults.baseURL = (process.env.NODE_ENV === 'development') ? process.env.BASE_API : ""; |
| | | |