Browse Source

fix: 重构influxdb service/AppDeviceService.java

jackzhou 6 months ago
parent
commit
639a01a989
15 changed files with 246 additions and 250 deletions
  1. 25 1
      snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/modular/login/param/AuthAccountPasswordLoginParam.java
  2. 0 35
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/bean/influxdb/ComparisonOperator.java
  3. 149 57
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/bean/influxdb/SensorData.java
  4. 4 81
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/bean/influxdb/SensorDataService.java
  5. 0 32
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/bean/influxdb/SensorQueryCondition.java
  6. 0 2
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/config/ColdChainAsyncConfig.java
  7. 0 2
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/renke/config/JfcloudColdChainServerAutoConfiguration.java
  8. 6 1
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/service/dataprocess/dataclean/impl/AbsRenkeMonitorDataProcessor.java
  9. 4 3
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/app/param/AppDeviceData.java
  10. 3 1
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/app/service/AppDeviceService.java
  11. 2 2
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitordevice/service/MonitorDeviceService.java
  12. 4 4
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitordevice/service/impl/MonitorDeviceServiceImpl.java
  13. 2 4
      snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitortargetregion/service/impl/MonitorTargetRegionServiceImpl.java
  14. 2 0
      snowy-web-app/src/main/java/vip/xiaonuo/Application.java
  15. 45 25
      snowy-web-app/src/main/java/vip/xiaonuo/core/config/GlobalTrimAdvice.java

+ 25 - 1
snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/modular/login/param/AuthAccountPasswordLoginParam.java

@@ -24,7 +24,6 @@ import lombok.Setter;
  * @date 2022/7/7 16:46
  **/
 @Getter
-@Setter
 public class AuthAccountPasswordLoginParam {
 
     /** 账号 */
@@ -52,4 +51,29 @@ public class AuthAccountPasswordLoginParam {
     /** 验证码请求号 */
     @Schema(description = "验证码请求号")
     private String validCodeReqNo;
+
+    // 自定义的 setter 方法,去除首尾空格
+    public void setAccount(String account) {
+        this.account = (account != null) ? account.trim() : null;
+    }
+
+    public void setPassword(String password) {
+        this.password = (password != null) ? password.trim() : null;
+    }
+
+    public void setDevice(String device) {
+        this.device = (device != null) ? device.trim() : null;
+    }
+
+    public void setValidCode(String validCode) {
+        this.validCode = (validCode != null) ? validCode.trim() : null;
+    }
+
+    public void setOpenId(String openId) {
+        this.openId = (openId != null) ? openId.trim() : null;
+    }
+
+    public void setValidCodeReqNo(String validCodeReqNo) {
+        this.validCodeReqNo = (validCodeReqNo != null) ? validCodeReqNo.trim() : null;
+    }
 }

+ 0 - 35
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/bean/influxdb/ComparisonOperator.java

@@ -1,35 +0,0 @@
-package vip.xiaonuo.coldchain.core.bean.influxdb;
-
-/**
- * @author jackzhou
- * @version 1.0
- * @project jfcloud-coldchain
- * @description
- * @date 2024/11/22 15:45:35
- */
-public enum ComparisonOperator {
-    GT(">"),
-    LT("<"),
-    GTE(">="),
-    LTE("<=");
-
-    private final String operator;
-
-    ComparisonOperator(String operator) {
-        this.operator = operator;
-    }
-
-    // 根据字符串获取对应的枚举
-    public static ComparisonOperator fromString(String operator) {
-        for (ComparisonOperator op : ComparisonOperator.values()) {
-            if (op.operator.equalsIgnoreCase(operator)) {
-                return op;
-            }
-        }
-        throw new IllegalArgumentException("Invalid operator: " + operator);
-    }
-
-    public String getOperator() {
-        return operator;
-    }
-}

+ 149 - 57
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/bean/influxdb/SensorData.java

@@ -6,21 +6,29 @@ import com.influxdb.annotations.Measurement;
 import com.influxdb.query.FluxRecord;
 import lombok.AllArgsConstructor;
 import lombok.Data;
+import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import vip.xiaonuo.coldchain.core.config.JfcloudColdChainConstants;
 import vip.xiaonuo.coldchain.core.service.dataprocess.model.PowerEnum;
 
+import java.lang.reflect.Field;
 import java.time.Instant;
-import java.time.ZoneOffset;
-import java.util.Optional;
-
+import java.time.LocalDate;
+import java.util.Date;
+
+/**
+ * SensorData类,用于表示传感器数据,继承自JfcloudInFluxEntity。
+ * 使用反射将FluxRecord映射到此类的属性。
+ */
+@EqualsAndHashCode(callSuper = true)
 @Data
 @AllArgsConstructor
 @NoArgsConstructor
 @Measurement(name = JfcloudColdChainConstants.INFLUXDB_DEFAULT_MEASUREMENT_NAME)
 @Slf4j
 public class SensorData extends JfcloudInFluxEntity {
+
     @Column(name = "temperature")
     private Float temperature;
 
@@ -54,75 +62,159 @@ public class SensorData extends JfcloudInFluxEntity {
     @Column(name = "model_name", tag = true)
     private String modelName;
 
+    /**
+     * 使用反射和FluxRecord动态映射字段值到SensorData对象
+     *
+     * @param record FluxRecord数据记录
+     * @return 映射后的SensorData对象
+     */
     public static SensorData mapToSensorData(FluxRecord record) {
         SensorData sensorData = new SensorData();
         try {
-            sensorData.setDeviceId(getStringValue(record, "device_id"));
-            sensorData.setRoads(getIntegerValue(record, "roads"));
-            sensorData.setTemperature(getFloatValue(record, "temperature"));
-            sensorData.setHumidity(getFloatValue(record, "humidity"));
-            sensorData.setCo2(getFloatValue(record, "co2"));
-            sensorData.setBattery(getFloatValue(record, "battery"));
-            sensorData.setPlugInStatus(getStringValue(record, "plugInStatus"));
-            sensorData.setLocation(getStringValue(record, "location"));
-            sensorData.setLng(getDoubleValue(record, "longitude"));
-            sensorData.setLat(getDoubleValue(record, "latitude"));
-            sensorData.setTime(getInstantValue(record));
-
+            // 获取SensorData类的所有字段
+            Field[] fields = SensorData.class.getDeclaredFields();
+            for (Field field : fields) {
+                field.setAccessible(true);  // 设置字段可访问
+                // 如果字段没有@Column注解,则跳过
+                if (field.getAnnotation(Column.class) == null) {
+                    continue;
+                }
+
+                String fieldName = field.getName(); // 获取字段名
+                Object value = record.getValueByKey(fieldName); // 从FluxRecord中根据字段名获取值
+                if (value == null) {
+                    continue; // 如果FluxRecord中没有该字段的值,则跳过
+                }
+
+                // 根据字段类型进行相应的值转换
+                if (field.getType().equals(String.class)) {
+                    field.set(sensorData, value.toString());
+                } else if (field.getType().equals(Integer.class) || field.getType().equals(int.class)) {
+                    field.set(sensorData, convertToInteger(value));
+                } else if (field.getType().equals(Float.class) || field.getType().equals(float.class)) {
+                    field.set(sensorData, convertToFloat(value));
+                } else if (field.getType().equals(Double.class) || field.getType().equals(double.class)) {
+                    field.set(sensorData, convertToDouble(value));
+                } else if (field.getType().equals(Instant.class)) {
+                    field.set(sensorData, convertToInstant(value));
+                } else if (field.getType().equals(Date.class)) {
+                    field.set(sensorData, convertToDate(value));
+                } else if (field.getType().equals(LocalDate.class)) {
+                    field.set(sensorData, convertToLocalDate(value));
+                } else {
+                    log.warn("无法处理字段类型: " + field.getName() + ",字段值: " + value);
+                }
+            }
         } catch (Exception e) {
-            log.error("Error mapping FluxRecord to SensorData", e);
+            log.error("从FluxRecord映射到SensorData时出错", e);
         }
         return sensorData;
     }
 
-    private static String getStringValue(FluxRecord record, String key) {
-        return Optional.ofNullable(record.getValueByKey(key))
-                .map(Object::toString)
-                .orElse(null);
+    // 类型转换方法
+
+    /**
+     * 将值转换为Integer类型
+     *
+     * @param value 要转换的值
+     * @return 转换后的Integer值
+     */
+    private static Integer convertToInteger(Object value) {
+        try {
+            return (value instanceof Integer) ? (Integer) value : Integer.valueOf(value.toString());
+        } catch (NumberFormatException e) {
+            log.error("将值转换为Integer时出错: " + value, e);
+            return null;
+        }
     }
 
-    private static Integer getIntegerValue(FluxRecord record, String key) {
-        return Optional.ofNullable(record.getValueByKey(key))
-                .map(value -> {
-                    try {
-                        return (value instanceof Integer) ? (Integer) value :
-                                (value instanceof String) ? Integer.valueOf((String) value) : null;
-                    } catch (NumberFormatException e) {
-                        return null;
-                    }
-                })
-                .orElse(null);
+    /**
+     * 将值转换为Float类型
+     *
+     * @param value 要转换的值
+     * @return 转换后的Float值
+     */
+    private static Float convertToFloat(Object value) {
+        try {
+            if (value instanceof Double) {
+                return ((Double) value).floatValue();  // 将Double 转换为Float
+            }
+            return (value instanceof Float) ? (Float) value : Float.valueOf(value.toString());
+        } catch (NumberFormatException e) {
+            log.error("将值转换为Float时出错: " + value, e);
+            return null;
+        }
     }
 
-    private static Double getDoubleValue(FluxRecord record, String key) {
-        return Optional.ofNullable(record.getValueByKey(key))
-                .map(value -> {
-                    try {
-                        return (value instanceof Double) ? (Double) value :
-                                (value instanceof String) ? Double.valueOf((String) value) : null;
-                    } catch (NumberFormatException e) {
-                        return null;
-                    }
-                })
-                .orElse(null);
+    /**
+     * 将值转换为Double类型
+     *
+     * @param value 要转换的值
+     * @return 转换后的Double值
+     */
+    private static Double convertToDouble(Object value) {
+        try {
+            return (value instanceof Double) ? (Double) value : Double.valueOf(value.toString());
+        } catch (NumberFormatException e) {
+            log.error("将值转换为Double时出错: " + value, e);
+            return null;
+        }
     }
 
-    private static Float getFloatValue(FluxRecord record, String key) {
-        return Optional.ofNullable(record.getValueByKey(key))
-                .map(value -> {
-                    try {
-                        return (value instanceof Float) ? (Float) value :
-                                (value instanceof String) ? Float.valueOf((String) value) : null;
-                    } catch (NumberFormatException e) {
-                        return null;
-                    }
-                })
-                .orElse(null);
+    /**
+     * 将值转换为Instant类型
+     *
+     * @param value 要转换的值
+     * @return 转换后的Instant值
+     */
+    private static Instant convertToInstant(Object value) {
+        try {
+            return (value instanceof Instant) ? (Instant) value : Instant.parse(value.toString());
+        } catch (Exception e) {
+            log.error("将值转换为Instant时出错: " + value, e);
+            return null;
+        }
+    }
+
+    /**
+     * 将值转换为Date类型
+     *
+     * @param value 要转换的值
+     * @return 转换后的Date值
+     */
+    private static Date convertToDate(Object value) {
+        try {
+            if (value instanceof Instant) {
+                return Date.from((Instant) value);
+            } else if (value instanceof String) {
+                return Date.from(Instant.parse((String) value));
+            } else {
+                return (Date) value;
+            }
+        } catch (Exception e) {
+            log.error("将值转换为Date时出错: " + value, e);
+            return null;
+        }
     }
 
-    private static Instant getInstantValue(FluxRecord record) {
-        return Optional.ofNullable(record.getTime())
-                .map(time -> time.atOffset(ZoneOffset.UTC).toInstant())
-                .orElse(null);
+    /**
+     * 将值转换为LocalDate类型
+     *
+     * @param value 要转换的值
+     * @return 转换后的LocalDate值
+     */
+    private static LocalDate convertToLocalDate(Object value) {
+        try {
+            if (value instanceof Instant) {
+                return ((Instant) value).atZone(java.time.ZoneId.systemDefault()).toLocalDate();
+            } else if (value instanceof String) {
+                return LocalDate.parse((String) value);
+            } else {
+                return (LocalDate) value;
+            }
+        } catch (Exception e) {
+            log.error("将值转换为LocalDate时出错: " + value, e);
+            return null;
+        }
     }
 }

+ 4 - 81
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/bean/influxdb/SensorDataService.java

@@ -1,11 +1,10 @@
 package vip.xiaonuo.coldchain.core.bean.influxdb;
 
 import com.github.jfcloud.influxdb.config.JfcloudInfluxDB2Properties;
+import com.github.jfcloud.influxdb.flux.QueryCondition;
 import com.github.jfcloud.influxdb.service.JfcloudInfluxDBService;
 import com.influxdb.annotations.Column;
 import com.influxdb.annotations.Measurement;
-import com.influxdb.client.QueryApi;
-import com.influxdb.query.FluxTable;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Component;
 import vip.xiaonuo.coldchain.core.config.JfcloudColdChainConstants;
@@ -20,6 +19,7 @@ import java.util.stream.Collectors;
  */
 @Component
 @RequiredArgsConstructor
+@Deprecated
 public class SensorDataService {
 
     private final JfcloudInfluxDBService jfcloudInfluxDBService;
@@ -61,7 +61,7 @@ public class SensorDataService {
      * @param sensorDataClass SensorData 类
      * @return 构建的 Flux 查询语句
      */
-    public String buildFluxQuery(String deviceId, int roads, Instant startTime, Instant endTime, List<SensorQueryCondition> queryConditions, Class<?> sensorDataClass) {
+    public String buildFluxQuery(String deviceId, int roads, Instant startTime, Instant endTime, List<QueryCondition> queryConditions, Class<?> sensorDataClass) {
         StringBuilder fluxQuery = new StringBuilder();
         // 获取 measurement(表名)
         String measurement = getMeasurement(sensorDataClass);
@@ -72,7 +72,7 @@ public class SensorDataService {
                 .append("|> filter(fn: (r) => r._measurement == \"").append(measurement).append("\" and r.device_id == \"").append(deviceId).append("\" and r.roads == ").append(roads).append(") ");
         // 添加自定义查询条件
         if (queryConditions != null) {
-            for (SensorQueryCondition condition : queryConditions) {
+            for (QueryCondition condition : queryConditions) {
                 fluxQuery.append("|> filter(fn: (r) => r._field == \"").append(condition.getField()).append("\" and r._value ").append(condition.getOperator().getOperator()).append(" ").append(condition.getValue()).append(") ");
             }
         }
@@ -80,84 +80,7 @@ public class SensorDataService {
         return fluxQuery.toString();
     }
 
-    /**
-     * 根据 deviceId、roads、时间范围和查询条件查询数据
-     *
-     * @param deviceId        设备 ID
-     * @param roads           路数
-     * @param startTime       查询开始时间
-     * @param endTime         查询结束时间
-     * @param queryConditions 查询条件列表
-     * @return 查询到的传感器数据列表
-     */
-    public List<SensorData> querySensorData(String deviceId, int roads, Instant startTime, Instant endTime, List<SensorQueryCondition> queryConditions) {
-        String fluxQuery = buildFluxQuery(deviceId, roads, startTime, endTime, queryConditions, SensorData.class);
-        QueryApi queryApi = jfcloudInfluxDBService.getInfluxDBClient().getQueryApi();
-        List<FluxTable> tables = queryApi.query(fluxQuery);
-        // 将查询结果映射为 SensorData 实体
-        return tables.stream().flatMap(table -> table.getRecords().stream()).map(SensorData::mapToSensorData).collect(Collectors.toList());
-    }
-
-    /**
-     * 根据 deviceId 和 roads 查询最新的数据
-     *
-     * @param deviceId 设备 ID
-     * @param roads    路数
-     * @return 最新的传感器数据
-     */
-    public SensorData queryLatestDataByDeviceIdAndRoads(String deviceId, Integer roads) {
-        // 构建 Flux 查询,获取最新一条记录
-//        String fluxQuery = String.format(
-//                "from(bucket: \"%s\") " +
-//                        "|> range(start: -30d) " +  // 查询过去 30 天的数据
-//                        "|> filter(fn: (r) => r._measurement == \"%s\" and r[\"device_id\"] == \"%s\" and r[\"roads\"] == \"%s\") " +
-//                        "|> sort(columns: [\"_time\"], desc: true) " +  // 按时间降序排序
-//                        "|> limit(n: 1)",  // 限制查询结果为 1 条
-//                getBucketName(),  // 动态获取桶名
-//                getMeasurement(SensorData.class),  // 动态获取 measurement 名称
-//                deviceId,  // 设备 ID
-//                roads  // 路数
-//        );
-        String fluxQuery = String.format(
-                "from(bucket: \"%s\") " +
-                        "|> range(start: -30d) " +
-                        "|> filter(fn: (r) => r._measurement == \"%s\" and r[\"device_id\"] == \"%s\" and r[\"roads\"] == \"%s\") " +
-                        "|> sort(columns: [\"_time\"], desc: true) " +
-                        "|> limit(n: 1) " +
-                        "|> pivot(rowKey: [\"_time\"], columnKey: [\"_field\"], valueColumn: \"_value\") " +
-                        "|> keep(columns: [\"_time\", \"temperature\", \"humidity\", \"co2\", \"battery\", \"plugInStatus\", \"location\", \"longitude\", \"latitude\", \"device_id\", \"roads\", \"modelName\"])",
-                getBucketName(),
-                getMeasurement(SensorData.class),
-                deviceId,
-                roads
-        );
-        QueryApi queryApi = jfcloudInfluxDBService.getInfluxDBClient().getQueryApi();
-        List<FluxTable> tables = queryApi.query(fluxQuery);
-
-        // 将查询结果映射为 SensorData 实体
-        return tables.stream()
-                .flatMap(table -> table.getRecords().stream())  // 拉平所有记录
-                .map(SensorData::mapToSensorData)  // 将每个记录映射为 SensorData 实体
-                .findFirst()  // 只取第一条记录(即最新一条记录)
-                .orElse(null);  // 如果没有数据,返回 null
-    }
 
-    /**
-     * 根据 deviceId、roads 和时间范围查询数据
-     *
-     * @param deviceId  设备 ID
-     * @param roads     路数
-     * @param startTime 查询开始时间
-     * @param endTime   查询结束时间
-     * @return 查询到的传感器数据列表
-     */
-    public List<SensorData> queryDataByDeviceIdAndRoads(String deviceId, Integer roads, String startTime, String endTime) {
-        String query = String.format("SELECT * FROM \"%s\" WHERE \"device_id\" = '%s' AND \"roads\" = %d AND time >= '%s' AND time <= '%s' ORDER BY time DESC", getMeasurement(SensorData.class), deviceId, roads, startTime, endTime);
-        QueryApi queryApi = jfcloudInfluxDBService.getInfluxDBClient().getQueryApi();
-        List<FluxTable> results = queryApi.query(query);
-        // 将查询结果转换为 SensorData 实体
-        return results.stream().flatMap(table -> table.getRecords().stream()).map(SensorData::mapToSensorData).collect(Collectors.toList());
-    }
 
     /**
      * 获取桶名(通过配置类获取或返回默认桶名)

+ 0 - 32
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/bean/influxdb/SensorQueryCondition.java

@@ -1,32 +0,0 @@
-package vip.xiaonuo.coldchain.core.bean.influxdb;
-
-/**
- * @author jackzhou
- * @version 1.0
- * @project jfcloud-coldchain
- * @description
- * @date 2024/11/22 15:48:29
- */
-public class SensorQueryCondition {
-    private String field;             // 字段名(如 "temperature", "humidity", "co2")
-    private ComparisonOperator operator;  // 比较符号(GT, LT, GTE, LTE)
-    private Double value;             // 查询的阈值
-
-    public SensorQueryCondition(String field, ComparisonOperator operator, Double value) {
-        this.field = field;
-        this.operator = operator;
-        this.value = value;
-    }
-
-    public String getField() {
-        return field;
-    }
-
-    public ComparisonOperator getOperator() {
-        return operator;
-    }
-
-    public Double getValue() {
-        return value;
-    }
-}

+ 0 - 2
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/config/ColdChainAsyncConfig.java

@@ -10,11 +10,9 @@ package vip.xiaonuo.coldchain.core.config;
 
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.scheduling.annotation.EnableAsync;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 
 @Configuration
-@EnableAsync
 public class ColdChainAsyncConfig {
     /**
      * 创建自定义的线程池配置

+ 0 - 2
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/renke/config/JfcloudColdChainServerAutoConfiguration.java

@@ -9,7 +9,6 @@ import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.scheduling.annotation.Async;
-import org.springframework.scheduling.annotation.EnableAsync;
 import rk.netDevice.sdk.p2.IDataListener;
 import rk.netDevice.sdk.p2.RSServer;
 import vip.xiaonuo.coldchain.core.renke.listener.JfcloudColdChainRenKeDefaultDataListener;
@@ -24,7 +23,6 @@ import java.util.concurrent.Executors;
 
 @Configuration
 @EnableConfigurationProperties(JfcloudColdChainServerProperties.class)
-@EnableAsync
 @Slf4j
 public class JfcloudColdChainServerAutoConfiguration {
 

+ 6 - 1
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/core/service/dataprocess/dataclean/impl/AbsRenkeMonitorDataProcessor.java

@@ -132,7 +132,12 @@ public abstract class AbsRenkeMonitorDataProcessor implements MonitorDataProcess
         }
         // 遍历传感器数据列表并发布每个数据的事件
         for (SensorData sensorData : sensorDataList) {
-            if (!writeSensorData(sensorData)) {
+            boolean b = writeSensorData(sensorData);
+            if (b) {
+                RenKeColdChainMessageData renKeColdChainMessageData = new RenKeColdChainMessageData();
+                renKeColdChainMessageData.setDeviceId(Integer.parseInt(sensorData.getDeviceId()));
+                heartbeat(renKeColdChainMessageData);
+            } else {
                 log.error("发布传感器数据事件失败: {}", sensorData);
                 return false;
             }

+ 4 - 3
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/app/param/AppDeviceData.java

@@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
+import lombok.EqualsAndHashCode;
 import vip.xiaonuo.coldchain.core.service.dataprocess.model.PowerEnum;
 import vip.xiaonuo.coldchain.modular.monitortargetregion.entity.MonitorTargetRegion;
 
@@ -16,19 +17,19 @@ import java.util.Date;
  * @description 设备数据类,包含设备的各项监控数据及电源状态
  * @date 2024/11/17 22:39:49
  */
+@EqualsAndHashCode(callSuper = true)
 @Data
 public class AppDeviceData extends MonitorTargetRegion {
-
     @Schema(description = "数据记录的时间")
     private Date timestamp;  // 数据记录的时间
 
     @Schema(description = "设备温度 (℃)")
-    @JsonSerialize(using = DoubleNullToDashSerializer.class)  // 使用自定义序列化器
+    @JsonSerialize(using = FloatNullToDashSerializer.class)  // 使用自定义序列化器
     @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "#.00")
     private Float temperature;  // 温度
 
     @Schema(description = "设备湿度 (%)")
-    @JsonSerialize(using = DoubleNullToDashSerializer.class)  // 使用自定义序列化器
+    @JsonSerialize(using = FloatNullToDashSerializer.class)  // 使用自定义序列化器
     @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "#.00")
     private Float humidity;  // 湿度
 

+ 3 - 1
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/app/service/AppDeviceService.java

@@ -110,7 +110,9 @@ public class AppDeviceService {
                         SensorData sensorData = monitorDeviceService.queryLatestDataByDeviceIdAndRoads(deviceCode, sensorRoute);
                         if (!Objects.isNull(sensorData)) {
                             appDeviceData.setBatteryPercentage(sensorData.getBattery());
-                            appDeviceData.setTimestamp(Date.from(sensorData.getTime()));
+                            if (sensorData.getTime() != null) {
+                                appDeviceData.setTimestamp(Date.from(sensorData.getTime()));
+                            }
                             appDeviceData.setHumidity(sensorData.getHumidity());
                             appDeviceData.setTemperature(sensorData.getTemperature());
                             appDeviceData.setCo2Level(sensorData.getCo2());

+ 2 - 2
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitordevice/service/MonitorDeviceService.java

@@ -14,10 +14,10 @@ package vip.xiaonuo.coldchain.modular.monitordevice.service;
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.github.jfcloud.influxdb.flux.QueryCondition;
 import rk.netDevice.sdk.p2.ParamData;
 import rk.netDevice.sdk.p2.ParamIdsData;
 import vip.xiaonuo.coldchain.core.bean.influxdb.SensorData;
-import vip.xiaonuo.coldchain.core.bean.influxdb.SensorQueryCondition;
 import vip.xiaonuo.coldchain.modular.monitordevice.entity.MonitorDevice;
 import vip.xiaonuo.coldchain.modular.monitordevice.param.MonitorDeviceAddParam;
 import vip.xiaonuo.coldchain.modular.monitordevice.param.MonitorDeviceEditParam;
@@ -97,7 +97,7 @@ public interface MonitorDeviceService extends IService<MonitorDevice> {
 
     SensorData queryLatestDataByDeviceIdAndRoads(String deviceId, Integer sensorRoute);
 
-    List<SensorData> querySensorData(String deviceId, int roads, Instant startTime, Instant endTime, List<SensorQueryCondition> queryConditions);
+    List<SensorData> querySensorData(String deviceId, int roads, Instant startTime, Instant endTime, List<QueryCondition> queryConditions);
 
     List<MonitorDevice> myList(Boolean isAll);
 }

+ 4 - 4
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitordevice/service/impl/MonitorDeviceServiceImpl.java

@@ -21,6 +21,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.github.jfcloud.influxdb.flux.QueryCondition;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -28,10 +29,9 @@ import org.springframework.transaction.annotation.Transactional;
 import rk.netDevice.sdk.p2.ParamData;
 import rk.netDevice.sdk.p2.ParamIdsData;
 import vip.xiaonuo.coldchain.core.bean.influxdb.SensorData;
-import vip.xiaonuo.coldchain.core.bean.influxdb.SensorDataService;
-import vip.xiaonuo.coldchain.core.bean.influxdb.SensorQueryCondition;
 import vip.xiaonuo.coldchain.core.cache.monitordevice.MonitorDeviceCache;
 import vip.xiaonuo.coldchain.core.renke.RenKeService;
+import vip.xiaonuo.coldchain.core.service.JfcloudSensorDataService;
 import vip.xiaonuo.coldchain.modular.monitordevice.entity.MonitorDevice;
 import vip.xiaonuo.coldchain.modular.monitordevice.enums.MonitorDeviceStatusEnum;
 import vip.xiaonuo.coldchain.modular.monitordevice.mapper.MonitorDeviceMapper;
@@ -60,7 +60,7 @@ import java.util.List;
 public class MonitorDeviceServiceImpl extends ServiceImpl<MonitorDeviceMapper, MonitorDevice> implements MonitorDeviceService {
     private final RenKeService renKeService;
     private final MonitorDeviceCache monitorDeviceCache;
-    private final SensorDataService sensorDataService;
+    private final JfcloudSensorDataService sensorDataService;
 
     private String bucketName;
 
@@ -227,7 +227,7 @@ public class MonitorDeviceServiceImpl extends ServiceImpl<MonitorDeviceMapper, M
     }
 
     @Override
-    public List<SensorData> querySensorData(String deviceId, int roads, Instant startTime, Instant endTime, List<SensorQueryCondition> queryConditions) {
+    public List<SensorData> querySensorData(String deviceId, int roads, Instant startTime, Instant endTime, List<QueryCondition> queryConditions) {
 //        return sensorDataService.querySensorData(deviceId, roads, startTime, endTime, queryConditions);
         return null;
     }

+ 2 - 4
snowy-plugin/snowy-plugin-coldchain/src/main/java/vip/xiaonuo/coldchain/modular/monitortargetregion/service/impl/MonitorTargetRegionServiceImpl.java

@@ -17,9 +17,7 @@ import cn.hutool.core.collection.CollStreamUtil;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.lang.tree.Tree;
 import cn.hutool.core.lang.tree.TreeNode;
-import cn.hutool.core.lang.tree.TreeNodeConfig;
 import cn.hutool.core.lang.tree.TreeUtil;
-import cn.hutool.core.lang.tree.parser.DefaultNodeParser;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONUtil;
@@ -189,9 +187,9 @@ public class MonitorTargetRegionServiceImpl extends ServiceImpl<MonitorTargetReg
     }
 
     @Override
-    public List<String> getTargetIdListByDeviceId(String deviceId) {
+    public List<String> getTargetIdListByDeviceId(String deviceCode) {
         LambdaQueryWrapper<MonitorTargetRegion> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.eq(MonitorTargetRegion::getMonitorDeviceId,deviceId);
+        queryWrapper.eq(MonitorTargetRegion::getDeviceCode,deviceCode);
         List<String> targetIdList = new ArrayList<>();
         for (MonitorTargetRegion monitorTargetRegion : list(queryWrapper)) {
             targetIdList.add(monitorTargetRegion.getMonitorTargetId());

+ 2 - 0
snowy-web-app/src/main/java/vip/xiaonuo/Application.java

@@ -19,6 +19,7 @@ import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.core.env.Environment;
+import org.springframework.scheduling.annotation.EnableAsync;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RestController;
 
@@ -31,6 +32,7 @@ import org.springframework.web.bind.annotation.RestController;
 @Slf4j
 @RestController
 @SpringBootApplication(scanBasePackages = {"vip.xiaonuo","com.github.jfcloud"})
+@EnableAsync
 public class Application {
 
     /* 解决druid 日志报错:discard long time none received connection:xxx */

+ 45 - 25
snowy-web-app/src/main/java/vip/xiaonuo/core/config/GlobalTrimAdvice.java

@@ -1,44 +1,64 @@
 package vip.xiaonuo.core.config;
 
-/**
- * @author jackzhou
- * @version 1.0
- * @project jfcloud-coldchain
- * @description
- * @date 2024/11/25 10:25:14
- */
 import lombok.SneakyThrows;
-import org.springframework.stereotype.Component;
-import org.springframework.web.bind.annotation.ControllerAdvice;
 import org.springframework.web.bind.annotation.ModelAttribute;
 
 import java.lang.reflect.Field;
+import java.util.Collection;
+import java.util.Map;
 
-/**
- * 全局去掉请求参数中 String 类型字段的前后空格
- */
-@ControllerAdvice
-@Component
+//@ControllerAdvice
+//@Component
 public class GlobalTrimAdvice {
 
-    @ModelAttribute
     @SneakyThrows
+    @ModelAttribute
     public void trimStrings(Object model) {
-        // 获取当前model的所有字段
+        // 如果model是null,直接返回
+        if (model == null) {
+            return;
+        }
+        // 处理模型中的所有字段
+        trimFields(model);
+        // 如果有嵌套对象或集合,递归处理
+        handleNestedObjects(model);
+    }
+
+    // 递归遍历对象字段并去掉首尾空格
+    @SneakyThrows
+    private void trimFields(Object model) {
         Field[] fields = model.getClass().getDeclaredFields();
         for (Field field : fields) {
-            // 如果字段是String类型
+            field.setAccessible(true); // 设置字段可访问
             if (field.getType().equals(String.class)) {
-                try {
-                    field.setAccessible(true); // 设置字段可访问
-                    String value = (String) field.get(model);
-                    // 去除前后空格
-                    if (value != null) {
-                        field.set(model, value.trim());
-                    }
-                } catch (IllegalAccessException e) {
+                String value = (String) field.get(model);
+                if (value != null) {
+                    field.set(model, value.trim());
                 }
             }
         }
     }
+
+    // 递归处理嵌套对象或集合
+    private void handleNestedObjects(Object model) {
+        if (model == null) {
+            return;
+        }
+        // 如果对象是一个集合,递归遍历每个元素
+        if (model instanceof Collection) {
+            for (Object element : (Collection<?>) model) {
+                handleNestedObjects(element);
+            }
+        }
+        // 如果对象是一个Map,递归遍历每个键值对
+        else if (model instanceof Map) {
+            for (Map.Entry<?, ?> entry : ((Map<?, ?>) model).entrySet()) {
+                handleNestedObjects(entry.getValue());
+            }
+        }
+        // 如果对象是一个普通JavaBean,递归遍历它的字段
+        else {
+            trimFields(model);
+        }
+    }
 }