|
@@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
|
|
|
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
|
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
|
|
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
|
|
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
|
|
|
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
|
|
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
|
|
|
-import cn.iocoder.yudao.module.pms.controller.admin.vo.DeviceVO;
|
|
|
|
|
import cn.iocoder.yudao.module.pms.dal.dataobject.IotDeviceDO;
|
|
import cn.iocoder.yudao.module.pms.dal.dataobject.IotDeviceDO;
|
|
|
import cn.iocoder.yudao.module.pms.dal.dataobject.yanfan.YfDeviceDO;
|
|
import cn.iocoder.yudao.module.pms.dal.dataobject.yanfan.YfDeviceDO;
|
|
|
import cn.iocoder.yudao.module.pms.dal.mysql.IotDeviceMapper;
|
|
import cn.iocoder.yudao.module.pms.dal.mysql.IotDeviceMapper;
|
|
@@ -21,9 +20,8 @@ import org.springframework.stereotype.Component;
|
|
|
import javax.annotation.Resource;
|
|
import javax.annotation.Resource;
|
|
|
import java.sql.Timestamp;
|
|
import java.sql.Timestamp;
|
|
|
import java.text.SimpleDateFormat;
|
|
import java.text.SimpleDateFormat;
|
|
|
-import java.util.ArrayList;
|
|
|
|
|
-import java.util.List;
|
|
|
|
|
-import java.util.Objects;
|
|
|
|
|
|
|
+import java.util.*;
|
|
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
@Component
|
|
@Component
|
|
|
@Slf4j
|
|
@Slf4j
|
|
@@ -40,76 +38,170 @@ public class TdCronJob implements JobHandler {
|
|
|
@Override
|
|
@Override
|
|
|
@TenantIgnore
|
|
@TenantIgnore
|
|
|
public String execute(String param) throws Exception {
|
|
public String execute(String param) throws Exception {
|
|
|
- List<String> codes = new ArrayList<>();
|
|
|
|
|
|
|
+
|
|
|
|
|
+ //1.查询源设备,构建sn -> YfDeviceDO map,避免循环内stream findFirst
|
|
|
List<YfDeviceDO> allDevice = yfDeviceService.getAllDevice();
|
|
List<YfDeviceDO> allDevice = yfDeviceService.getAllDevice();
|
|
|
- allDevice.forEach(d -> {
|
|
|
|
|
- codes.add(d.getSerialNumber());
|
|
|
|
|
|
|
+ Map<String, YfDeviceDO> yfDeviceMap = allDevice.stream()
|
|
|
|
|
+ .collect(Collectors.toMap(YfDeviceDO::getSerialNumber, e -> e));
|
|
|
|
|
+ List<String> rawSnList = new ArrayList<>(yfDeviceMap.keySet());
|
|
|
|
|
+ if(CollUtil.isEmpty(rawSnList)){
|
|
|
|
|
+ return "";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //2.查询iot设备
|
|
|
|
|
+ List<IotDeviceDO> devices = iotDeviceMapper.selectByCodeIn(rawSnList);
|
|
|
|
|
+ if (CollUtil.isEmpty(devices)) {
|
|
|
|
|
+ return "";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ===================== TDengine批量预处理(替代循环内tableIfExist、selectLastTime) =====================
|
|
|
|
|
+ // 子表完整表名:device_${sn}
|
|
|
|
|
+ List<String> fullTbNameList = rawSnList.stream()
|
|
|
|
|
+ .map(sn -> "device_" + sn)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ for (String s : fullTbNameList) {
|
|
|
|
|
+ System.out.println("--------------"+s);
|
|
|
|
|
+ }
|
|
|
|
|
+ //批量查询哪些子表真实存在
|
|
|
|
|
+ List<String> existFullTbList = deviceMapper.batchGetExistFullTbName(fullTbNameList);
|
|
|
|
|
+ existFullTbList.forEach(device -> {
|
|
|
|
|
+ System.out.println("%%%%%%%%%%%%%%%%"+device);
|
|
|
});
|
|
});
|
|
|
- List<IotDeviceDO> devices = iotDeviceMapper.selectByCodeIn(codes);
|
|
|
|
|
|
|
+ // key:完整表名 device_xxx ; value:原始sn
|
|
|
|
|
+ Map<String, String> fullTbToRawSnMap = new HashMap<>();
|
|
|
|
|
+ for (String sn : rawSnList) {
|
|
|
|
|
+ fullTbToRawSnMap.put("device_" + sn, sn);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //批量查询【带identity过滤条件】每个设备最大ts
|
|
|
|
|
+ Map<String, Timestamp> rawSnLastTsMap = new HashMap<>();
|
|
|
|
|
+ if (CollUtil.isNotEmpty(existFullTbList)) {
|
|
|
|
|
+ List<SnTsVO> snTsVOList = deviceMapper.batchQueryFilterLastTs(existFullTbList);
|
|
|
|
|
+ System.out.println("=========================="+JSON.toJSONString(snTsVOList));
|
|
|
|
|
+ for (SnTsVO vo : snTsVOList) {
|
|
|
|
|
+ String rawSn = fullTbToRawSnMap.get(vo.getTbName());
|
|
|
|
|
+ if(rawSn != null && vo.getTs() != null){
|
|
|
|
|
+ rawSnLastTsMap.put(rawSn, vo.getTs());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
|
|
+
|
|
|
|
|
+ // ===================== Redis批量获取hash字段,减少网络IO =====================
|
|
|
|
|
+ Set<String> deviceCodeSet = devices.stream().map(IotDeviceDO::getDeviceCode).collect(Collectors.toSet());
|
|
|
|
|
+ Map<String, Map<Object, Object>> redisHashCache = new HashMap<>();
|
|
|
|
|
+ for (String code : deviceCodeSet) {
|
|
|
|
|
+ String hashKey = "TSLV:" + code;
|
|
|
|
|
+ List<Object> multiGet = redisTemplate.opsForHash().multiGet(hashKey, Arrays.asList("lat", "lng", "online"));
|
|
|
|
|
+ Map<Object, Object> fieldMap = new HashMap<>();
|
|
|
|
|
+ fieldMap.put("lat", multiGet.get(0));
|
|
|
|
|
+ fieldMap.put("lng", multiGet.get(1));
|
|
|
|
|
+ fieldMap.put("online", multiGet.get(2));
|
|
|
|
|
+ redisHashCache.put(code, fieldMap);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ===================== 业务组装,循环内部不再任何DB调用 =====================
|
|
|
List<IotDeviceDO> deviceDOS = new ArrayList<>();
|
|
List<IotDeviceDO> deviceDOS = new ArrayList<>();
|
|
|
for (IotDeviceDO device : devices) {
|
|
for (IotDeviceDO device : devices) {
|
|
|
String deviceCode = device.getDeviceCode();
|
|
String deviceCode = device.getDeviceCode();
|
|
|
- allDevice.stream().filter(e -> e.getSerialNumber().equals(deviceCode)).findFirst().ifPresent(e -> {
|
|
|
|
|
- device.setYfDeviceId(e.getDeviceId());
|
|
|
|
|
- Integer i = deviceMapper.tableIfExist(e.getSerialNumber().toLowerCase());
|
|
|
|
|
- if (i==1) {
|
|
|
|
|
- List<DeviceVO> deviceVOS = deviceMapper.selectLastTime(e.getSerialNumber());
|
|
|
|
|
- if (CollUtil.isNotEmpty(deviceVOS)) {
|
|
|
|
|
- Timestamp ts = deviceVOS.get(0).getTs();
|
|
|
|
|
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
|
|
- String format = sdf.format(ts);
|
|
|
|
|
- device.setLastInlineTime(format);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- if (e.getStatus()==1) {//未激活状态
|
|
|
|
|
-
|
|
|
|
|
- if (StringUtils.isNotBlank(device.getLastInlineTime())) {
|
|
|
|
|
- try {
|
|
|
|
|
- if (DateUtils.checkIfFullDayDifference(device.getLastInlineTime())) {
|
|
|
|
|
- device.setIfInline(4);
|
|
|
|
|
- } else {
|
|
|
|
|
- device.setIfInline(3);
|
|
|
|
|
- }
|
|
|
|
|
- } catch (Exception ex) {
|
|
|
|
|
- throw new RuntimeException(ex.getMessage());
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- device.setIfInline(4);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- Object lat = redisTemplate.opsForHash().get("TSLV:" + device.getDeviceCode(), "lat");
|
|
|
|
|
- if (Objects.nonNull(lat)) {
|
|
|
|
|
- JSONObject jsonObject = JSON.parseObject(lat.toString());
|
|
|
|
|
- device.setLat(Double.valueOf((String) jsonObject.get("value")));
|
|
|
|
|
- }
|
|
|
|
|
- Object lng = redisTemplate.opsForHash().get("TSLV:" + device.getDeviceCode(), "lng");
|
|
|
|
|
- if (Objects.nonNull(lng)) {
|
|
|
|
|
- JSONObject jsonObject = JSON.parseObject(lng.toString());
|
|
|
|
|
- device.setLng(Double.valueOf((String) jsonObject.get("value")));
|
|
|
|
|
- }
|
|
|
|
|
- Object online = redisTemplate.opsForHash().get("TSLV:" + device.getDeviceCode(), "online");
|
|
|
|
|
- if (Objects.nonNull(online)) {
|
|
|
|
|
- JSONObject jsonObject = JSON.parseObject(online.toString());
|
|
|
|
|
- String value = String.valueOf(jsonObject.get("value"));
|
|
|
|
|
- device.setIfInline("true".equals(value)?3:4);
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- if (StringUtils.isNotBlank(device.getLastInlineTime())) {
|
|
|
|
|
- if (DateUtils.checkIfFullDayDifference(device.getLastInlineTime())) {
|
|
|
|
|
- device.setIfInline(4);
|
|
|
|
|
- } else {
|
|
|
|
|
- device.setIfInline(e.getStatus());
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- device.setIfInline(4);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-// iotDeviceMapper.updateTdCron(device);
|
|
|
|
|
- deviceDOS.add(device);
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ YfDeviceDO yfDevice = yfDeviceMap.get(deviceCode);
|
|
|
|
|
+ if (yfDevice == null) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ device.setYfDeviceId(yfDevice.getDeviceId());
|
|
|
|
|
+ String sn = yfDevice.getSerialNumber();
|
|
|
|
|
+
|
|
|
|
|
+ //从预加载map拿ts,完全替代循环调用selectLastTime
|
|
|
|
|
+ Timestamp ts = rawSnLastTsMap.get(sn);
|
|
|
|
|
+ if (ts != null) {
|
|
|
|
|
+ device.setLastInlineTime(sdf.format(ts));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ device.setLastInlineTime(null);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //填充在线状态逻辑
|
|
|
|
|
+ fillInlineStatus(device, yfDevice);
|
|
|
|
|
+ //填充经纬度、redis在线标记
|
|
|
|
|
+ fillLocationAndOnline(device, redisHashCache.get(deviceCode));
|
|
|
|
|
+
|
|
|
|
|
+ deviceDOS.add(device);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (CollUtil.isNotEmpty(deviceDOS)) {
|
|
|
|
|
+ iotDeviceMapper.updateBatch(deviceDOS);
|
|
|
}
|
|
}
|
|
|
- iotDeviceMapper.updateBatch(deviceDOS);
|
|
|
|
|
return "";
|
|
return "";
|
|
|
|
|
+// List<String> codes = new ArrayList<>();
|
|
|
|
|
+// List<YfDeviceDO> allDevice = yfDeviceService.getAllDevice();
|
|
|
|
|
+// allDevice.forEach(d -> {
|
|
|
|
|
+// codes.add(d.getSerialNumber());
|
|
|
|
|
+// });
|
|
|
|
|
+// List<IotDeviceDO> devices = iotDeviceMapper.selectByCodeIn(codes);
|
|
|
|
|
+// List<IotDeviceDO> deviceDOS = new ArrayList<>();
|
|
|
|
|
+// for (IotDeviceDO device : devices) {
|
|
|
|
|
+// String deviceCode = device.getDeviceCode();
|
|
|
|
|
+// allDevice.stream().filter(e -> e.getSerialNumber().equals(deviceCode)).findFirst().ifPresent(e -> {
|
|
|
|
|
+// device.setYfDeviceId(e.getDeviceId());
|
|
|
|
|
+// Integer i = deviceMapper.tableIfExist(e.getSerialNumber().toLowerCase());
|
|
|
|
|
+// if (i==1) {
|
|
|
|
|
+// List<DeviceVO> deviceVOS = deviceMapper.selectLastTime(e.getSerialNumber());
|
|
|
|
|
+// if (CollUtil.isNotEmpty(deviceVOS)) {
|
|
|
|
|
+// Timestamp ts = deviceVOS.get(0).getTs();
|
|
|
|
|
+// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
|
|
+// String format = sdf.format(ts);
|
|
|
|
|
+// device.setLastInlineTime(format);
|
|
|
|
|
+// }
|
|
|
|
|
+// }
|
|
|
|
|
+// if (e.getStatus()==1) {//未激活状态
|
|
|
|
|
+//
|
|
|
|
|
+// if (StringUtils.isNotBlank(device.getLastInlineTime())) {
|
|
|
|
|
+// try {
|
|
|
|
|
+// if (DateUtils.checkIfFullDayDifference(device.getLastInlineTime())) {
|
|
|
|
|
+// device.setIfInline(4);
|
|
|
|
|
+// } else {
|
|
|
|
|
+// device.setIfInline(3);
|
|
|
|
|
+// }
|
|
|
|
|
+// } catch (Exception ex) {
|
|
|
|
|
+// throw new RuntimeException(ex.getMessage());
|
|
|
|
|
+// }
|
|
|
|
|
+// } else {
|
|
|
|
|
+// device.setIfInline(4);
|
|
|
|
|
+// }
|
|
|
|
|
+//
|
|
|
|
|
+// Object lat = redisTemplate.opsForHash().get("TSLV:" + device.getDeviceCode(), "lat");
|
|
|
|
|
+// if (Objects.nonNull(lat)) {
|
|
|
|
|
+// JSONObject jsonObject = JSON.parseObject(lat.toString());
|
|
|
|
|
+// device.setLat(Double.valueOf((String) jsonObject.get("value")));
|
|
|
|
|
+// }
|
|
|
|
|
+// Object lng = redisTemplate.opsForHash().get("TSLV:" + device.getDeviceCode(), "lng");
|
|
|
|
|
+// if (Objects.nonNull(lng)) {
|
|
|
|
|
+// JSONObject jsonObject = JSON.parseObject(lng.toString());
|
|
|
|
|
+// device.setLng(Double.valueOf((String) jsonObject.get("value")));
|
|
|
|
|
+// }
|
|
|
|
|
+// Object online = redisTemplate.opsForHash().get("TSLV:" + device.getDeviceCode(), "online");
|
|
|
|
|
+// if (Objects.nonNull(online)) {
|
|
|
|
|
+// JSONObject jsonObject = JSON.parseObject(online.toString());
|
|
|
|
|
+// String value = String.valueOf(jsonObject.get("value"));
|
|
|
|
|
+// device.setIfInline("true".equals(value)?3:4);
|
|
|
|
|
+// }
|
|
|
|
|
+// } else {
|
|
|
|
|
+// if (StringUtils.isNotBlank(device.getLastInlineTime())) {
|
|
|
|
|
+// if (DateUtils.checkIfFullDayDifference(device.getLastInlineTime())) {
|
|
|
|
|
+// device.setIfInline(4);
|
|
|
|
|
+// } else {
|
|
|
|
|
+// device.setIfInline(e.getStatus());
|
|
|
|
|
+// }
|
|
|
|
|
+// } else {
|
|
|
|
|
+// device.setIfInline(4);
|
|
|
|
|
+// }
|
|
|
|
|
+// }
|
|
|
|
|
+//// iotDeviceMapper.updateTdCron(device);
|
|
|
|
|
+// deviceDOS.add(device);
|
|
|
|
|
+// });
|
|
|
|
|
+// }
|
|
|
|
|
+// iotDeviceMapper.updateBatch(deviceDOS);
|
|
|
|
|
+// return "";
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -117,4 +209,62 @@ public class TdCronJob implements JobHandler {
|
|
|
String abc = "2026-01-21 10:25:40";
|
|
String abc = "2026-01-21 10:25:40";
|
|
|
System.out.println(DateUtils.checkIfFullDayDifference(abc));
|
|
System.out.println(DateUtils.checkIfFullDayDifference(abc));
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 填充在线状态逻辑,原业务逻辑完全保留
|
|
|
|
|
+ */
|
|
|
|
|
+ private void fillInlineStatus(IotDeviceDO device, YfDeviceDO yfDevice) throws Exception {
|
|
|
|
|
+ String lastInlineTime = device.getLastInlineTime();
|
|
|
|
|
+ Integer yfStatus = yfDevice.getStatus();
|
|
|
|
|
+ if (yfStatus == 1) {
|
|
|
|
|
+ //未激活状态
|
|
|
|
|
+ if (StringUtils.isNotBlank(lastInlineTime)) {
|
|
|
|
|
+ if (DateUtils.checkIfFullDayDifference(lastInlineTime)) {
|
|
|
|
|
+ device.setIfInline(4);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ device.setIfInline(3);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ device.setIfInline(4);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (StringUtils.isNotBlank(lastInlineTime)) {
|
|
|
|
|
+ if (DateUtils.checkIfFullDayDifference(lastInlineTime)) {
|
|
|
|
|
+ device.setIfInline(4);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ device.setIfInline(yfStatus);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ device.setIfInline(4);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 填充经纬度、redis的online状态
|
|
|
|
|
+ */
|
|
|
|
|
+ private void fillLocationAndOnline(IotDeviceDO device, Map<Object, Object> redisFields) {
|
|
|
|
|
+ if (redisFields == null) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ Object latObj = redisFields.get("lat");
|
|
|
|
|
+ if (Objects.nonNull(latObj)) {
|
|
|
|
|
+ JSONObject jsonObject = JSON.parseObject(latObj.toString());
|
|
|
|
|
+ device.setLat(Double.valueOf(String.valueOf(jsonObject.get("value"))));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Object lngObj = redisFields.get("lng");
|
|
|
|
|
+ if (Objects.nonNull(lngObj)) {
|
|
|
|
|
+ JSONObject jsonObject = JSON.parseObject(lngObj.toString());
|
|
|
|
|
+ device.setLng(Double.valueOf(String.valueOf(jsonObject.get("value"))));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Object onlineObj = redisFields.get("online");
|
|
|
|
|
+ if (Objects.nonNull(onlineObj)) {
|
|
|
|
|
+ JSONObject jsonObject = JSON.parseObject(onlineObj.toString());
|
|
|
|
|
+ String value = String.valueOf(jsonObject.get("value"));
|
|
|
|
|
+ device.setIfInline("true".equals(value) ? 3 : 4);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|