修改缓存
This commit is contained in:
parent
3f53fe82ec
commit
dc5c2e1396
6
pom.xml
6
pom.xml
|
|
@ -117,6 +117,12 @@
|
||||||
<artifactId>caffeine</artifactId>
|
<artifactId>caffeine</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- WebSocket -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Spring Integration MQTT -->
|
<!-- Spring Integration MQTT -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.integration</groupId>
|
<groupId>org.springframework.integration</groupId>
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@ public class DeviceCacheConfig {
|
||||||
public static final String PAYLOAD_CACHE = "payload";
|
public static final String PAYLOAD_CACHE = "payload";
|
||||||
public static final String DOCK_AIRCRAFT_CACHE = "dockAircraft";
|
public static final String DOCK_AIRCRAFT_CACHE = "dockAircraft";
|
||||||
public static final String AIRCRAFT_PAYLOAD_CACHE = "aircraftPayload";
|
public static final String AIRCRAFT_PAYLOAD_CACHE = "aircraftPayload";
|
||||||
|
public static final String THINGSBOARD_ATTRIBUTES_CACHE = "thingsboardAttributes";
|
||||||
|
public static final String THINGSBOARD_TELEMETRY_CACHE = "thingsboardTelemetry";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 配置缓存管理器
|
* 配置缓存管理器
|
||||||
|
|
@ -68,6 +70,12 @@ public class DeviceCacheConfig {
|
||||||
cacheConfigurations.put(DOCK_AIRCRAFT_CACHE, defaultConfig.entryTtl(Duration.ofMinutes(15)));
|
cacheConfigurations.put(DOCK_AIRCRAFT_CACHE, defaultConfig.entryTtl(Duration.ofMinutes(15)));
|
||||||
cacheConfigurations.put(AIRCRAFT_PAYLOAD_CACHE, defaultConfig.entryTtl(Duration.ofMinutes(15)));
|
cacheConfigurations.put(AIRCRAFT_PAYLOAD_CACHE, defaultConfig.entryTtl(Duration.ofMinutes(15)));
|
||||||
|
|
||||||
|
// ThingsBoard 设备属性:90秒(属性数据,变化较少)
|
||||||
|
cacheConfigurations.put(THINGSBOARD_ATTRIBUTES_CACHE, defaultConfig.entryTtl(Duration.ofSeconds(90)));
|
||||||
|
|
||||||
|
// ThingsBoard 设备遥测:15秒(遥测数据,实时性要求高)
|
||||||
|
cacheConfigurations.put(THINGSBOARD_TELEMETRY_CACHE, defaultConfig.entryTtl(Duration.ofSeconds(15)));
|
||||||
|
|
||||||
return RedisCacheManager.builder(connectionFactory)
|
return RedisCacheManager.builder(connectionFactory)
|
||||||
.cacheDefaults(defaultConfig)
|
.cacheDefaults(defaultConfig)
|
||||||
.withInitialCacheConfigurations(cacheConfigurations)
|
.withInitialCacheConfigurations(cacheConfigurations)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.ruoyi.device.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class WebSocketConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ServerEndpointExporter serverEndpointExporter() {
|
||||||
|
return new ServerEndpointExporter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -54,212 +54,17 @@ public class StaticsController extends BaseController
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public R<StatisticsVO> getStatistics()
|
public R<StatisticsVO> getStatistics()
|
||||||
{
|
{
|
||||||
StatisticsVO vo = new StatisticsVO();
|
return R.ok(buildDjiStatisticsVO());
|
||||||
|
|
||||||
// 获取所有机场
|
|
||||||
List<DockDTO> docks = dockService.selectDockList(new DockDTO());
|
|
||||||
vo.setDockCount(docks != null ? docks.size() : 0);
|
|
||||||
|
|
||||||
// 批量获取机场详情 - 优化:从N次查询减少到1次批量查询
|
|
||||||
Map<Long, DockDetailDTO> dockDetailsMap = null;
|
|
||||||
if (docks != null && !docks.isEmpty()) {
|
|
||||||
List<Long> dockIds = docks.stream()
|
|
||||||
.map(DockDTO::getDockId)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
dockDetailsMap = bufferDeviceService.getDockDetailsByIds(dockIds);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 统计各状态机场数量
|
|
||||||
int idleCount = 0;
|
|
||||||
int workingCount = 0;
|
|
||||||
int debuggingCount = 0;
|
|
||||||
int offlineCount = 0;
|
|
||||||
|
|
||||||
if (docks != null && dockDetailsMap != null) {
|
|
||||||
for (DockDTO dock : docks) {
|
|
||||||
DockDetailDTO dockDetail = dockDetailsMap.get(dock.getDockId());
|
|
||||||
if (dockDetail != null && dockDetail.getDockStatus() != null) {
|
|
||||||
String status = dockDetail.getDockStatus();
|
|
||||||
if (DockStatusEnum.IDLE.getCode().equals(status)) {
|
|
||||||
idleCount++;
|
|
||||||
} else if (DockStatusEnum.WORKING.getCode().equals(status)) {
|
|
||||||
workingCount++;
|
|
||||||
} else if (DockStatusEnum.Debugging.getCode().equals(status)) {
|
|
||||||
debuggingCount++;
|
|
||||||
} else {
|
|
||||||
offlineCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vo.setIdleDockCount(idleCount);
|
|
||||||
vo.setWorkingDockCount(workingCount);
|
|
||||||
vo.setDebuggingDockCount(debuggingCount);
|
|
||||||
vo.setOfflineDockCount(offlineCount);
|
|
||||||
|
|
||||||
// 获取所有无人机
|
|
||||||
List<AircraftDTO> aircrafts = aircraftService.selectAircraftList(new AircraftDTO());
|
|
||||||
vo.setAircraftCount(aircrafts != null ? aircrafts.size() : 0);
|
|
||||||
|
|
||||||
// 批量获取无人机详情 - 优化:从N次查询减少到1次批量查询
|
|
||||||
Map<Long, AircraftDetailDTO> aircraftDetailsMap = null;
|
|
||||||
if (aircrafts != null && !aircrafts.isEmpty()) {
|
|
||||||
List<Long> aircraftIds = aircrafts.stream()
|
|
||||||
.map(AircraftDTO::getAircraftId)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
aircraftDetailsMap = bufferDeviceService.getAircraftDetailsByIds(aircraftIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 统计各状态无人机数量
|
|
||||||
int powerOnInCabinCount = 0;
|
|
||||||
int powerOffInCabinCount = 0;
|
|
||||||
int inMissionCount = 0;
|
|
||||||
int debuggingAircraftCount = 0;
|
|
||||||
int offlineAircraftCount = 0;
|
|
||||||
|
|
||||||
if (aircrafts != null && aircraftDetailsMap != null) {
|
|
||||||
for (AircraftDTO aircraft : aircrafts) {
|
|
||||||
AircraftDetailDTO aircraftDetail = aircraftDetailsMap.get(aircraft.getAircraftId());
|
|
||||||
if (aircraftDetail != null && aircraftDetail.getAircraftStatus() != null) {
|
|
||||||
String status = aircraftDetail.getAircraftStatus();
|
|
||||||
if (AircraftStatusEnum.POWER_ON_IN_CABIN.getCode().equals(status)) {
|
|
||||||
powerOnInCabinCount++;
|
|
||||||
} else if (AircraftStatusEnum.POWER_OFF_IN_CABIN.getCode().equals(status)) {
|
|
||||||
powerOffInCabinCount++;
|
|
||||||
} else if (AircraftStatusEnum.IN_MISSION.getCode().equals(status)) {
|
|
||||||
inMissionCount++;
|
|
||||||
} else if (AircraftStatusEnum.DEBUGGING.getCode().equals(status)) {
|
|
||||||
debuggingAircraftCount++;
|
|
||||||
} else if (AircraftStatusEnum.OFFLINE.getCode().equals(status)) {
|
|
||||||
offlineAircraftCount++;
|
|
||||||
} else {
|
|
||||||
offlineAircraftCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vo.setPowerOnInCabinCount(powerOnInCabinCount);
|
|
||||||
vo.setPowerOffInCabinCount(powerOffInCabinCount);
|
|
||||||
vo.setInMissionCount(inMissionCount);
|
|
||||||
vo.setDebuggingAircraftCount(debuggingAircraftCount);
|
|
||||||
vo.setOfflineAircraftCount(offlineAircraftCount);
|
|
||||||
|
|
||||||
// 获取所有挂载
|
|
||||||
List<PayloadDTO> payloads = payloadService.selectPayloadList(new PayloadDTO());
|
|
||||||
vo.setPayloadCount(payloads != null ? payloads.size() : 0);
|
|
||||||
|
|
||||||
// 统计离线挂载数量(暂时设置为0,因为挂载状态需要从实时数据获取)
|
|
||||||
vo.setOfflinePayloadCount(0);
|
|
||||||
|
|
||||||
return R.ok(vo);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/dji")
|
@GetMapping("/dji")
|
||||||
public R<StatisticsVO> getDjiStatistics()
|
public R<StatisticsVO> getDjiStatistics()
|
||||||
{
|
{
|
||||||
StatisticsVO vo = new StatisticsVO();
|
return R.ok(buildDjiStatisticsVO());
|
||||||
|
|
||||||
// 获取所有机场
|
|
||||||
List<DockDTO> docks = dockService.selectDockList(new DockDTO());
|
|
||||||
vo.setDockCount(docks != null ? docks.size() : 0);
|
|
||||||
|
|
||||||
// 批量获取机场详情 - 优化:从N次查询减少到1次批量查询
|
|
||||||
Map<Long, DockDetailDTO> dockDetailsMap = null;
|
|
||||||
if (docks != null && !docks.isEmpty()) {
|
|
||||||
List<Long> dockIds = docks.stream()
|
|
||||||
.map(DockDTO::getDockId)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
dockDetailsMap = bufferDeviceService.getDockDetailsByIds(dockIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 统计各状态机场数量
|
|
||||||
int idleCount = 0;
|
|
||||||
int workingCount = 0;
|
|
||||||
int debuggingCount = 0;
|
|
||||||
int offlineCount = 0;
|
|
||||||
|
|
||||||
if (docks != null && dockDetailsMap != null) {
|
|
||||||
for (DockDTO dock : docks) {
|
|
||||||
DockDetailDTO dockDetail = dockDetailsMap.get(dock.getDockId());
|
|
||||||
if (dockDetail != null && dockDetail.getDockStatus() != null) {
|
|
||||||
String status = dockDetail.getDockStatus();
|
|
||||||
if (DockStatusEnum.IDLE.getCode().equals(status)) {
|
|
||||||
idleCount++;
|
|
||||||
} else if (DockStatusEnum.WORKING.getCode().equals(status)) {
|
|
||||||
workingCount++;
|
|
||||||
} else if (DockStatusEnum.Debugging.getCode().equals(status)) {
|
|
||||||
debuggingCount++;
|
|
||||||
} else {
|
|
||||||
offlineCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vo.setIdleDockCount(idleCount);
|
|
||||||
vo.setWorkingDockCount(workingCount);
|
|
||||||
vo.setDebuggingDockCount(debuggingCount);
|
|
||||||
vo.setOfflineDockCount(offlineCount);
|
|
||||||
|
|
||||||
// 获取所有无人机
|
|
||||||
List<AircraftDTO> aircrafts = aircraftService.selectAircraftList(new AircraftDTO());
|
|
||||||
vo.setAircraftCount(aircrafts != null ? aircrafts.size() : 0);
|
|
||||||
|
|
||||||
// 批量获取无人机详情 - 优化:从N次查询减少到1次批量查询
|
|
||||||
Map<Long, AircraftDetailDTO> aircraftDetailsMap = null;
|
|
||||||
if (aircrafts != null && !aircrafts.isEmpty()) {
|
|
||||||
List<Long> aircraftIds = aircrafts.stream()
|
|
||||||
.map(AircraftDTO::getAircraftId)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
aircraftDetailsMap = bufferDeviceService.getAircraftDetailsByIds(aircraftIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 统计各状态无人机数量
|
|
||||||
int powerOnInCabinCount = 0;
|
|
||||||
int powerOffInCabinCount = 0;
|
|
||||||
int inMissionCount = 0;
|
|
||||||
int debuggingAircraftCount = 0;
|
|
||||||
int offlineAircraftCount = 0;
|
|
||||||
|
|
||||||
if (aircrafts != null && aircraftDetailsMap != null) {
|
|
||||||
for (AircraftDTO aircraft : aircrafts) {
|
|
||||||
AircraftDetailDTO aircraftDetail = aircraftDetailsMap.get(aircraft.getAircraftId());
|
|
||||||
if (aircraftDetail != null && aircraftDetail.getAircraftStatus() != null) {
|
|
||||||
String status = aircraftDetail.getAircraftStatus();
|
|
||||||
if (AircraftStatusEnum.POWER_ON_IN_CABIN.getCode().equals(status)) {
|
|
||||||
powerOnInCabinCount++;
|
|
||||||
} else if (AircraftStatusEnum.POWER_OFF_IN_CABIN.getCode().equals(status)) {
|
|
||||||
powerOffInCabinCount++;
|
|
||||||
} else if (AircraftStatusEnum.IN_MISSION.getCode().equals(status)) {
|
|
||||||
inMissionCount++;
|
|
||||||
} else if (AircraftStatusEnum.DEBUGGING.getCode().equals(status)) {
|
|
||||||
debuggingAircraftCount++;
|
|
||||||
} else if (AircraftStatusEnum.OFFLINE.getCode().equals(status)) {
|
|
||||||
offlineAircraftCount++;
|
|
||||||
} else {
|
|
||||||
offlineAircraftCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vo.setPowerOnInCabinCount(powerOnInCabinCount);
|
|
||||||
vo.setPowerOffInCabinCount(powerOffInCabinCount);
|
|
||||||
vo.setInMissionCount(inMissionCount);
|
|
||||||
vo.setDebuggingAircraftCount(debuggingAircraftCount);
|
|
||||||
vo.setOfflineAircraftCount(offlineAircraftCount);
|
|
||||||
|
|
||||||
// 获取所有挂载
|
|
||||||
List<PayloadDTO> payloads = payloadService.selectPayloadList(new PayloadDTO());
|
|
||||||
vo.setPayloadCount(payloads != null ? payloads.size() : 0);
|
|
||||||
|
|
||||||
// 统计离线挂载数量(暂时设置为0,因为挂载状态需要从实时数据获取)
|
|
||||||
vo.setOfflinePayloadCount(0);
|
|
||||||
|
|
||||||
return R.ok(vo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -289,4 +94,107 @@ public class StaticsController extends BaseController
|
||||||
|
|
||||||
return R.ok(vo);
|
return R.ok(vo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private StatisticsVO buildDjiStatisticsVO (){
|
||||||
|
StatisticsVO vo = new StatisticsVO();
|
||||||
|
|
||||||
|
// 获取所有机场
|
||||||
|
List<DockDTO> docks = dockService.selectDockList(new DockDTO());
|
||||||
|
vo.setDockCount(docks != null ? docks.size() : 0);
|
||||||
|
|
||||||
|
// 批量获取机场详情 - 优化:从N次查询减少到1次批量查询
|
||||||
|
Map<Long, DockDetailDTO> dockDetailsMap = null;
|
||||||
|
if (docks != null && !docks.isEmpty()) {
|
||||||
|
List<Long> dockIds = docks.stream()
|
||||||
|
.map(DockDTO::getDockId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
dockDetailsMap = bufferDeviceService.getDockDetailsByIds(dockIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统计各状态机场数量
|
||||||
|
int idleCount = 0;
|
||||||
|
int workingCount = 0;
|
||||||
|
int debuggingCount = 0;
|
||||||
|
int offlineCount = 0;
|
||||||
|
|
||||||
|
if (docks != null && dockDetailsMap != null) {
|
||||||
|
for (DockDTO dock : docks) {
|
||||||
|
DockDetailDTO dockDetail = dockDetailsMap.get(dock.getDockId());
|
||||||
|
if (dockDetail != null && dockDetail.getDockStatus() != null) {
|
||||||
|
String status = dockDetail.getDockStatus();
|
||||||
|
if (DockStatusEnum.IDLE.getCode().equals(status)) {
|
||||||
|
idleCount++;
|
||||||
|
} else if (DockStatusEnum.WORKING.getCode().equals(status)) {
|
||||||
|
workingCount++;
|
||||||
|
} else if (DockStatusEnum.Debugging.getCode().equals(status)) {
|
||||||
|
debuggingCount++;
|
||||||
|
} else {
|
||||||
|
offlineCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vo.setIdleDockCount(idleCount);
|
||||||
|
vo.setWorkingDockCount(workingCount);
|
||||||
|
vo.setDebuggingDockCount(debuggingCount);
|
||||||
|
vo.setOfflineDockCount(offlineCount);
|
||||||
|
|
||||||
|
// 获取所有无人机
|
||||||
|
List<AircraftDTO> aircrafts = aircraftService.selectAircraftList(new AircraftDTO());
|
||||||
|
vo.setAircraftCount(aircrafts != null ? aircrafts.size() : 0);
|
||||||
|
|
||||||
|
// 批量获取无人机详情 - 优化:从N次查询减少到1次批量查询
|
||||||
|
Map<Long, AircraftDetailDTO> aircraftDetailsMap = null;
|
||||||
|
if (aircrafts != null && !aircrafts.isEmpty()) {
|
||||||
|
List<Long> aircraftIds = aircrafts.stream()
|
||||||
|
.map(AircraftDTO::getAircraftId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
aircraftDetailsMap = bufferDeviceService.getAircraftDetailsByIds(aircraftIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统计各状态无人机数量
|
||||||
|
int powerOnInCabinCount = 0;
|
||||||
|
int powerOffInCabinCount = 0;
|
||||||
|
int inMissionCount = 0;
|
||||||
|
int debuggingAircraftCount = 0;
|
||||||
|
int offlineAircraftCount = 0;
|
||||||
|
|
||||||
|
if (aircrafts != null && aircraftDetailsMap != null) {
|
||||||
|
for (AircraftDTO aircraft : aircrafts) {
|
||||||
|
AircraftDetailDTO aircraftDetail = aircraftDetailsMap.get(aircraft.getAircraftId());
|
||||||
|
if (aircraftDetail != null && aircraftDetail.getAircraftStatus() != null) {
|
||||||
|
String status = aircraftDetail.getAircraftStatus();
|
||||||
|
if (AircraftStatusEnum.POWER_ON_IN_CABIN.getCode().equals(status)) {
|
||||||
|
powerOnInCabinCount++;
|
||||||
|
} else if (AircraftStatusEnum.POWER_OFF_IN_CABIN.getCode().equals(status)) {
|
||||||
|
powerOffInCabinCount++;
|
||||||
|
} else if (AircraftStatusEnum.IN_MISSION.getCode().equals(status)) {
|
||||||
|
inMissionCount++;
|
||||||
|
} else if (AircraftStatusEnum.DEBUGGING.getCode().equals(status)) {
|
||||||
|
debuggingAircraftCount++;
|
||||||
|
} else if (AircraftStatusEnum.OFFLINE.getCode().equals(status)) {
|
||||||
|
offlineAircraftCount++;
|
||||||
|
} else {
|
||||||
|
offlineAircraftCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vo.setPowerOnInCabinCount(powerOnInCabinCount);
|
||||||
|
vo.setPowerOffInCabinCount(powerOffInCabinCount);
|
||||||
|
vo.setInMissionCount(inMissionCount);
|
||||||
|
vo.setDebuggingAircraftCount(debuggingAircraftCount);
|
||||||
|
vo.setOfflineAircraftCount(offlineAircraftCount);
|
||||||
|
|
||||||
|
// 获取所有挂载
|
||||||
|
List<PayloadDTO> payloads = payloadService.selectPayloadList(new PayloadDTO());
|
||||||
|
vo.setPayloadCount(payloads != null ? payloads.size() : 0);
|
||||||
|
|
||||||
|
// 统计离线挂载数量(暂时设置为0,因为挂载状态需要从实时数据获取)
|
||||||
|
vo.setOfflinePayloadCount(0);
|
||||||
|
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -91,4 +91,20 @@ public interface IThingsBoardDomain {
|
||||||
* @return 子设备ID列表,如果网关没有子设备则返回空列表
|
* @return 子设备ID列表,如果网关没有子设备则返回空列表
|
||||||
*/
|
*/
|
||||||
List<String> getGatewayChildDevices(String gatewayDeviceId);
|
List<String> getGatewayChildDevices(String gatewayDeviceId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除设备属性缓存
|
||||||
|
* 使 getDeviceAttributes 方法的缓存失效
|
||||||
|
*
|
||||||
|
* @param deviceId 设备ID
|
||||||
|
*/
|
||||||
|
void evictDeviceAttributesCache(String deviceId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除设备遥测数据缓存
|
||||||
|
* 使 getDeviceTelemetry 方法的缓存失效
|
||||||
|
*
|
||||||
|
* @param deviceId 设备ID
|
||||||
|
*/
|
||||||
|
void evictDeviceTelemetryCache(String deviceId);
|
||||||
}
|
}
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
package com.ruoyi.device.domain.impl;
|
package com.ruoyi.device.domain.impl;
|
||||||
|
|
||||||
|
|
||||||
import com.github.benmanes.caffeine.cache.Cache;
|
import com.ruoyi.device.config.DeviceCacheConfig;
|
||||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
|
||||||
import com.github.benmanes.caffeine.cache.Expiry;
|
|
||||||
import com.ruoyi.device.domain.api.IThingsBoardDomain;
|
import com.ruoyi.device.domain.api.IThingsBoardDomain;
|
||||||
import com.ruoyi.device.domain.model.thingsboard.*;
|
import com.ruoyi.device.domain.model.thingsboard.*;
|
||||||
import com.ruoyi.device.domain.model.thingsboard.constants.DeviceAttributes;
|
import com.ruoyi.device.domain.model.thingsboard.constants.DeviceAttributes;
|
||||||
|
|
@ -11,6 +9,8 @@ import com.ruoyi.device.domain.model.thingsboard.constants.DeviceTelemetry;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.cache.annotation.CacheEvict;
|
||||||
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.thingsboard.rest.client.RestClient;
|
import org.thingsboard.rest.client.RestClient;
|
||||||
|
|
@ -30,9 +30,7 @@ import org.thingsboard.server.common.data.relation.RelationTypeGroup;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Random;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ThingsBoard设备服务实现类
|
* ThingsBoard设备服务实现类
|
||||||
|
|
@ -46,10 +44,6 @@ public class ThingsBoardDomainImpl implements IThingsBoardDomain {
|
||||||
|
|
||||||
private final RestClient client;
|
private final RestClient client;
|
||||||
private final int pageSize;
|
private final int pageSize;
|
||||||
private final Random random = new Random();
|
|
||||||
|
|
||||||
private final Cache<String, AttributeMap> attributesCache;
|
|
||||||
private final Cache<String, TelemetryMap> telemetryCache;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造函数 - Spring 会自动装配
|
* 构造函数 - Spring 会自动装配
|
||||||
|
|
@ -60,48 +54,6 @@ public class ThingsBoardDomainImpl implements IThingsBoardDomain {
|
||||||
@Value("${thingsboard.page-size:10}") int pageSize) {
|
@Value("${thingsboard.page-size:10}") int pageSize) {
|
||||||
this.client = clientManager.getClient();
|
this.client = clientManager.getClient();
|
||||||
this.pageSize = pageSize;
|
this.pageSize = pageSize;
|
||||||
|
|
||||||
this.attributesCache = Caffeine.newBuilder()
|
|
||||||
.expireAfter(new Expiry<String, AttributeMap>() {
|
|
||||||
@Override
|
|
||||||
public long expireAfterCreate(String key, AttributeMap value, long currentTime) {
|
|
||||||
long randomSeconds = 60 + random.nextInt(61);
|
|
||||||
return TimeUnit.SECONDS.toNanos(randomSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long expireAfterUpdate(String key, AttributeMap value, long currentTime, long currentDuration) {
|
|
||||||
long randomSeconds = 60 + random.nextInt(61);
|
|
||||||
return TimeUnit.SECONDS.toNanos(randomSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long expireAfterRead(String key, AttributeMap value, long currentTime, long currentDuration) {
|
|
||||||
return currentDuration;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.build();
|
|
||||||
|
|
||||||
this.telemetryCache = Caffeine.newBuilder()
|
|
||||||
.expireAfter(new Expiry<String, TelemetryMap>() {
|
|
||||||
@Override
|
|
||||||
public long expireAfterCreate(String key, TelemetryMap value, long currentTime) {
|
|
||||||
long randomSeconds = 12 + random.nextInt(7);
|
|
||||||
return TimeUnit.SECONDS.toNanos(randomSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long expireAfterUpdate(String key, TelemetryMap value, long currentTime, long currentDuration) {
|
|
||||||
long randomSeconds = 12 + random.nextInt(7);
|
|
||||||
return TimeUnit.SECONDS.toNanos(randomSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long expireAfterRead(String key, TelemetryMap value, long currentTime, long currentDuration) {
|
|
||||||
return currentDuration;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -138,22 +90,22 @@ public class ThingsBoardDomainImpl implements IThingsBoardDomain {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Cacheable(value = DeviceCacheConfig.THINGSBOARD_ATTRIBUTES_CACHE, key = "#deviceId", unless = "#result == null || #result.isEmpty()")
|
||||||
public AttributeMap getDeviceAttributes(String deviceId) {
|
public AttributeMap getDeviceAttributes(String deviceId) {
|
||||||
return attributesCache.get(deviceId, id -> {
|
|
||||||
AttributeMap attributeMap = new AttributeMap();
|
AttributeMap attributeMap = new AttributeMap();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DeviceId deviceIdObj = new DeviceId(UUID.fromString(id));
|
DeviceId deviceIdObj = new DeviceId(UUID.fromString(deviceId));
|
||||||
|
|
||||||
List<String> attributeKeys = client.getAttributeKeys(deviceIdObj);
|
List<String> attributeKeys = client.getAttributeKeys(deviceIdObj);
|
||||||
if (attributeKeys == null || attributeKeys.isEmpty()) {
|
if (attributeKeys == null || attributeKeys.isEmpty()) {
|
||||||
log.debug("设备 {} 没有属性", id);
|
log.debug("设备 {} 没有属性", deviceId);
|
||||||
return attributeMap;
|
return attributeMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<AttributeKvEntry> attributeKvEntries = client.getAttributeKvEntries(deviceIdObj, attributeKeys);
|
List<AttributeKvEntry> attributeKvEntries = client.getAttributeKvEntries(deviceIdObj, attributeKeys);
|
||||||
if (attributeKvEntries == null || attributeKvEntries.isEmpty()) {
|
if (attributeKvEntries == null || attributeKvEntries.isEmpty()) {
|
||||||
log.debug("设备 {} 的属性值为空", id);
|
log.debug("设备 {} 的属性值为空", deviceId);
|
||||||
return attributeMap;
|
return attributeMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -162,30 +114,29 @@ public class ThingsBoardDomainImpl implements IThingsBoardDomain {
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("获取设备属性失败: deviceId={}, error={}", id, e.getMessage(), e);
|
log.error("获取设备属性失败: deviceId={}, error={}", deviceId, e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return attributeMap;
|
return attributeMap;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Cacheable(value = DeviceCacheConfig.THINGSBOARD_TELEMETRY_CACHE, key = "#deviceId", unless = "#result == null || #result.isEmpty()")
|
||||||
public TelemetryMap getDeviceTelemetry(String deviceId) {
|
public TelemetryMap getDeviceTelemetry(String deviceId) {
|
||||||
return telemetryCache.get(deviceId, id -> {
|
|
||||||
TelemetryMap telemetryMap = new TelemetryMap();
|
TelemetryMap telemetryMap = new TelemetryMap();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DeviceId deviceIdObj = new DeviceId(UUID.fromString(id));
|
DeviceId deviceIdObj = new DeviceId(UUID.fromString(deviceId));
|
||||||
|
|
||||||
List<String> timeseriesKeys = client.getTimeseriesKeys(deviceIdObj);
|
List<String> timeseriesKeys = client.getTimeseriesKeys(deviceIdObj);
|
||||||
if (timeseriesKeys == null || timeseriesKeys.isEmpty()) {
|
if (timeseriesKeys == null || timeseriesKeys.isEmpty()) {
|
||||||
log.debug("设备 {} 没有遥测数据", id);
|
log.debug("设备 {} 没有遥测数据", deviceId);
|
||||||
return telemetryMap;
|
return telemetryMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<TsKvEntry> latestTimeseries = client.getLatestTimeseries(deviceIdObj, timeseriesKeys);
|
List<TsKvEntry> latestTimeseries = client.getLatestTimeseries(deviceIdObj, timeseriesKeys);
|
||||||
if (latestTimeseries == null || latestTimeseries.isEmpty()) {
|
if (latestTimeseries == null || latestTimeseries.isEmpty()) {
|
||||||
log.debug("设备 {} 的遥测数据为空", id);
|
log.debug("设备 {} 的遥测数据为空", deviceId);
|
||||||
return telemetryMap;
|
return telemetryMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -194,11 +145,10 @@ public class ThingsBoardDomainImpl implements IThingsBoardDomain {
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("获取设备遥测数据失败: deviceId={}, error={}", id, e.getMessage(), e);
|
log.error("获取设备遥测数据失败: deviceId={}, error={}", deviceId, e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return telemetryMap;
|
return telemetryMap;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -379,5 +329,15 @@ public class ThingsBoardDomainImpl implements IThingsBoardDomain {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CacheEvict(value = DeviceCacheConfig.THINGSBOARD_ATTRIBUTES_CACHE, key = "#deviceId")
|
||||||
|
public void evictDeviceAttributesCache(String deviceId) {
|
||||||
|
// 空实现,仅用于清除缓存
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CacheEvict(value = DeviceCacheConfig.THINGSBOARD_TELEMETRY_CACHE, key = "#deviceId")
|
||||||
|
public void evictDeviceTelemetryCache(String deviceId) {
|
||||||
|
// 空实现,仅用于清除缓存
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,256 @@
|
||||||
|
package com.ruoyi.device.websocket;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.ruoyi.device.api.domain.StatisticsVO;
|
||||||
|
import com.ruoyi.device.service.api.IBufferDeviceService;
|
||||||
|
import com.ruoyi.device.service.api.IAircraftService;
|
||||||
|
import com.ruoyi.device.service.api.IDockService;
|
||||||
|
import com.ruoyi.device.service.api.IPayloadService;
|
||||||
|
import com.ruoyi.device.service.dto.AircraftDTO;
|
||||||
|
import com.ruoyi.device.service.dto.AircraftDetailDTO;
|
||||||
|
import com.ruoyi.device.service.dto.DockDTO;
|
||||||
|
import com.ruoyi.device.service.dto.DockDetailDTO;
|
||||||
|
import com.ruoyi.device.service.dto.PayloadDTO;
|
||||||
|
import com.ruoyi.device.api.enums.AircraftStatusEnum;
|
||||||
|
import com.ruoyi.device.api.enums.DockStatusEnum;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import jakarta.websocket.*;
|
||||||
|
import jakarta.websocket.server.PathParam;
|
||||||
|
import jakarta.websocket.server.ServerEndpoint;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@ServerEndpoint("/websocket/statistics/{type}")
|
||||||
|
public class StatisticsWebSocket {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(StatisticsWebSocket.class);
|
||||||
|
|
||||||
|
private static IBufferDeviceService bufferDeviceService;
|
||||||
|
private static IAircraftService aircraftService;
|
||||||
|
private static IDockService dockService;
|
||||||
|
private static IPayloadService payloadService;
|
||||||
|
|
||||||
|
private Session session;
|
||||||
|
|
||||||
|
private static final Map<String, CopyOnWriteArraySet<StatisticsWebSocket>> sessions = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setBufferDeviceService(IBufferDeviceService bufferDeviceService) {
|
||||||
|
StatisticsWebSocket.bufferDeviceService = bufferDeviceService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setAircraftService(IAircraftService aircraftService) {
|
||||||
|
StatisticsWebSocket.aircraftService = aircraftService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setDockService(IDockService dockService) {
|
||||||
|
StatisticsWebSocket.dockService = dockService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setPayloadService(IPayloadService payloadService) {
|
||||||
|
StatisticsWebSocket.payloadService = payloadService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnOpen
|
||||||
|
public void onOpen(Session session, @PathParam("type") String type) {
|
||||||
|
this.session = session;
|
||||||
|
sessions.computeIfAbsent(type, k -> new CopyOnWriteArraySet<>()).add(this);
|
||||||
|
log.info("WebSocket连接建立: sessionId={}, type={}", session.getId(), type);
|
||||||
|
|
||||||
|
sendCurrentStatistics(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnClose
|
||||||
|
public void onClose(@PathParam("type") String type) {
|
||||||
|
CopyOnWriteArraySet<StatisticsWebSocket> typeSessions = sessions.get(type);
|
||||||
|
if (typeSessions != null) {
|
||||||
|
typeSessions.remove(this);
|
||||||
|
if (typeSessions.isEmpty()) {
|
||||||
|
sessions.remove(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("WebSocket连接关闭: sessionId={}, type={}", session.getId(), type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnMessage
|
||||||
|
public void onMessage(String message, @PathParam("type") String type) {
|
||||||
|
log.info("收到WebSocket消息: sessionId={}, type={}, message={}", session.getId(), type, message);
|
||||||
|
if ("refresh".equals(message)) {
|
||||||
|
sendCurrentStatistics(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnError
|
||||||
|
public void onError(Session session, Throwable error, @PathParam("type") String type) {
|
||||||
|
log.error("WebSocket错误: sessionId={}, type={}, error={}", session.getId(), type, error.getMessage(), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendCurrentStatistics(String type) {
|
||||||
|
try {
|
||||||
|
StatisticsVO statistics = buildStatistics(type);
|
||||||
|
sendMessage(JSON.toJSONString(statistics));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("发送统计数据失败: type={}, error={}", type, e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private StatisticsVO buildStatistics(String type) {
|
||||||
|
if ("th".equals(type)) {
|
||||||
|
return buildThStatistics();
|
||||||
|
} else {
|
||||||
|
return buildDjiStatistics();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private StatisticsVO buildDjiStatistics() {
|
||||||
|
StatisticsVO vo = new StatisticsVO();
|
||||||
|
|
||||||
|
List<DockDTO> docks = dockService.selectDockList(new DockDTO());
|
||||||
|
vo.setDockCount(docks != null ? docks.size() : 0);
|
||||||
|
|
||||||
|
Map<Long, DockDetailDTO> dockDetailsMap = null;
|
||||||
|
if (docks != null && !docks.isEmpty()) {
|
||||||
|
List<Long> dockIds = docks.stream()
|
||||||
|
.map(DockDTO::getDockId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
dockDetailsMap = bufferDeviceService.getDockDetailsByIds(dockIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
int idleCount = 0;
|
||||||
|
int workingCount = 0;
|
||||||
|
int debuggingCount = 0;
|
||||||
|
int offlineCount = 0;
|
||||||
|
|
||||||
|
if (docks != null && dockDetailsMap != null) {
|
||||||
|
for (DockDTO dock : docks) {
|
||||||
|
DockDetailDTO dockDetail = dockDetailsMap.get(dock.getDockId());
|
||||||
|
if (dockDetail != null && dockDetail.getDockStatus() != null) {
|
||||||
|
String status = dockDetail.getDockStatus();
|
||||||
|
if (DockStatusEnum.IDLE.getCode().equals(status)) {
|
||||||
|
idleCount++;
|
||||||
|
} else if (DockStatusEnum.WORKING.getCode().equals(status)) {
|
||||||
|
workingCount++;
|
||||||
|
} else if (DockStatusEnum.Debugging.getCode().equals(status)) {
|
||||||
|
debuggingCount++;
|
||||||
|
} else {
|
||||||
|
offlineCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vo.setIdleDockCount(idleCount);
|
||||||
|
vo.setWorkingDockCount(workingCount);
|
||||||
|
vo.setDebuggingDockCount(debuggingCount);
|
||||||
|
vo.setOfflineDockCount(offlineCount);
|
||||||
|
|
||||||
|
List<AircraftDTO> aircrafts = aircraftService.selectAircraftList(new AircraftDTO());
|
||||||
|
vo.setAircraftCount(aircrafts != null ? aircrafts.size() : 0);
|
||||||
|
|
||||||
|
Map<Long, AircraftDetailDTO> aircraftDetailsMap = null;
|
||||||
|
if (aircrafts != null && !aircrafts.isEmpty()) {
|
||||||
|
List<Long> aircraftIds = aircrafts.stream()
|
||||||
|
.map(AircraftDTO::getAircraftId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
aircraftDetailsMap = bufferDeviceService.getAircraftDetailsByIds(aircraftIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
int powerOnInCabinCount = 0;
|
||||||
|
int powerOffInCabinCount = 0;
|
||||||
|
int inMissionCount = 0;
|
||||||
|
int debuggingAircraftCount = 0;
|
||||||
|
int offlineAircraftCount = 0;
|
||||||
|
|
||||||
|
if (aircrafts != null && aircraftDetailsMap != null) {
|
||||||
|
for (AircraftDTO aircraft : aircrafts) {
|
||||||
|
AircraftDetailDTO aircraftDetail = aircraftDetailsMap.get(aircraft.getAircraftId());
|
||||||
|
if (aircraftDetail != null && aircraftDetail.getAircraftStatus() != null) {
|
||||||
|
String status = aircraftDetail.getAircraftStatus();
|
||||||
|
if (AircraftStatusEnum.POWER_ON_IN_CABIN.getCode().equals(status)) {
|
||||||
|
powerOnInCabinCount++;
|
||||||
|
} else if (AircraftStatusEnum.POWER_OFF_IN_CABIN.getCode().equals(status)) {
|
||||||
|
powerOffInCabinCount++;
|
||||||
|
} else if (AircraftStatusEnum.IN_MISSION.getCode().equals(status)) {
|
||||||
|
inMissionCount++;
|
||||||
|
} else if (AircraftStatusEnum.DEBUGGING.getCode().equals(status)) {
|
||||||
|
debuggingAircraftCount++;
|
||||||
|
} else if (AircraftStatusEnum.OFFLINE.getCode().equals(status)) {
|
||||||
|
offlineAircraftCount++;
|
||||||
|
} else {
|
||||||
|
offlineAircraftCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vo.setPowerOnInCabinCount(powerOnInCabinCount);
|
||||||
|
vo.setPowerOffInCabinCount(powerOffInCabinCount);
|
||||||
|
vo.setInMissionCount(inMissionCount);
|
||||||
|
vo.setDebuggingAircraftCount(debuggingAircraftCount);
|
||||||
|
vo.setOfflineAircraftCount(offlineAircraftCount);
|
||||||
|
|
||||||
|
List<PayloadDTO> payloads = payloadService.selectPayloadList(new PayloadDTO());
|
||||||
|
vo.setPayloadCount(payloads != null ? payloads.size() : 0);
|
||||||
|
vo.setOfflinePayloadCount(0);
|
||||||
|
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private StatisticsVO buildThStatistics() {
|
||||||
|
StatisticsVO vo = new StatisticsVO();
|
||||||
|
vo.setDockCount(0);
|
||||||
|
vo.setIdleDockCount(0);
|
||||||
|
vo.setWorkingDockCount(0);
|
||||||
|
vo.setDebuggingDockCount(0);
|
||||||
|
vo.setOfflineDockCount(0);
|
||||||
|
vo.setAircraftCount(0);
|
||||||
|
vo.setPowerOnInCabinCount(0);
|
||||||
|
vo.setPowerOffInCabinCount(0);
|
||||||
|
vo.setInMissionCount(0);
|
||||||
|
vo.setDebuggingAircraftCount(0);
|
||||||
|
vo.setOfflineAircraftCount(0);
|
||||||
|
vo.setPayloadCount(0);
|
||||||
|
vo.setOfflinePayloadCount(0);
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendMessage(String message) {
|
||||||
|
try {
|
||||||
|
if (session != null && session.isOpen()) {
|
||||||
|
session.getBasicRemote().sendText(message);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("发送WebSocket消息失败: error={}", e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void broadcastToType(String type, String message) {
|
||||||
|
CopyOnWriteArraySet<StatisticsWebSocket> typeSessions = sessions.get(type);
|
||||||
|
if (typeSessions != null) {
|
||||||
|
for (StatisticsWebSocket ws : typeSessions) {
|
||||||
|
ws.sendMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void broadcastDjiStatistics() {
|
||||||
|
StatisticsVO statistics = new StatisticsWebSocket().buildDjiStatistics();
|
||||||
|
broadcastToType("dji", JSON.toJSONString(statistics));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void broadcastThStatistics() {
|
||||||
|
StatisticsVO statistics = new StatisticsWebSocket().buildThStatistics();
|
||||||
|
broadcastToType("th", JSON.toJSONString(statistics));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue