Commit 4b9549dfbf55d8af415efe609623e9d19dd6e6d4

Authored by Lawrence
1 parent 0456d6e3

添加浏览器ID,确保SSE可同时推送到不同的前端

src/main/java/com/genersoft/iot/vmp/gb28181/event/alarm/AlarmEventListener.java
@@ -4,6 +4,10 @@ import org.springframework.context.ApplicationListener; @@ -4,6 +4,10 @@ import org.springframework.context.ApplicationListener;
4 import org.springframework.stereotype.Component; 4 import org.springframework.stereotype.Component;
5 import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; 5 import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
6 import java.io.IOException; 6 import java.io.IOException;
  7 +import java.util.Hashtable;
  8 +import java.util.Iterator;
  9 +import java.util.Map;
  10 +
7 import org.slf4j.Logger; 11 import org.slf4j.Logger;
8 import org.slf4j.LoggerFactory; 12 import org.slf4j.LoggerFactory;
9 13
@@ -18,10 +22,10 @@ public class AlarmEventListener implements ApplicationListener<AlarmEvent> { @@ -18,10 +22,10 @@ public class AlarmEventListener implements ApplicationListener<AlarmEvent> {
18 22
19 private final static Logger logger = LoggerFactory.getLogger(AlarmEventListener.class); 23 private final static Logger logger = LoggerFactory.getLogger(AlarmEventListener.class);
20 24
21 - private static SseEmitter emitter = new SseEmitter(); 25 + private static Map<String, SseEmitter> sseEmitters = new Hashtable<>();
22 26
23 - public void addSseEmitters(SseEmitter sseEmitter) {  
24 - emitter = sseEmitter; 27 + public void addSseEmitters(String browserId, SseEmitter sseEmitter) {
  28 + sseEmitters.put(browserId, sseEmitter);
25 } 29 }
26 30
27 @Override 31 @Override
@@ -30,18 +34,25 @@ public class AlarmEventListener implements ApplicationListener&lt;AlarmEvent&gt; { @@ -30,18 +34,25 @@ public class AlarmEventListener implements ApplicationListener&lt;AlarmEvent&gt; {
30 logger.debug("设备报警事件触发,deviceId:" + event.getAlarmInfo().getDeviceId() + ", " 34 logger.debug("设备报警事件触发,deviceId:" + event.getAlarmInfo().getDeviceId() + ", "
31 + event.getAlarmInfo().getAlarmDescription()); 35 + event.getAlarmInfo().getAlarmDescription());
32 } 36 }
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 通道已关闭"); 37 + String msg = "<strong>设备编码:</strong> <i>" + event.getAlarmInfo().getDeviceId() + "</i>"
  38 + + "<br><strong>报警描述:</strong> <i>" + event.getAlarmInfo().getAlarmDescription() + "</i>"
  39 + + "<br><strong>报警时间:</strong> <i>" + event.getAlarmInfo().getAlarmTime() + "</i>"
  40 + + "<br><strong>报警位置:</strong> <i>" + event.getAlarmInfo().getLongitude() + "</i>"
  41 + + ", <i>" + event.getAlarmInfo().getLatitude() + "</i>";
  42 +
  43 + for (Iterator<Map.Entry<String, SseEmitter>> it = sseEmitters.entrySet().iterator(); it.hasNext();) {
  44 + Map.Entry<String, SseEmitter> emitter = it.next();
  45 + logger.info("推送到SSE连接,浏览器ID: " + emitter.getKey());
  46 + try {
  47 + emitter.getValue().send(msg);
  48 + } catch (IOException | IllegalStateException e) {
  49 + if (logger.isDebugEnabled()) {
  50 + logger.debug("SSE连接已关闭");
  51 + }
  52 + // 移除已关闭的连接
  53 + it.remove();
  54 + // e.printStackTrace();
43 } 55 }
44 - // e.printStackTrace();  
45 } 56 }
46 } 57 }
47 } 58 }
src/main/java/com/genersoft/iot/vmp/vmanager/SEEController/SEEController.java renamed to src/main/java/com/genersoft/iot/vmp/vmanager/SseController/SseController.java
1 -package com.genersoft.iot.vmp.vmanager.SEEController; 1 +package com.genersoft.iot.vmp.vmanager.SseController;
2 2
3 import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEventListener; 3 import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEventListener;
4 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.beans.factory.annotation.Autowired;
5 import org.springframework.stereotype.Controller; 5 import org.springframework.stereotype.Controller;
6 import org.springframework.web.bind.annotation.RequestMapping; 6 import org.springframework.web.bind.annotation.RequestMapping;
  7 +import org.springframework.web.bind.annotation.RequestParam;
7 import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; 8 import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
8 9
9 /** 10 /**
@@ -14,16 +15,16 @@ import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; @@ -14,16 +15,16 @@ import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
14 15
15 @Controller 16 @Controller
16 @RequestMapping("/api") 17 @RequestMapping("/api")
17 -public class SEEController { 18 +public class SseController {
18 @Autowired 19 @Autowired
19 AlarmEventListener alarmEventListener; 20 AlarmEventListener alarmEventListener;
20 21
21 //设置响应 22 //设置响应
22 @RequestMapping("/emit") 23 @RequestMapping("/emit")
23 - public SseEmitter emit() {  
24 - SseEmitter sseEmitter = new SseEmitter(0L); 24 + public SseEmitter emit(@RequestParam String browserId) {
  25 + final SseEmitter sseEmitter = new SseEmitter(0L);
25 try { 26 try {
26 - alarmEventListener.addSseEmitters(sseEmitter); 27 + alarmEventListener.addSseEmitters(browserId, sseEmitter);
27 }catch (Exception e){ 28 }catch (Exception e){
28 sseEmitter.completeWithError(e); 29 sseEmitter.completeWithError(e);
29 } 30 }
web_src/package-lock.json
@@ -99,7 +99,6 @@ @@ -99,7 +99,6 @@
99 "version": "3.2.1", 99 "version": "3.2.1",
100 "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-3.2.1.tgz", 100 "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-3.2.1.tgz",
101 "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", 101 "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=",
102 - "dev": true,  
103 "requires": { 102 "requires": {
104 "color-convert": "^1.9.0" 103 "color-convert": "^1.9.0"
105 } 104 }
@@ -1645,7 +1644,6 @@ @@ -1645,7 +1644,6 @@
1645 "version": "2.4.2", 1644 "version": "2.4.2",
1646 "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-2.4.2.tgz", 1645 "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-2.4.2.tgz",
1647 "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", 1646 "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=",
1648 - "dev": true,  
1649 "requires": { 1647 "requires": {
1650 "ansi-styles": "^3.2.1", 1648 "ansi-styles": "^3.2.1",
1651 "escape-string-regexp": "^1.0.5", 1649 "escape-string-regexp": "^1.0.5",
@@ -1847,7 +1845,6 @@ @@ -1847,7 +1845,6 @@
1847 "version": "1.9.3", 1845 "version": "1.9.3",
1848 "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-1.9.3.tgz", 1846 "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-1.9.3.tgz",
1849 "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=", 1847 "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=",
1850 - "dev": true,  
1851 "requires": { 1848 "requires": {
1852 "color-name": "1.1.3" 1849 "color-name": "1.1.3"
1853 } 1850 }
@@ -1855,8 +1852,7 @@ @@ -1855,8 +1852,7 @@
1855 "color-name": { 1852 "color-name": {
1856 "version": "1.1.3", 1853 "version": "1.1.3",
1857 "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.3.tgz", 1854 "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.3.tgz",
1858 - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",  
1859 - "dev": true 1855 + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
1860 }, 1856 },
1861 "color-string": { 1857 "color-string": {
1862 "version": "0.3.0", 1858 "version": "0.3.0",
@@ -3713,8 +3709,7 @@ @@ -3713,8 +3709,7 @@
3713 "escape-string-regexp": { 3709 "escape-string-regexp": {
3714 "version": "1.0.5", 3710 "version": "1.0.5",
3715 "resolved": "https://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz", 3711 "resolved": "https://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz",
3716 - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",  
3717 - "dev": true 3712 + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
3718 }, 3713 },
3719 "escope": { 3714 "escope": {
3720 "version": "3.6.0", 3715 "version": "3.6.0",
@@ -4150,6 +4145,11 @@ @@ -4150,6 +4145,11 @@
4150 "locate-path": "^2.0.0" 4145 "locate-path": "^2.0.0"
4151 } 4146 }
4152 }, 4147 },
  4148 + "fingerprintjs2": {
  4149 + "version": "2.1.2",
  4150 + "resolved": "https://registry.npmjs.org/fingerprintjs2/-/fingerprintjs2-2.1.2.tgz",
  4151 + "integrity": "sha512-ZPsLgjziFRbUb5tXWpEMtWp4XFnzSah8SiNfl3aoURDZ+2zi2tuIOYUULqDBV+Cb6paN+raWT+Q2qpOaCbX/Yw=="
  4152 + },
4153 "flatten": { 4153 "flatten": {
4154 "version": "1.0.3", 4154 "version": "1.0.3",
4155 "resolved": "https://registry.npm.taobao.org/flatten/download/flatten-1.0.3.tgz", 4155 "resolved": "https://registry.npm.taobao.org/flatten/download/flatten-1.0.3.tgz",
@@ -4403,8 +4403,7 @@ @@ -4403,8 +4403,7 @@
4403 "has-flag": { 4403 "has-flag": {
4404 "version": "3.0.0", 4404 "version": "3.0.0",
4405 "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-3.0.0.tgz", 4405 "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-3.0.0.tgz",
4406 - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",  
4407 - "dev": true 4406 + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
4408 }, 4407 },
4409 "has-symbols": { 4408 "has-symbols": {
4410 "version": "1.0.1", 4409 "version": "1.0.1",
@@ -8437,6 +8436,34 @@ @@ -8437,6 +8436,34 @@
8437 } 8436 }
8438 } 8437 }
8439 }, 8438 },
  8439 + "postcss-pxtorem": {
  8440 + "version": "5.1.1",
  8441 + "resolved": "https://registry.npmjs.org/postcss-pxtorem/-/postcss-pxtorem-5.1.1.tgz",
  8442 + "integrity": "sha512-uvgIujL/pn0GbZ+rczESD2orHsbXrrCqi+q9wJO8PCk3ZGCoVVtu5hZTbtk+tbZHZP5UkTfCvqOrTZs9Ncqfsg==",
  8443 + "requires": {
  8444 + "postcss": "^7.0.27"
  8445 + },
  8446 + "dependencies": {
  8447 + "postcss": {
  8448 + "version": "7.0.35",
  8449 + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
  8450 + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
  8451 + "requires": {
  8452 + "chalk": "^2.4.2",
  8453 + "source-map": "^0.6.1",
  8454 + "supports-color": "^6.1.0"
  8455 + }
  8456 + },
  8457 + "supports-color": {
  8458 + "version": "6.1.0",
  8459 + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
  8460 + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
  8461 + "requires": {
  8462 + "has-flag": "^3.0.0"
  8463 + }
  8464 + }
  8465 + }
  8466 + },
8440 "postcss-reduce-idents": { 8467 "postcss-reduce-idents": {
8441 "version": "2.4.0", 8468 "version": "2.4.0",
8442 "resolved": "https://registry.npm.taobao.org/postcss-reduce-idents/download/postcss-reduce-idents-2.4.0.tgz?cache=0&sync_timestamp=1599672339373&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-reduce-idents%2Fdownload%2Fpostcss-reduce-idents-2.4.0.tgz", 8469 "resolved": "https://registry.npm.taobao.org/postcss-reduce-idents/download/postcss-reduce-idents-2.4.0.tgz?cache=0&sync_timestamp=1599672339373&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss-reduce-idents%2Fdownload%2Fpostcss-reduce-idents-2.4.0.tgz",
@@ -9893,8 +9920,7 @@ @@ -9893,8 +9920,7 @@
9893 "source-map": { 9920 "source-map": {
9894 "version": "0.6.1", 9921 "version": "0.6.1",
9895 "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz", 9922 "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz",
9896 - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=",  
9897 - "dev": true 9923 + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM="
9898 }, 9924 },
9899 "source-map-resolve": { 9925 "source-map-resolve": {
9900 "version": "0.5.3", 9926 "version": "0.5.3",
@@ -10290,7 +10316,6 @@ @@ -10290,7 +10316,6 @@
10290 "version": "5.5.0", 10316 "version": "5.5.0",
10291 "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-5.5.0.tgz?cache=0&sync_timestamp=1598611719015&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-5.5.0.tgz", 10317 "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-5.5.0.tgz?cache=0&sync_timestamp=1598611719015&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-5.5.0.tgz",
10292 "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", 10318 "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=",
10293 - "dev": true,  
10294 "requires": { 10319 "requires": {
10295 "has-flag": "^3.0.0" 10320 "has-flag": "^3.0.0"
10296 } 10321 }
web_src/package.json
@@ -15,7 +15,9 @@ @@ -15,7 +15,9 @@
15 "core-js": "^2.6.5", 15 "core-js": "^2.6.5",
16 "echarts": "^4.7.0", 16 "echarts": "^4.7.0",
17 "element-ui": "2.10.1", 17 "element-ui": "2.10.1",
  18 + "fingerprintjs2": "^2.1.2",
18 "moment": "^2.29.1", 19 "moment": "^2.29.1",
  20 + "postcss-pxtorem": "^5.1.1",
19 "vue": "^2.6.11", 21 "vue": "^2.6.11",
20 "vue-clipboard2": "^0.3.1", 22 "vue-clipboard2": "^0.3.1",
21 "vue-cookies": "^1.7.4", 23 "vue-cookies": "^1.7.4",
web_src/src/components/UiHeader.vue
@@ -34,7 +34,8 @@ export default { @@ -34,7 +34,8 @@ export default {
34 sseControl() { 34 sseControl() {
35 let that = this; 35 let that = this;
36 if (this.alarmNotify) { 36 if (this.alarmNotify) {
37 - this.sseSource = new EventSource('/api/emit'); 37 + console.log("申请SSE推送API调用,浏览器ID: " + this.$browserId);
  38 + this.sseSource = new EventSource('/api/emit?browserId=' + this.$browserId);
38 this.sseSource.addEventListener('message', function(evt) { 39 this.sseSource.addEventListener('message', function(evt) {
39 that.$notify({ 40 that.$notify({
40 title: '收到报警信息', 41 title: '收到报警信息',
web_src/src/main.js
@@ -8,10 +8,28 @@ import axios from &#39;axios&#39;; @@ -8,10 +8,28 @@ import axios from &#39;axios&#39;;
8 import VueCookies from 'vue-cookies'; 8 import VueCookies from 'vue-cookies';
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'; 12 import { Notification } from 'element-ui';
  13 +import Fingerprint2 from 'fingerprintjs2';
13 14
14 -Vue.use(VueClipboard) 15 +// 生成唯一ID
  16 +Fingerprint2.get(function(components) {
  17 + const values = components.map(function(component,index) {
  18 + if (index === 0) { //把微信浏览器里UA的wifi或4G等网络替换成空,不然切换网络会ID不一样
  19 + return component.value.replace(/\bNetType\/\w+\b/, '');
  20 + }
  21 + return component.value;
  22 + })
  23 + //console.log(values) //使用的浏览器信息npm
  24 + // 生成最终id
  25 + let port = window.location.port;
  26 + console.log(port);
  27 + const fingerPrint = Fingerprint2.x64hash128(values.join(port), 31)
  28 + Vue.prototype.$browserId = fingerPrint;
  29 + console.log("唯一标识码:" + fingerPrint);
  30 +});
  31 +
  32 +Vue.use(VueClipboard);
15 Vue.use(ElementUI); 33 Vue.use(ElementUI);
16 Vue.use(VueCookies); 34 Vue.use(VueCookies);
17 Vue.prototype.$axios = axios; 35 Vue.prototype.$axios = axios;