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 4 import org.springframework.stereotype.Component;
5 5 import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
6 6 import java.io.IOException;
  7 +import java.util.Hashtable;
  8 +import java.util.Iterator;
  9 +import java.util.Map;
  10 +
7 11 import org.slf4j.Logger;
8 12 import org.slf4j.LoggerFactory;
9 13  
... ... @@ -18,10 +22,10 @@ public class AlarmEventListener implements ApplicationListener<AlarmEvent> {
18 22  
19 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 31 @Override
... ... @@ -30,18 +34,25 @@ public class AlarmEventListener implements ApplicationListener&lt;AlarmEvent&gt; {
30 34 logger.debug("设备报警事件触发,deviceId:" + event.getAlarmInfo().getDeviceId() + ", "
31 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 3 import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEventListener;
4 4 import org.springframework.beans.factory.annotation.Autowired;
5 5 import org.springframework.stereotype.Controller;
6 6 import org.springframework.web.bind.annotation.RequestMapping;
  7 +import org.springframework.web.bind.annotation.RequestParam;
7 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 15  
15 16 @Controller
16 17 @RequestMapping("/api")
17   -public class SEEController {
  18 +public class SseController {
18 19 @Autowired
19 20 AlarmEventListener alarmEventListener;
20 21  
21 22 //设置响应
22 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 26 try {
26   - alarmEventListener.addSseEmitters(sseEmitter);
  27 + alarmEventListener.addSseEmitters(browserId, sseEmitter);
27 28 }catch (Exception e){
28 29 sseEmitter.completeWithError(e);
29 30 }
... ...
web_src/package-lock.json
... ... @@ -99,7 +99,6 @@
99 99 "version": "3.2.1",
100 100 "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-3.2.1.tgz",
101 101 "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=",
102   - "dev": true,
103 102 "requires": {
104 103 "color-convert": "^1.9.0"
105 104 }
... ... @@ -1645,7 +1644,6 @@
1645 1644 "version": "2.4.2",
1646 1645 "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-2.4.2.tgz",
1647 1646 "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=",
1648   - "dev": true,
1649 1647 "requires": {
1650 1648 "ansi-styles": "^3.2.1",
1651 1649 "escape-string-regexp": "^1.0.5",
... ... @@ -1847,7 +1845,6 @@
1847 1845 "version": "1.9.3",
1848 1846 "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-1.9.3.tgz",
1849 1847 "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=",
1850   - "dev": true,
1851 1848 "requires": {
1852 1849 "color-name": "1.1.3"
1853 1850 }
... ... @@ -1855,8 +1852,7 @@
1855 1852 "color-name": {
1856 1853 "version": "1.1.3",
1857 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 1857 "color-string": {
1862 1858 "version": "0.3.0",
... ... @@ -3713,8 +3709,7 @@
3713 3709 "escape-string-regexp": {
3714 3710 "version": "1.0.5",
3715 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 3714 "escope": {
3720 3715 "version": "3.6.0",
... ... @@ -4150,6 +4145,11 @@
4150 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 4153 "flatten": {
4154 4154 "version": "1.0.3",
4155 4155 "resolved": "https://registry.npm.taobao.org/flatten/download/flatten-1.0.3.tgz",
... ... @@ -4403,8 +4403,7 @@
4403 4403 "has-flag": {
4404 4404 "version": "3.0.0",
4405 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 4408 "has-symbols": {
4410 4409 "version": "1.0.1",
... ... @@ -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 8467 "postcss-reduce-idents": {
8441 8468 "version": "2.4.0",
8442 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 9920 "source-map": {
9894 9921 "version": "0.6.1",
9895 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 9925 "source-map-resolve": {
9900 9926 "version": "0.5.3",
... ... @@ -10290,7 +10316,6 @@
10290 10316 "version": "5.5.0",
10291 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 10318 "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=",
10293   - "dev": true,
10294 10319 "requires": {
10295 10320 "has-flag": "^3.0.0"
10296 10321 }
... ...
web_src/package.json
... ... @@ -15,7 +15,9 @@
15 15 "core-js": "^2.6.5",
16 16 "echarts": "^4.7.0",
17 17 "element-ui": "2.10.1",
  18 + "fingerprintjs2": "^2.1.2",
18 19 "moment": "^2.29.1",
  20 + "postcss-pxtorem": "^5.1.1",
19 21 "vue": "^2.6.11",
20 22 "vue-clipboard2": "^0.3.1",
21 23 "vue-cookies": "^1.7.4",
... ...
web_src/src/components/UiHeader.vue
... ... @@ -34,7 +34,8 @@ export default {
34 34 sseControl() {
35 35 let that = this;
36 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 39 this.sseSource.addEventListener('message', function(evt) {
39 40 that.$notify({
40 41 title: '收到报警信息',
... ...
web_src/src/main.js
... ... @@ -8,10 +8,28 @@ import axios from &#39;axios&#39;;
8 8 import VueCookies from 'vue-cookies';
9 9 import echarts from 'echarts';
10 10  
11   -import VueClipboard from 'vue-clipboard2'
  11 +import VueClipboard from 'vue-clipboard2';
12 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 33 Vue.use(ElementUI);
16 34 Vue.use(VueCookies);
17 35 Vue.prototype.$axios = axios;
... ...