From 1ad4e08cb83ce4b1d1fdeb53df07715de44bd9a3 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 23 Jun 2025 08:52:57 +0800 Subject: [PATCH 01/33] =?UTF-8?q?reactor=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E5=A2=9E=E5=8A=A0=20IotRuleScene2DO?= =?UTF-8?q?=20=E6=96=B0=E7=9A=84=E5=AE=9A=E4=B9=89=EF=BC=8C=E5=AF=B9?= =?UTF-8?q?=E6=A0=87=E9=98=BF=E9=87=8C=E4=BA=91=20IoT=20=E7=9A=84=E3=80=8C?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E5=93=8D=E5=BA=94=E3=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../device/IotDeviceMessageTypeEnum.java | 1 + .../rule/IotRuleSceneActionTypeEnum.java | 27 +- ...=> IotRuleSceneConditionOperatorEnum.java} | 26 +- .../rule/IotRuleSceneConditionTypeEnum.java | 35 +++ .../rule/IotRuleSceneTriggerTypeEnum.java | 37 ++- ...AlertConfig.java => IotAlertConfigDO.java} | 2 +- .../dal/dataobject/rule/IotAlertRecordDO.java | 4 +- .../dal/dataobject/rule/IotRuleScene2DO.java | 241 ++++++++++++++++++ .../dal/dataobject/rule/IotRuleSceneDO.java | 8 +- .../service/rule/IotRuleSceneServiceImpl.java | 58 ++--- .../IotRuleSceneDeviceControlAction.java | 2 +- .../enums/IotDeviceMessageMethodEnum.java | 3 + 12 files changed, 399 insertions(+), 45 deletions(-) rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/{IotRuleSceneTriggerConditionParameterOperatorEnum.java => IotRuleSceneConditionOperatorEnum.java} (59%) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionTypeEnum.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/{IotAlertConfig.java => IotAlertConfigDO.java} (97%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleScene2DO.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java index 0354157ed4..9131210ab2 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java @@ -9,6 +9,7 @@ import java.util.Arrays; /** * IoT 设备消息类型枚举 */ +@Deprecated @Getter @RequiredArgsConstructor public enum IotDeviceMessageTypeEnum implements ArrayValuable { diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java index 2bdf7d0ede..6e6843b093 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java @@ -15,8 +15,33 @@ import java.util.Arrays; @Getter public enum IotRuleSceneActionTypeEnum implements ArrayValuable { - DEVICE_CONTROL(1), // 设备执行 + // TODO @芋艿:后续“对应”部分,要 @下,等包结构梳理完; + /** + * 设备属性设置 + * + * 对应 IotDeviceMessageMethodEnum.DEVICE_PROPERTY_SET + */ + DEVICE_PROPERTY_SET(1), + /** + * 设备服务调用 + * + * 对应 IotDeviceMessageMethodEnum.DEVICE_SERVICE_INVOKE + */ + DEVICE_SERVICE_INVOKE(2), + + /** + * 告警触发 + */ + ALERT_TRIGGER(100), + /** + * 告警恢复 + */ + ALERT_RECOVER(101), + + @Deprecated ALERT(2), // 告警执行 + + @Deprecated DATA_BRIDGE(3); // 桥接执行 private final Integer type; diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerConditionParameterOperatorEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionOperatorEnum.java similarity index 59% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerConditionParameterOperatorEnum.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionOperatorEnum.java index 952e504412..f9debc9ca9 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerConditionParameterOperatorEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionOperatorEnum.java @@ -8,13 +8,13 @@ import lombok.RequiredArgsConstructor; import java.util.Arrays; /** - * IoT 场景触发条件参数的操作符枚举 + * IoT 场景触发条件的操作符枚举 * * @author 芋道源码 */ @RequiredArgsConstructor @Getter -public enum IotRuleSceneTriggerConditionParameterOperatorEnum implements ArrayValuable { +public enum IotRuleSceneConditionOperatorEnum implements ArrayValuable { EQUALS("=", "#source == #value"), NOT_EQUALS("!=", "!(#source == #value)"), @@ -32,12 +32,28 @@ public enum IotRuleSceneTriggerConditionParameterOperatorEnum implements ArrayVa NOT_BETWEEN("not between", "(#source < #values.get(0)) || (#source > #values.get(1))"), LIKE("like", "#source.contains(#value)"), // 字符串匹配 - NOT_NULL("not null", "#source != null && #source.length() > 0"); // 非空 + NOT_NULL("not null", "#source != null && #source.length() > 0"), // 非空 + + // ========== 特殊:不放在字典里 ========== + + // TODO @puhui999:@芋艿:需要测试下 + DATE_TIME_GREATER_THAN("date_time_>", "#source > #value"), // 在时间之后:时间戳 + DATE_TIME_LESS_THAN("date_time_<", "#source < #value"), // 在时间之前:时间戳 + DATE_TIME_BETWEEN("date_time_between", // 在时间之间:时间戳 + "(#source >= #values.get(0)) && (#source <= #values.get(1))"), + + // TODO @puhui999:@芋艿:需要测试下 + TIME_GREATER_THAN("time_>", "#source.isAfter(#value)"), // 在当日时间之后:HH:mm:ss + TIME_LESS_THAN("time_<", "#source.isBefore(#value)"), // 在当日时间之前:HH:mm:ss + TIME_BETWEEN("time_between", // 在当日时间之间:HH:mm:ss + "(#source >= #values.get(0)) && (#source <= #values.get(1))"), + + ; private final String operator; private final String springExpression; - public static final String[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneTriggerConditionParameterOperatorEnum::getOperator).toArray(String[]::new); + public static final String[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneConditionOperatorEnum::getOperator).toArray(String[]::new); /** * Spring 表达式 - 原始值 @@ -52,7 +68,7 @@ public enum IotRuleSceneTriggerConditionParameterOperatorEnum implements ArrayVa */ public static final String SPRING_EXPRESSION_VALUE_LIST = "values"; - public static IotRuleSceneTriggerConditionParameterOperatorEnum operatorOf(String operator) { + public static IotRuleSceneConditionOperatorEnum operatorOf(String operator) { return ArrayUtil.firstMatch(item -> item.getOperator().equals(operator), values()); } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionTypeEnum.java new file mode 100644 index 0000000000..031976dc60 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionTypeEnum.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.iot.enums.rule; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * IoT 条件类型枚举 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Getter +public enum IotRuleSceneConditionTypeEnum implements ArrayValuable { + + DEVICE_STATE(1, "设备状态"), + DEVICE_PROPERTY(2, "设备属性"), + + CURRENT_TIME(100, "当前时间"), + + ; + + private final Integer type; + private final String name; + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneConditionTypeEnum::getType).toArray(Integer[]::new); + + @Override + public Integer[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java index a420a21d5b..e40bb2e7e1 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java @@ -9,14 +9,47 @@ import java.util.Arrays; /** * IoT 场景流转的触发类型枚举 * + * 为什么不直接使用 IotDeviceMessageMethodEnum 呢? + * 原因是,物模型属性上报,存在批量上报的情况,不只对应一个 method!!! + * * @author 芋道源码 */ @RequiredArgsConstructor @Getter public enum IotRuleSceneTriggerTypeEnum implements ArrayValuable { - DEVICE(1), // 设备触发 - TIMER(2); // 定时触发 + @Deprecated + DEVICE(1), // 设备触发 // TODO @puhui999:@芋艿:这个可以作废 + + // TODO @芋艿:后续“对应”部分,要 @下,等包结构梳理完; + /** + * 设备上下线变更 + * + * 对应 IotDeviceMessageMethodEnum.STATE_UPDATE + */ + DEVICE_STATE_UPDATE(1), + /** + * 物模型属性上报 + * + * 对应 IotDeviceMessageMethodEnum.DEVICE_PROPERTY_POST + */ + DEVICE_PROPERTY_POST(2), + /** + * 设备事件上报 + * + * 对应 IotDeviceMessageMethodEnum.DEVICE_EVENT_POST + */ + DEVICE_EVENT_POST(3), + /** + * 设备服务调用 + * + * 对应 IotDeviceMessageMethodEnum.DEVICE_SERVICE_INVOKE + */ + DEVICE_SERVICE_INVOKE(4), + + TIMER(100) // 定时触发 + + ; private final Integer type; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertConfigDO.java similarity index 97% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertConfig.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertConfigDO.java index c6a2390ac3..14e7d741fe 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertConfigDO.java @@ -23,7 +23,7 @@ import java.util.List; @Builder @NoArgsConstructor @AllArgsConstructor -public class IotAlertConfig extends BaseDO { +public class IotAlertConfigDO extends BaseDO { /** * 配置编号 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertRecordDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertRecordDO.java index d6e002e6a7..43a1c6360f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertRecordDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertRecordDO.java @@ -34,13 +34,13 @@ public class IotAlertRecordDO extends BaseDO { /** * 告警名称 * - * 冗余 {@link IotAlertConfig#getName()} + * 冗余 {@link IotAlertConfigDO#getName()} */ private Long configId; /** * 告警名称 * - * 冗余 {@link IotAlertConfig#getName()} + * 冗余 {@link IotAlertConfigDO#getName()} */ private String name; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleScene2DO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleScene2DO.java new file mode 100644 index 0000000000..5b6a3b5e42 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleScene2DO.java @@ -0,0 +1,241 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.rule; + +import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionOperatorEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +// TODO @puhui999:还是在 IotRuleSceneDO 里搞,这里主要可以看到变化字段哈。 +/** + * IoT 场景联动 DO + * + * @author 芋道源码 + */ +@TableName(value = "iot_rule_scene2", autoResultMap = true) +@KeySequence("iot_rule_scene_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IotRuleScene2DO extends TenantBaseDO { + + /** + * 设备编号 - 全部设备 + */ + public static final Long DEVICE_ID_ALL = 0L; + + /** + * 场景编号 + */ + @TableId + private Long id; + /** + * 场景名称 + */ + private String name; + /** + * 场景描述 + */ + private String description; + /** + * 场景状态 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + + /** + * 场景定义配置 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List triggers; + + /** + * 场景动作配置 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List actions; + + /** + * 场景定义配置 + */ + @Data + public static class Trigger { + + // ========== 事件部分 ========== + + /** + * 场景事件类型 + * + * 枚举 {@link IotRuleSceneTriggerTypeEnum} + * 1. {@link IotRuleSceneTriggerTypeEnum#DEVICE_STATE_UPDATE} 时,operator 非空,并且 value 为在线状态 + * 2. {@link IotRuleSceneTriggerTypeEnum#DEVICE_PROPERTY_POST} + * {@link IotRuleSceneTriggerTypeEnum#DEVICE_EVENT_POST} 时,identifier、operator 非空,并且 value 为属性值 + * 3. {@link IotRuleSceneTriggerTypeEnum#DEVICE_EVENT_POST} + * {@link IotRuleSceneTriggerTypeEnum#DEVICE_SERVICE_INVOKE} 时,identifier 非空,但是 operator、value 为空 + * 4. {@link IotRuleSceneTriggerTypeEnum#TIMER} 时,conditions 非空,并且设备无关(无需 productId、deviceId 字段) + */ + private Integer type; + + /** + * 产品编号 + * + * 关联 {@link IotProductDO#getId()} + */ + private Long productId; + /** + * 设备编号 + * + * 关联 {@link IotDeviceDO#getId()} + * 特殊:如果为 0,则是全部 + */ + private Long deviceId; + /** + * 物模型标识符 + * + * 对应:{@link IotThingModelDO#getIdentifier()} + */ + private String identifier; + /** + * 操作符 + * + * 枚举 {@link IotRuleSceneConditionOperatorEnum} + */ + private String operator; + /** + * 参数(属性值、在线状态) + * + * 如果有多个值,则使用 "," 分隔,类似 "1,2,3"。 + * 例如说,{@link IotRuleSceneConditionOperatorEnum#IN}、{@link IotRuleSceneConditionOperatorEnum#BETWEEN} + */ + private String value; + + /** + * CRON 表达式 + */ + private String cronExpression; + + // ========== 条件部分 ========== + + /** + * 触发条件分组(状态条件分组)的数组 + * + * 第一层 List:分组与分组之间,是“或”的关系 + * 第二层 List:条件与条件之间,是“且”的关系 + */ + private List> conditionGroups; + + } + + /** + * 触发条件(状态条件) + */ + @Data + public static class TriggerCondition { + + /** + * 触发条件类型 + * + * 枚举 {@link IotRuleSceneConditionTypeEnum} + * 1. {@link IotRuleSceneConditionTypeEnum#DEVICE_STATE} 时,operator 非空,并且 value 为在线状态 + * 2. {@link IotRuleSceneConditionTypeEnum#DEVICE_PROPERTY} 时,identifier、operator 非空,并且 value 为属性值 + * 3. {@link IotRuleSceneConditionTypeEnum#CURRENT_TIME} 时,operator 非空(使用 DATE_TIME_ 和 TIME_ 部分),并且 value 非空 + */ + private Integer type; + + /** + * 产品编号 + * + * 关联 {@link IotProductDO#getId()} + */ + private Long productId; + /** + * 设备编号 + * + * 关联 {@link IotDeviceDO#getId()} + */ + private Long deviceId; + /** + * 标识符(属性) + * + * 关联 {@link IotThingModelDO#getIdentifier()} + */ + private String identifier; + /** + * 操作符 + * + * 枚举 {@link IotRuleSceneConditionOperatorEnum} + */ + private String operator; + /** + * 参数 + * + * 如果有多个值,则使用 "," 分隔,类似 "1,2,3"。 + * 例如说,{@link IotRuleSceneConditionOperatorEnum#IN}、{@link IotRuleSceneConditionOperatorEnum#BETWEEN} + */ + private String param; + + } + + /** + * 场景动作配置 + */ + @Data + public static class Action { + + /** + * 执行类型 + * + * 枚举 {@link IotRuleSceneActionTypeEnum} + * 1. {@link IotRuleSceneActionTypeEnum#DEVICE_PROPERTY_SET} 时,params 非空 + * {@link IotRuleSceneActionTypeEnum#DEVICE_SERVICE_INVOKE} 时,params 非空 + * 2. {@link IotRuleSceneActionTypeEnum#ALERT_TRIGGER} 时,alertConfigId 为空,因为是 {@link IotAlertConfigDO} 里面关联它 + * 3. {@link IotRuleSceneActionTypeEnum#ALERT_RECOVER} 时,alertConfigId 非空 + */ + private Integer type; + + /** + * 产品编号 + * + * 关联 {@link IotProductDO#getId()} + */ + private Long productId; + /** + * 设备编号 + * + * 关联 {@link IotDeviceDO#getId()} + */ + private Long deviceId; + /** + * 请求参数 + * + * 一般来说,对应 {@link IotDeviceMessage#getParams()} 请求参数 + */ + private Object params; + + /** + * 告警配置编号 + * + * 关联 {@link IotAlertConfigDO#getId()} + */ + private Long alertConfigId; + + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java index f8f3382930..c2ccbdd650 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java @@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerConditionParameterOperatorEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionOperatorEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; @@ -163,7 +163,7 @@ public class IotRuleSceneDO extends TenantBaseDO { /** * 操作符 * - * 枚举 {@link IotRuleSceneTriggerConditionParameterOperatorEnum} + * 枚举 {@link IotRuleSceneConditionOperatorEnum} */ private String operator; @@ -171,7 +171,7 @@ public class IotRuleSceneDO extends TenantBaseDO { * 比较值 * * 如果有多个值,则使用 "," 分隔,类似 "1,2,3"。 - * 例如说,{@link IotRuleSceneTriggerConditionParameterOperatorEnum#IN}、{@link IotRuleSceneTriggerConditionParameterOperatorEnum#BETWEEN} + * 例如说,{@link IotRuleSceneConditionOperatorEnum#IN}、{@link IotRuleSceneConditionOperatorEnum#BETWEEN} */ private String value; @@ -193,7 +193,7 @@ public class IotRuleSceneDO extends TenantBaseDO { /** * 设备控制 * - * 必填:当 {@link #type} 为 {@link IotRuleSceneActionTypeEnum#DEVICE_CONTROL} 时 + * 必填:当 {@link #type} 为 {@link IotRuleSceneActionTypeEnum#DEVICE_PROPERTY_SET} 时 */ private ActionDeviceControl deviceControl; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java index 64982a8b2f..2553cdc240 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java @@ -23,7 +23,7 @@ import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotRuleSceneMapper; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerConditionParameterOperatorEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionOperatorEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager; import cn.iocoder.yudao.module.iot.job.rule.IotRuleSceneJob; @@ -127,57 +127,57 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { condition01.setParameters(CollUtil.newArrayList()); // IotRuleSceneDO.TriggerConditionParameter parameter010 = new IotRuleSceneDO.TriggerConditionParameter(); // parameter010.setIdentifier("width"); -// parameter010.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS.getOperator()); +// parameter010.setOperator(IotRuleSceneConditionOperatorEnum.EQUALS.getOperator()); // parameter010.setValue("abc"); // condition01.getParameters().add(parameter010); IotRuleSceneDO.TriggerConditionParameter parameter011 = new IotRuleSceneDO.TriggerConditionParameter(); parameter011.setIdentifier("width"); - parameter011.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS.getOperator()); + parameter011.setOperator(IotRuleSceneConditionOperatorEnum.EQUALS.getOperator()); parameter011.setValue("1"); condition01.getParameters().add(parameter011); IotRuleSceneDO.TriggerConditionParameter parameter012 = new IotRuleSceneDO.TriggerConditionParameter(); parameter012.setIdentifier("width"); - parameter012.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_EQUALS.getOperator()); + parameter012.setOperator(IotRuleSceneConditionOperatorEnum.NOT_EQUALS.getOperator()); parameter012.setValue("2"); condition01.getParameters().add(parameter012); IotRuleSceneDO.TriggerConditionParameter parameter013 = new IotRuleSceneDO.TriggerConditionParameter(); parameter013.setIdentifier("width"); - parameter013.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN.getOperator()); + parameter013.setOperator(IotRuleSceneConditionOperatorEnum.GREATER_THAN.getOperator()); parameter013.setValue("0"); condition01.getParameters().add(parameter013); IotRuleSceneDO.TriggerConditionParameter parameter014 = new IotRuleSceneDO.TriggerConditionParameter(); parameter014.setIdentifier("width"); - parameter014.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN_OR_EQUALS.getOperator()); + parameter014.setOperator(IotRuleSceneConditionOperatorEnum.GREATER_THAN_OR_EQUALS.getOperator()); parameter014.setValue("0"); condition01.getParameters().add(parameter014); IotRuleSceneDO.TriggerConditionParameter parameter015 = new IotRuleSceneDO.TriggerConditionParameter(); parameter015.setIdentifier("width"); - parameter015.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN.getOperator()); + parameter015.setOperator(IotRuleSceneConditionOperatorEnum.LESS_THAN.getOperator()); parameter015.setValue("2"); condition01.getParameters().add(parameter015); IotRuleSceneDO.TriggerConditionParameter parameter016 = new IotRuleSceneDO.TriggerConditionParameter(); parameter016.setIdentifier("width"); - parameter016.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN_OR_EQUALS.getOperator()); + parameter016.setOperator(IotRuleSceneConditionOperatorEnum.LESS_THAN_OR_EQUALS.getOperator()); parameter016.setValue("2"); condition01.getParameters().add(parameter016); IotRuleSceneDO.TriggerConditionParameter parameter017 = new IotRuleSceneDO.TriggerConditionParameter(); parameter017.setIdentifier("width"); - parameter017.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.IN.getOperator()); + parameter017.setOperator(IotRuleSceneConditionOperatorEnum.IN.getOperator()); parameter017.setValue("1,2,3"); condition01.getParameters().add(parameter017); IotRuleSceneDO.TriggerConditionParameter parameter018 = new IotRuleSceneDO.TriggerConditionParameter(); parameter018.setIdentifier("width"); - parameter018.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_IN.getOperator()); + parameter018.setOperator(IotRuleSceneConditionOperatorEnum.NOT_IN.getOperator()); parameter018.setValue("0,2,3"); condition01.getParameters().add(parameter018); IotRuleSceneDO.TriggerConditionParameter parameter019 = new IotRuleSceneDO.TriggerConditionParameter(); parameter019.setIdentifier("width"); - parameter019.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.BETWEEN.getOperator()); + parameter019.setOperator(IotRuleSceneConditionOperatorEnum.BETWEEN.getOperator()); parameter019.setValue("1,3"); condition01.getParameters().add(parameter019); IotRuleSceneDO.TriggerConditionParameter parameter020 = new IotRuleSceneDO.TriggerConditionParameter(); parameter020.setIdentifier("width"); - parameter020.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_BETWEEN.getOperator()); + parameter020.setOperator(IotRuleSceneConditionOperatorEnum.NOT_BETWEEN.getOperator()); parameter020.setValue("2,3"); condition01.getParameters().add(parameter020); trigger01.getConditions().add(condition01); @@ -194,7 +194,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { condition03.setParameters(CollUtil.newArrayList()); IotRuleSceneDO.TriggerConditionParameter parameter030 = new IotRuleSceneDO.TriggerConditionParameter(); parameter030.setIdentifier("width"); - parameter030.setOperator(IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS.getOperator()); + parameter030.setOperator(IotRuleSceneConditionOperatorEnum.EQUALS.getOperator()); parameter030.setValue("1"); trigger01.getConditions().add(condition03); ruleScene01.getTriggers().add(trigger01); @@ -202,7 +202,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { ruleScene01.setActions(CollUtil.newArrayList()); // 设备控制 IotRuleSceneDO.ActionConfig action01 = new IotRuleSceneDO.ActionConfig(); - action01.setType(IotRuleSceneActionTypeEnum.DEVICE_CONTROL.getType()); + action01.setType(IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET.getType()); IotRuleSceneDO.ActionDeviceControl actionDeviceControl01 = new IotRuleSceneDO.ActionDeviceControl(); actionDeviceControl01.setProductKey("4aymZgOTOOCrDKRT"); actionDeviceControl01.setDeviceNames(ListUtil.of("small")); @@ -266,7 +266,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { scene.setTriggers(ListUtil.toList(triggerConfig)); // 动作 IotRuleSceneDO.ActionConfig action01 = new IotRuleSceneDO.ActionConfig(); - action01.setType(IotRuleSceneActionTypeEnum.DEVICE_CONTROL.getType()); + action01.setType(IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET.getType()); IotRuleSceneDO.ActionDeviceControl iotRuleSceneActionDeviceControl01 = new IotRuleSceneDO.ActionDeviceControl(); iotRuleSceneActionDeviceControl01.setProductKey("4aymZgOTOOCrDKRT"); iotRuleSceneActionDeviceControl01.setDeviceNames(ListUtil.of("small")); @@ -366,8 +366,8 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { private boolean isTriggerConditionParameterMatched(IotDeviceMessage message, IotRuleSceneDO.TriggerConditionParameter parameter, IotRuleSceneDO ruleScene, IotRuleSceneDO.TriggerConfig trigger) { // 1.1 校验操作符是否合法 - IotRuleSceneTriggerConditionParameterOperatorEnum operator = - IotRuleSceneTriggerConditionParameterOperatorEnum.operatorOf(parameter.getOperator()); + IotRuleSceneConditionOperatorEnum operator = + IotRuleSceneConditionOperatorEnum.operatorOf(parameter.getOperator()); if (operator == null) { log.error("[isTriggerConditionParameterMatched][规则场景编号({}) 的触发器({}) 存在错误的操作符({})]", ruleScene.getId(), trigger, parameter.getOperator()); @@ -382,24 +382,24 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { // 2.1 构建 Spring 表达式的变量 Map springExpressionVariables = new HashMap<>(); try { - springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_SOURCE, messageValue); - springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE, parameter.getValue()); + springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, messageValue); + springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE, parameter.getValue()); List parameterValues = StrUtil.splitTrim(parameter.getValue(), CharPool.COMMA); - springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, parameterValues); + springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, parameterValues); // 特殊:解决数字的比较。因为 Spring 是基于它的 compareTo 方法,对数字的比较存在问题! - if (ObjectUtils.equalsAny(operator, IotRuleSceneTriggerConditionParameterOperatorEnum.BETWEEN, - IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_BETWEEN, - IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN, - IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN_OR_EQUALS, - IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN, - IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN_OR_EQUALS) + if (ObjectUtils.equalsAny(operator, IotRuleSceneConditionOperatorEnum.BETWEEN, + IotRuleSceneConditionOperatorEnum.NOT_BETWEEN, + IotRuleSceneConditionOperatorEnum.GREATER_THAN, + IotRuleSceneConditionOperatorEnum.GREATER_THAN_OR_EQUALS, + IotRuleSceneConditionOperatorEnum.LESS_THAN, + IotRuleSceneConditionOperatorEnum.LESS_THAN_OR_EQUALS) && NumberUtil.isNumber(messageValue) && NumberUtils.isAllNumber(parameterValues)) { - springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_SOURCE, + springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, NumberUtil.parseDouble(messageValue)); - springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE, + springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE, NumberUtil.parseDouble(parameter.getValue())); - springExpressionVariables.put(IotRuleSceneTriggerConditionParameterOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, + springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, convertList(parameterValues, NumberUtil::parseDouble)); } // 2.2 计算 Spring 表达式 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDeviceControlAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDeviceControlAction.java index 0ae4f4bc0d..a967c3d65a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDeviceControlAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDeviceControlAction.java @@ -49,7 +49,7 @@ public class IotRuleSceneDeviceControlAction implements IotRuleSceneAction { @Override public IotRuleSceneActionTypeEnum getType() { - return IotRuleSceneActionTypeEnum.DEVICE_CONTROL; + return IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET; } } diff --git a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums/IotDeviceMessageMethodEnum.java b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums/IotDeviceMessageMethodEnum.java index 04b342346d..92fe71f033 100644 --- a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums/IotDeviceMessageMethodEnum.java +++ b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums/IotDeviceMessageMethodEnum.java @@ -19,9 +19,12 @@ public enum IotDeviceMessageMethodEnum implements ArrayValuable { // ========== 设备状态 ========== + // TODO @芋艿:要合并下;thing.state.update STATE_ONLINE("thing.state.online", "设备上线", true), STATE_OFFLINE("thing.state.offline", "设备下线", true), + STATE_UPDATE("thing.state.update", "设备状态更新", true), + // ========== 设备属性 ========== // 可参考:https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services From 1f5dff77c2befefb60e7b7de36975a9ddca0a2cd Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 23 Jun 2025 09:35:21 +0800 Subject: [PATCH 02/33] =?UTF-8?q?reactor=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E5=A2=9E=E5=8A=A0=20IotDataRuleDO?= =?UTF-8?q?=20=E7=9A=84=E5=AE=9A=E4=B9=89=EF=BC=8C=E5=AF=B9=E6=A0=87?= =?UTF-8?q?=E9=98=BF=E9=87=8C=E4=BA=91=20IoT=20=E7=9A=84=E3=80=8C=E4=BA=91?= =?UTF-8?q?=E4=BA=A7=E5=93=81=E6=B5=81=E8=BD=AC=E3=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...Enum.java => IotDataRuleSinkTypeEnum.java} | 6 +- .../admin/rule/IotDataBridgeController.java | 8 +- .../vo/databridge/IotDataBridgeSaveReqVO.java | 4 +- .../config/IotDataBridgeAbstractConfig.java | 4 +- .../dal/dataobject/device/IotDeviceDO.java | 5 ++ .../dal/dataobject/rule/IotDataRuleDO.java | 62 +++++++++++++++ ...taBridgeDO.java => IotDataRuleSinkDO.java} | 20 ++--- .../dataobject/rule/IotDataRuleSourceDO.java | 79 +++++++++++++++++++ .../dal/dataobject/rule/IotRuleSceneDO.java | 2 +- ...tRuleScene2DO.java => IotSceneRuleDO.java} | 26 +++--- .../dal/mysql/rule/IotDataBridgeMapper.java | 24 +++--- .../service/rule/IotDataBridgeService.java | 8 +- .../rule/IotDataBridgeServiceImpl.java | 12 +-- .../action/IotRuleSceneDataBridgeAction.java | 4 +- .../AbstractCacheableDataBridgeExecute.java | 4 +- .../databridge/IotDataBridgeExecute.java | 4 +- .../databridge/IotHttpDataBridgeExecute.java | 4 +- .../IotKafkaMQDataBridgeExecute.java | 4 +- .../IotRabbitMQDataBridgeExecute.java | 4 +- .../IotRedisStreamDataBridgeExecute.java | 4 +- .../IotRocketMQDataBridgeExecute.java | 4 +- .../databridge/IotDataBridgeExecuteTest.java | 8 +- 22 files changed, 223 insertions(+), 77 deletions(-) rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/{IotDataBridgeTypeEnum.java => IotDataRuleSinkTypeEnum.java} (79%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleDO.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/{IotDataBridgeDO.java => IotDataRuleSinkDO.java} (78%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleSourceDO.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/{IotRuleScene2DO.java => IotSceneRuleDO.java} (93%) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataRuleSinkTypeEnum.java similarity index 79% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeTypeEnum.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataRuleSinkTypeEnum.java index 78fc8452eb..824dc78f0e 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataRuleSinkTypeEnum.java @@ -7,13 +7,13 @@ import lombok.RequiredArgsConstructor; import java.util.Arrays; /** - * IoT 数据桥接的类型枚举 + * IoT 数据流转的数据目的的类型枚举 * * @author 芋道源码 */ @RequiredArgsConstructor @Getter -public enum IotDataBridgeTypeEnum implements ArrayValuable { +public enum IotDataRuleSinkTypeEnum implements ArrayValuable { HTTP(1, "HTTP"), TCP(2, "TCP"), @@ -32,7 +32,7 @@ public enum IotDataBridgeTypeEnum implements ArrayValuable { private final String name; - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataBridgeTypeEnum::getType).toArray(Integer[]::new); + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataRuleSinkTypeEnum::getType).toArray(Integer[]::new); @Override public Integer[] array() { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java index b4839144f0..90ff2dba91 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java @@ -7,7 +7,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgePageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgeRespVO; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgeSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleSinkDO; import cn.iocoder.yudao.module.iot.service.rule.IotDataBridgeService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -61,7 +61,7 @@ public class IotDataBridgeController { @Parameter(name = "id", description = "编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('iot:data-bridge:query')") public CommonResult getDataBridge(@RequestParam("id") Long id) { - IotDataBridgeDO dataBridge = dataBridgeService.getDataBridge(id); + IotDataRuleSinkDO dataBridge = dataBridgeService.getDataBridge(id); return success(BeanUtils.toBean(dataBridge, IotDataBridgeRespVO.class)); } @@ -69,14 +69,14 @@ public class IotDataBridgeController { @Operation(summary = "获得数据桥梁分页") @PreAuthorize("@ss.hasPermission('iot:data-bridge:query')") public CommonResult> getDataBridgePage(@Valid IotDataBridgePageReqVO pageReqVO) { - PageResult pageResult = dataBridgeService.getDataBridgePage(pageReqVO); + PageResult pageResult = dataBridgeService.getDataBridgePage(pageReqVO); return success(BeanUtils.toBean(pageResult, IotDataBridgeRespVO.class)); } @GetMapping("/simple-list") @Operation(summary = "获取数据桥梁的精简信息列表", description = "主要用于前端的下拉选项") public CommonResult> getSimpleDataBridgeList() { - List list = dataBridgeService.getDataBridgeList(CommonStatusEnum.ENABLE.getStatus()); + List list = dataBridgeService.getDataBridgeList(CommonStatusEnum.ENABLE.getStatus()); return success(convertList(list, dataBridge -> // 只返回 id、name 字段 new IotDataBridgeRespVO().setId(dataBridge.getId()).setName(dataBridge.getName()))); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java index 8441701af8..ba1bfb1959 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeAbstractConfig; import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeDirectionEnum; -import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataRuleSinkTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; @@ -36,7 +36,7 @@ public class IotDataBridgeSaveReqVO { @Schema(description = "桥梁类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotNull(message = "桥梁类型不能为空") - @InEnum(IotDataBridgeTypeEnum.class) + @InEnum(IotDataRuleSinkTypeEnum.class) private Integer type; @Schema(description = "桥梁配置") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java index 7bf714f617..62fa5558cd 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; -import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataRuleSinkTypeEnum; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import lombok.Data; @@ -28,7 +28,7 @@ public abstract class IotDataBridgeAbstractConfig { /** * 配置类型 * - * 枚举 {@link IotDataBridgeTypeEnum#getType()} + * 枚举 {@link IotDataRuleSinkTypeEnum#getType()} */ private String type; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java index a02d2017af..987c6b55ee 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java @@ -28,6 +28,11 @@ import java.util.Set; @AllArgsConstructor public class IotDeviceDO extends TenantBaseDO { + /** + * 设备编号 - 全部设备 + */ + public static final Long DEVICE_ID_ALL = 0L; + /** * 设备 ID,主键,自增 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleDO.java new file mode 100644 index 0000000000..024e71c031 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleDO.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.rule; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * IoT 数据流转 DO + * + * 组合 {@link IotDataRuleSourceDO} => {@link IotDataRuleSinkDO} + * + * @author 芋道源码 + */ +@TableName(value = "iot_data_flow", autoResultMap = true) +@KeySequence("iot_data_flow_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IotDataRuleDO { + + /** + * 数据流转编号 + */ + private Long id; + /** + * 数据流转名称 + */ + private String name; + /** + * 数据流转描述 + */ + private String description; + /** + * 数据流转状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; + + /** + * 数据源编号 + * + * 关联 {@link IotDataRuleSourceDO#getId()} + */ + private List sourceIds; + /** + * 数据目的编号 + * + * 关联 {@link IotDataRuleSinkDO#getId()} + */ + private List sinkIds; + + // TODO @芋艿:未来考虑使用 groovy;支持数据处理; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleSinkDO.java similarity index 78% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleSinkDO.java index fed4298720..1214e710d3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataBridgeDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleSinkDO.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeAbstractConfig; import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeDirectionEnum; -import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataRuleSinkTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; @@ -13,7 +13,7 @@ import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import lombok.*; /** - * IoT 数据桥梁 DO + * IoT 数据流转的数据目的 DO * * @author 芋道源码 */ @@ -23,19 +23,19 @@ import lombok.*; @Builder @NoArgsConstructor @AllArgsConstructor -public class IotDataBridgeDO extends BaseDO { +public class IotDataRuleSinkDO extends BaseDO { /** - * 桥梁编号 + * 数据目的编号 */ @TableId private Long id; /** - * 桥梁名称 + * 数据目的名称 */ private String name; /** - * 桥梁描述 + * 数据目的描述 */ private String description; /** @@ -43,23 +43,25 @@ public class IotDataBridgeDO extends BaseDO { * * 枚举 {@link CommonStatusEnum} */ + @Deprecated // TODO @puhui999:这个删除 private Integer status; /** * 桥梁方向 * * 枚举 {@link IotDataBridgeDirectionEnum} */ + @Deprecated // TODO @puhui999:这个删除 private Integer direction; /** - * 桥梁类型 + * 数据目的类型 * - * 枚举 {@link IotDataBridgeTypeEnum} + * 枚举 {@link IotDataRuleSinkTypeEnum} */ private Integer type; /** - * 桥梁配置 + * 数据目的配置 */ @TableField(typeHandler = JacksonTypeHandler.class) private IotDataBridgeAbstractConfig config; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleSourceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleSourceDO.java new file mode 100644 index 0000000000..87dd36ae79 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleSourceDO.java @@ -0,0 +1,79 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.rule; + +import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * IoT 数据流转的数据源 DO + * + * @author 芋道源码 + */ +@TableName(value = "iot_data_flow_source", autoResultMap = true) +@KeySequence("iot_data_flow_source_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IotDataRuleSourceDO { + + /** + * 数据源编号 + */ + private Long id; + /** + * 数据源名称 + */ + private String name; + + /** + * 配置数组 + */ + private List configs; + + /** + * 配置 + */ + @Data + public static class Config { + + /** + * 消息方法 + * + * 枚举 {@link IotDeviceMessageMethodEnum} 中的 upstream 上行部分 + */ + private String method; + + /** + * 产品编号 + * + * 关联 {@link IotProductDO#getId()} + */ + private Long productId; + /** + * 设备编号 + * + * 关联 {@link IotDeviceDO#getId()} + * 特殊:如果为 {@link IotDeviceDO#DEVICE_ID_ALL} 时,则是全部设备 + */ + private Long deviceId; + + /** + * 标识符 + * + * 1. 物模型时,对应:{@link IotThingModelDO#getIdentifier()} + */ + private String identifier; + + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java index c2ccbdd650..741d93d2c9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java @@ -201,7 +201,7 @@ public class IotRuleSceneDO extends TenantBaseDO { * 数据桥接编号 * * 必填:当 {@link #type} 为 {@link IotRuleSceneActionTypeEnum#DATA_BRIDGE} 时 - * 关联:{@link IotDataBridgeDO#getId()} + * 关联:{@link IotDataRuleSinkDO#getId()} */ private Long dataBridgeId; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleScene2DO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotSceneRuleDO.java similarity index 93% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleScene2DO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotSceneRuleDO.java index 5b6a3b5e42..78eb7fb11b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleScene2DO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotSceneRuleDO.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.rule; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; @@ -25,38 +26,35 @@ import java.util.List; /** * IoT 场景联动 DO * + * 基于 {@link Trigger} 触发 {@link Action} + * * @author 芋道源码 */ -@TableName(value = "iot_rule_scene2", autoResultMap = true) -@KeySequence("iot_rule_scene_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@TableName(value = "iot_scene_rule", autoResultMap = true) +@KeySequence("iot_scene_rule_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Builder @NoArgsConstructor @AllArgsConstructor -public class IotRuleScene2DO extends TenantBaseDO { +public class IotSceneRuleDO extends TenantBaseDO { /** - * 设备编号 - 全部设备 - */ - public static final Long DEVICE_ID_ALL = 0L; - - /** - * 场景编号 + * 场景联动编号 */ @TableId private Long id; /** - * 场景名称 + * 场景联动名称 */ private String name; /** - * 场景描述 + * 场景联动描述 */ private String description; /** - * 场景状态 + * 场景联动状态 * - * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + * 枚举 {@link CommonStatusEnum} */ private Integer status; @@ -103,7 +101,7 @@ public class IotRuleScene2DO extends TenantBaseDO { * 设备编号 * * 关联 {@link IotDeviceDO#getId()} - * 特殊:如果为 0,则是全部 + * 特殊:如果为 {@link IotDeviceDO#DEVICE_ID_ALL} 时,则是全部设备 */ private Long deviceId; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java index bfaee9acf4..dc7f0964bc 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgePageReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleSinkDO; import org.apache.ibatis.annotations.Mapper; import java.util.List; @@ -15,20 +15,20 @@ import java.util.List; * @author HUIHUI */ @Mapper -public interface IotDataBridgeMapper extends BaseMapperX { +public interface IotDataBridgeMapper extends BaseMapperX { - default PageResult selectPage(IotDataBridgePageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .likeIfPresent(IotDataBridgeDO::getName, reqVO.getName()) - .eqIfPresent(IotDataBridgeDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(IotDataBridgeDO::getCreateTime, reqVO.getCreateTime()) - .orderByDesc(IotDataBridgeDO::getId)); + default PageResult selectPage(IotDataBridgePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(IotDataRuleSinkDO::getName, reqVO.getName()) + .eqIfPresent(IotDataRuleSinkDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(IotDataRuleSinkDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(IotDataRuleSinkDO::getId)); } - default List selectList(Integer status) { - return selectList(new LambdaQueryWrapperX() - .eqIfPresent(IotDataBridgeDO::getStatus, status) - .orderByDesc(IotDataBridgeDO::getId)); + default List selectList(Integer status) { + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(IotDataRuleSinkDO::getStatus, status) + .orderByDesc(IotDataRuleSinkDO::getId)); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java index 934bf39570..8559940a8c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.service.rule; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgePageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgeSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleSinkDO; import jakarta.validation.Valid; import java.util.List; @@ -43,7 +43,7 @@ public interface IotDataBridgeService { * @param id 编号 * @return 数据桥梁 */ - IotDataBridgeDO getDataBridge(Long id); + IotDataRuleSinkDO getDataBridge(Long id); /** * 获得数据桥梁分页 @@ -51,7 +51,7 @@ public interface IotDataBridgeService { * @param pageReqVO 分页查询 * @return 数据桥梁分页 */ - PageResult getDataBridgePage(IotDataBridgePageReqVO pageReqVO); + PageResult getDataBridgePage(IotDataBridgePageReqVO pageReqVO); /** * 获取数据桥梁列表 @@ -59,6 +59,6 @@ public interface IotDataBridgeService { * @param status 状态,如果为空,则不进行筛选 * @return 数据桥梁列表 */ - List getDataBridgeList(Integer status); + List getDataBridgeList(Integer status); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java index 16fa025669..f10ebc0577 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgePageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgeSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleSinkDO; import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotDataBridgeMapper; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; @@ -30,7 +30,7 @@ public class IotDataBridgeServiceImpl implements IotDataBridgeService { @Override public Long createDataBridge(IotDataBridgeSaveReqVO createReqVO) { // 插入 - IotDataBridgeDO dataBridge = BeanUtils.toBean(createReqVO, IotDataBridgeDO.class); + IotDataRuleSinkDO dataBridge = BeanUtils.toBean(createReqVO, IotDataRuleSinkDO.class); dataBridgeMapper.insert(dataBridge); // 返回 return dataBridge.getId(); @@ -41,7 +41,7 @@ public class IotDataBridgeServiceImpl implements IotDataBridgeService { // 校验存在 validateDataBridgeExists(updateReqVO.getId()); // 更新 - IotDataBridgeDO updateObj = BeanUtils.toBean(updateReqVO, IotDataBridgeDO.class); + IotDataRuleSinkDO updateObj = BeanUtils.toBean(updateReqVO, IotDataRuleSinkDO.class); dataBridgeMapper.updateById(updateObj); } @@ -60,17 +60,17 @@ public class IotDataBridgeServiceImpl implements IotDataBridgeService { } @Override - public IotDataBridgeDO getDataBridge(Long id) { + public IotDataRuleSinkDO getDataBridge(Long id) { return dataBridgeMapper.selectById(id); } @Override - public PageResult getDataBridgePage(IotDataBridgePageReqVO pageReqVO) { + public PageResult getDataBridgePage(IotDataBridgePageReqVO pageReqVO) { return dataBridgeMapper.selectPage(pageReqVO); } @Override - public List getDataBridgeList(Integer status) { + public List getDataBridgeList(Integer status) { return dataBridgeMapper.selectList(status); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java index cd1e3600c9..ca73c8bd66 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.service.rule.action; import cn.hutool.core.lang.Assert; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleSinkDO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; import cn.iocoder.yudao.module.iot.service.rule.IotDataBridgeService; @@ -36,7 +36,7 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { } // 1.2 获得数据桥梁 Assert.notNull(config.getDataBridgeId(), "数据桥梁编号不能为空"); - IotDataBridgeDO dataBridge = dataBridgeService.getDataBridge(config.getDataBridgeId()); + IotDataRuleSinkDO dataBridge = dataBridgeService.getDataBridge(config.getDataBridgeId()); if (dataBridge == null || dataBridge.getConfig() == null) { log.error("[execute][message({}) config({}) 对应的数据桥梁不存在]", message, config); return; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java index a83912dda0..3f5b1e5372 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleSinkDO; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; @@ -100,7 +100,7 @@ public abstract class AbstractCacheableDataBridgeExecute imple @Override @SuppressWarnings({"unchecked"}) - public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { + public void execute(IotDeviceMessage message, IotDataRuleSinkDO dataBridge) { if (ObjUtil.notEqual(dataBridge.getType(), getType())) { return; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java index 1251f3089d..d5dab1124f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleSinkDO; /** * IoT 数据桥梁的执行器 execute 接口 @@ -24,7 +24,7 @@ public interface IotDataBridgeExecute { * @param dataBridge 数据桥梁 */ @SuppressWarnings({"unchecked"}) - default void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) throws Exception { + default void execute(IotDeviceMessage message, IotDataRuleSinkDO dataBridge) throws Exception { // 1.1 校验数据桥梁类型 if (!getType().equals(dataBridge.getType())) { return; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java index 16af0c109e..9d628acd96 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java @@ -5,7 +5,7 @@ import cn.iocoder.yudao.framework.common.util.http.HttpUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeHttpConfig; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataRuleSinkTypeEnum; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.http.*; @@ -30,7 +30,7 @@ public class IotHttpDataBridgeExecute implements IotDataBridgeExecute action, IotDataBridgeAbstractConfig config, String type) throws Exception { log.info("[test{}DataBridge][第一次执行,应该会创建新的 producer]", type); - action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); + action.execute(message, new IotDataRuleSinkDO().setType(action.getType()).setConfig(config)); log.info("[test{}DataBridge][第二次执行,应该会复用缓存的 producer]", type); - action.execute(message, new IotDataBridgeDO().setType(action.getType()).setConfig(config)); + action.execute(message, new IotDataRuleSinkDO().setType(action.getType()).setConfig(config)); } } From afda934c1db59d9187e4f3f7a67a221ec2f6591c Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 24 Jun 2025 09:55:27 +0800 Subject: [PATCH 03/33] =?UTF-8?q?reactor=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E8=B0=83=E6=95=B4=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=B5=81=E8=BD=AC=E7=9A=84=E5=8C=85=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rule/IotDataBridgeDirectionEnum.java | 30 ------- ...TypeEnum.java => IotDataSinkTypeEnum.java} | 19 +++-- .../admin/rule/IotDataBridgeController.java | 84 ------------------- .../admin/rule/IotDataSinkController.java | 84 +++++++++++++++++++ .../admin/rule/IotRuleSceneController.java | 2 +- .../admin/rule/vo/data/package-info.java | 1 + .../sink/IotDataSinkPageReqVO.java} | 10 +-- .../rule/vo/data/sink/IotDataSinkRespVO.java | 34 ++++++++ .../vo/data/sink/IotDataSinkSaveReqVO.java | 40 +++++++++ .../vo/databridge/IotDataBridgeRespVO.java | 37 -------- .../vo/databridge/IotDataBridgeSaveReqVO.java | 46 ---------- .../thingmodel/model/ThingModelEvent.java | 1 + .../dal/dataobject/rule/IotDataRuleDO.java | 57 +++++++++++-- .../dataobject/rule/IotDataRuleSourceDO.java | 79 ----------------- ...DataRuleSinkDO.java => IotDataSinkDO.java} | 31 +++---- .../dal/dataobject/rule/IotRuleSceneDO.java | 2 +- .../config/IotDataBridgeAbstractConfig.java | 8 +- .../rule}/config/IotDataBridgeHttpConfig.java | 2 +- .../config/IotDataBridgeKafkaMQConfig.java | 2 +- .../rule}/config/IotDataBridgeMqttConfig.java | 2 +- .../config/IotDataBridgeRabbitMQConfig.java | 2 +- .../IotDataBridgeRedisStreamConfig.java | 2 +- .../config/IotDataBridgeRocketMQConfig.java | 2 +- .../dal/mysql/rule/IotDataBridgeMapper.java | 34 -------- .../iot/dal/mysql/rule/IotDataSinkMapper.java | 32 +++++++ .../module/iot/job/rule/IotRuleSceneJob.java | 2 +- .../rule/IotRuleSceneMessageHandler.java | 2 +- .../service/rule/IotDataBridgeService.java | 64 -------------- .../rule/IotDataBridgeServiceImpl.java | 77 ----------------- .../service/rule/data/IotDataSinkService.java | 64 ++++++++++++++ .../rule/data/IotDataSinkServiceImpl.java | 75 +++++++++++++++++ .../IotRuleSceneDataBridgeAction.java | 13 +-- .../AbstractCacheableDataBridgeExecute.java | 6 +- .../action}/IotDataBridgeExecute.java | 6 +- .../action}/IotHttpDataBridgeExecute.java | 8 +- .../action}/IotKafkaMQDataBridgeExecute.java | 8 +- .../action}/IotRabbitMQDataBridgeExecute.java | 8 +- .../IotRedisStreamDataBridgeExecute.java | 8 +- .../action}/IotRocketMQDataBridgeExecute.java | 8 +- .../rule/{ => scene}/IotRuleSceneService.java | 2 +- .../{ => scene}/IotRuleSceneServiceImpl.java | 4 +- .../action/IotRuleSceneAction.java | 2 +- .../action/IotRuleSceneAlertAction.java | 2 +- .../IotRuleSceneDeviceControlAction.java | 2 +- .../databridge/IotDataBridgeExecuteTest.java | 11 +-- 45 files changed, 467 insertions(+), 548 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeDirectionEnum.java rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/{IotDataRuleSinkTypeEnum.java => IotDataSinkTypeEnum.java} (56%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataSinkController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/package-info.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/{databridge/IotDataBridgePageReqVO.java => data/sink/IotDataSinkPageReqVO.java} (74%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/sink/IotDataSinkRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/sink/IotDataSinkSaveReqVO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleSourceDO.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/{IotDataRuleSinkDO.java => IotDataSinkDO.java} (62%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/{controller/admin/rule/vo/databridge => dal/dataobject/rule}/config/IotDataBridgeAbstractConfig.java (79%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/{controller/admin/rule/vo/databridge => dal/dataobject/rule}/config/IotDataBridgeHttpConfig.java (87%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/{controller/admin/rule/vo/databridge => dal/dataobject/rule}/config/IotDataBridgeKafkaMQConfig.java (86%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/{controller/admin/rule/vo/databridge => dal/dataobject/rule}/config/IotDataBridgeMqttConfig.java (86%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/{controller/admin/rule/vo/databridge => dal/dataobject/rule}/config/IotDataBridgeRabbitMQConfig.java (90%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/{controller/admin/rule/vo/databridge => dal/dataobject/rule}/config/IotDataBridgeRedisStreamConfig.java (86%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/{controller/admin/rule/vo/databridge => dal/dataobject/rule}/config/IotDataBridgeRocketMQConfig.java (88%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataSinkMapper.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkServiceImpl.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/{action => data}/IotRuleSceneDataBridgeAction.java (80%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/{action/databridge => data/action}/AbstractCacheableDataBridgeExecute.java (94%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/{action/databridge => data/action}/IotDataBridgeExecute.java (79%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/{action/databridge => data/action}/IotHttpDataBridgeExecute.java (92%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/{action/databridge => data/action}/IotKafkaMQDataBridgeExecute.java (90%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/{action/databridge => data/action}/IotRabbitMQDataBridgeExecute.java (88%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/{action/databridge => data/action}/IotRedisStreamDataBridgeExecute.java (91%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/{action/databridge => data/action}/IotRocketMQDataBridgeExecute.java (88%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/{ => scene}/IotRuleSceneService.java (97%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/{ => scene}/IotRuleSceneServiceImpl.java (99%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/{ => scene}/action/IotRuleSceneAction.java (93%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/{ => scene}/action/IotRuleSceneAlertAction.java (92%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/{ => scene}/action/IotRuleSceneDeviceControlAction.java (97%) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeDirectionEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeDirectionEnum.java deleted file mode 100644 index a9d445fd23..0000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeDirectionEnum.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.iocoder.yudao.module.iot.enums.rule; - -import cn.iocoder.yudao.framework.common.core.ArrayValuable; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -import java.util.Arrays; - -/** - * IoT 数据桥接的方向枚举 - * - * @author 芋道源码 - */ -@RequiredArgsConstructor -@Getter -public enum IotDataBridgeDirectionEnum implements ArrayValuable { - - INPUT(1), // 输入 - OUTPUT(2); // 输出 - - private final Integer type; - - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataBridgeDirectionEnum::getType).toArray(Integer[]::new); - - @Override - public Integer[] array() { - return ARRAYS; - } - -} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataRuleSinkTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataSinkTypeEnum.java similarity index 56% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataRuleSinkTypeEnum.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataSinkTypeEnum.java index 824dc78f0e..ed341c618b 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataRuleSinkTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataSinkTypeEnum.java @@ -7,32 +7,33 @@ import lombok.RequiredArgsConstructor; import java.util.Arrays; /** - * IoT 数据流转的数据目的的类型枚举 + * IoT 数据目的的类型枚举 * * @author 芋道源码 */ @RequiredArgsConstructor @Getter -public enum IotDataRuleSinkTypeEnum implements ArrayValuable { +public enum IotDataSinkTypeEnum implements ArrayValuable { HTTP(1, "HTTP"), TCP(2, "TCP"), - WEBSOCKET(3, "WEBSOCKET"), + WEBSOCKET(3, "WebSocket"), MQTT(10, "MQTT"), - DATABASE(20, "DATABASE"), - REDIS_STREAM(21, "REDIS_STREAM"), + DATABASE(20, "Database"), + // TODO @芋艿:改成 Redis;通过 execute 通用化; + REDIS_STREAM(21, "Redis Stream"), - ROCKETMQ(30, "ROCKETMQ"), - RABBITMQ(31, "RABBITMQ"), - KAFKA(32, "KAFKA"); + ROCKETMQ(30, "RocketMQ"), + RABBITMQ(31, "RabbitMQ"), + KAFKA(32, "Kafka"); private final Integer type; private final String name; - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataRuleSinkTypeEnum::getType).toArray(Integer[]::new); + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataSinkTypeEnum::getType).toArray(Integer[]::new); @Override public Integer[] array() { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java deleted file mode 100644 index 90ff2dba91..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataBridgeController.java +++ /dev/null @@ -1,84 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.rule; - -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgePageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgeRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgeSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleSinkDO; -import cn.iocoder.yudao.module.iot.service.rule.IotDataBridgeService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.annotation.Resource; -import jakarta.validation.Valid; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; - -@Tag(name = "管理后台 - IoT 数据桥梁") -@RestController -@RequestMapping("/iot/data-bridge") -@Validated -public class IotDataBridgeController { - - @Resource - private IotDataBridgeService dataBridgeService; - - @PostMapping("/create") - @Operation(summary = "创建数据桥梁") - @PreAuthorize("@ss.hasPermission('iot:data-bridge:create')") - public CommonResult createDataBridge(@Valid @RequestBody IotDataBridgeSaveReqVO createReqVO) { - return success(dataBridgeService.createDataBridge(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新数据桥梁") - @PreAuthorize("@ss.hasPermission('iot:data-bridge:update')") - public CommonResult updateDataBridge(@Valid @RequestBody IotDataBridgeSaveReqVO updateReqVO) { - dataBridgeService.updateDataBridge(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除数据桥梁") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('iot:data-bridge:delete')") - public CommonResult deleteDataBridge(@RequestParam("id") Long id) { - dataBridgeService.deleteDataBridge(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得数据桥梁") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('iot:data-bridge:query')") - public CommonResult getDataBridge(@RequestParam("id") Long id) { - IotDataRuleSinkDO dataBridge = dataBridgeService.getDataBridge(id); - return success(BeanUtils.toBean(dataBridge, IotDataBridgeRespVO.class)); - } - - @GetMapping("/page") - @Operation(summary = "获得数据桥梁分页") - @PreAuthorize("@ss.hasPermission('iot:data-bridge:query')") - public CommonResult> getDataBridgePage(@Valid IotDataBridgePageReqVO pageReqVO) { - PageResult pageResult = dataBridgeService.getDataBridgePage(pageReqVO); - return success(BeanUtils.toBean(pageResult, IotDataBridgeRespVO.class)); - } - - @GetMapping("/simple-list") - @Operation(summary = "获取数据桥梁的精简信息列表", description = "主要用于前端的下拉选项") - public CommonResult> getSimpleDataBridgeList() { - List list = dataBridgeService.getDataBridgeList(CommonStatusEnum.ENABLE.getStatus()); - return success(convertList(list, dataBridge -> // 只返回 id、name 字段 - new IotDataBridgeRespVO().setId(dataBridge.getId()).setName(dataBridge.getName()))); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataSinkController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataSinkController.java new file mode 100644 index 0000000000..c5232d3d08 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataSinkController.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink.IotDataSinkPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink.IotDataSinkRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink.IotDataSinkSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; +import cn.iocoder.yudao.module.iot.service.rule.data.IotDataSinkService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "管理后台 - IoT 数据流转目的") +@RestController +@RequestMapping("/iot/data-sink") +@Validated +public class IotDataSinkController { + + @Resource + private IotDataSinkService dataSinkService; + + @PostMapping("/create") + @Operation(summary = "创建数据目的") + @PreAuthorize("@ss.hasPermission('iot:data-sink:create')") + public CommonResult createDataSink(@Valid @RequestBody IotDataSinkSaveReqVO createReqVO) { + return success(dataSinkService.createDataSink(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新数据目的") + @PreAuthorize("@ss.hasPermission('iot:data-sink:update')") + public CommonResult updateDataSink(@Valid @RequestBody IotDataSinkSaveReqVO updateReqVO) { + dataSinkService.updateDataSink(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除数据目的") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:data-sink:delete')") + public CommonResult deleteDataSink(@RequestParam("id") Long id) { + dataSinkService.deleteDataSink(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得数据目的") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:data-sink:query')") + public CommonResult getDataSink(@RequestParam("id") Long id) { + IotDataSinkDO sink = dataSinkService.getDataSink(id); + return success(BeanUtils.toBean(sink, IotDataSinkRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得数据目的分页") + @PreAuthorize("@ss.hasPermission('iot:data-sink:query')") + public CommonResult> getDataSinkPage(@Valid IotDataSinkPageReqVO pageReqVO) { + PageResult pageResult = dataSinkService.getDataSinkPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotDataSinkRespVO.class)); + } + + @GetMapping("/simple-list") + @Operation(summary = "获取数据目的的精简信息列表", description = "主要用于前端的下拉选项") + public CommonResult> getSimpleDataSinkList() { + List list = dataSinkService.getDataSinkListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(convertList(list, sink -> // 只返回 id、name 字段 + new IotDataSinkRespVO().setId(sink.getId()).setName(sink.getName()))); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java index 5a9cf37db7..4168daf0b0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java @@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleScenePa import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneRespVO; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; -import cn.iocoder.yudao.module.iot.service.rule.IotRuleSceneService; +import cn.iocoder.yudao.module.iot.service.rule.scene.IotRuleSceneService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/package-info.java new file mode 100644 index 0000000000..6be90cf325 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/sink/IotDataSinkPageReqVO.java similarity index 74% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/sink/IotDataSinkPageReqVO.java index e4dc36ef9e..06bbecc894 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/sink/IotDataSinkPageReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge; +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageParam; @@ -11,14 +11,14 @@ import java.time.LocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; -@Schema(description = "管理后台 - IoT 数据桥梁分页 Request VO") +@Schema(description = "管理后台 - IoT 数据流转目的分页 Request VO") @Data -public class IotDataBridgePageReqVO extends PageParam { +public class IotDataSinkPageReqVO extends PageParam { - @Schema(description = "桥梁名称", example = "赵六") + @Schema(description = "数据目的名称", example = "赵六") private String name; - @Schema(description = "桥梁状态", example = "1") + @Schema(description = "数据目的状态", example = "2") @InEnum(CommonStatusEnum.class) private Integer status; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/sink/IotDataSinkRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/sink/IotDataSinkRespVO.java new file mode 100644 index 0000000000..b00e8a3b79 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/sink/IotDataSinkRespVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink; + +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataBridgeAbstractConfig; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - IoT 数据流转目的 Response VO") +@Data +public class IotDataSinkRespVO { + + @Schema(description = "数据目的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18564") + private Long id; + + @Schema(description = "数据目的名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + private String name; + + @Schema(description = "数据目的描述", example = "随便") + private String description; + + @Schema(description = "数据目的状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "数据目的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; + + @Schema(description = "数据目的配置") + private IotDataBridgeAbstractConfig config; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/sink/IotDataSinkSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/sink/IotDataSinkSaveReqVO.java new file mode 100644 index 0000000000..b178e09c56 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/sink/IotDataSinkSaveReqVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataBridgeAbstractConfig; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataSinkTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(description = "管理后台 - IoT 数据流转目的新增/修改 Request VO") +@Data +public class IotDataSinkSaveReqVO { + + @Schema(description = "数据目的编号", example = "18564") + private Long id; + + @Schema(description = "数据目的名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + @NotEmpty(message = "数据目的名称不能为空") + private String name; + + @Schema(description = "数据目的描述", example = "随便") + private String description; + + @Schema(description = "数据目的状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "数据目的状态不能为空") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @Schema(description = "数据目的类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "数据目的类型不能为空") + @InEnum(IotDataSinkTypeEnum.class) + private Integer type; + + @Schema(description = "数据目的配置") + @NotNull(message = "数据目的配置不能为空") + private IotDataBridgeAbstractConfig config; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java deleted file mode 100644 index 38e04b2ebe..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeRespVO.java +++ /dev/null @@ -1,37 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge; - -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeAbstractConfig; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.time.LocalDateTime; - -@Schema(description = "管理后台 - IoT 数据桥梁 Response VO") -@Data -public class IotDataBridgeRespVO { - - @Schema(description = "桥梁编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18564") - private Long id; - - @Schema(description = "桥梁名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") - private String name; - - @Schema(description = "桥梁描述", example = "随便") - private String description; - - @Schema(description = "桥梁状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer status; - - @Schema(description = "桥梁方向", requiredMode = Schema.RequiredMode.REQUIRED) - private Integer direction; - - @Schema(description = "桥梁类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer type; - - @Schema(description = "桥梁配置") - private IotDataBridgeAbstractConfig config; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime createTime; - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java deleted file mode 100644 index ba1bfb1959..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/IotDataBridgeSaveReqVO.java +++ /dev/null @@ -1,46 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge; - -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeAbstractConfig; -import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeDirectionEnum; -import cn.iocoder.yudao.module.iot.enums.rule.IotDataRuleSinkTypeEnum; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; -import lombok.Data; - -@Schema(description = "管理后台 - IoT 数据桥梁新增/修改 Request VO") -@Data -public class IotDataBridgeSaveReqVO { - - @Schema(description = "桥梁编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18564") - private Long id; - - @Schema(description = "桥梁名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") - @NotEmpty(message = "桥梁名称不能为空") - private String name; - - @Schema(description = "桥梁描述", example = "随便") - private String description; - - @Schema(description = "桥梁状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @NotNull(message = "桥梁状态不能为空") - @InEnum(CommonStatusEnum.class) - private Integer status; - - @Schema(description = "桥梁方向", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "桥梁方向不能为空") - @InEnum(IotDataBridgeDirectionEnum.class) - private Integer direction; - - @Schema(description = "桥梁类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @NotNull(message = "桥梁类型不能为空") - @InEnum(IotDataRuleSinkTypeEnum.class) - private Integer type; - - @Schema(description = "桥梁配置") - @NotNull(message = "桥梁配置不能为空") - private IotDataBridgeAbstractConfig config; - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java index 06cc43809e..bf6e20b8a2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java @@ -9,6 +9,7 @@ import lombok.Data; import java.util.List; +// TODO @puhui999:感觉这个,是不是放到 dal 里会好点?(讨论下,先不改哈) /** * IoT 物模型中的事件 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleDO.java index 024e71c031..1cf766c488 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleDO.java @@ -1,8 +1,15 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.rule; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; +import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -11,9 +18,9 @@ import lombok.NoArgsConstructor; import java.util.List; /** - * IoT 数据流转 DO + * IoT 数据流转规则 DO * - * 组合 {@link IotDataRuleSourceDO} => {@link IotDataRuleSinkDO} + * 监听 {@link SourceConfig} 数据源,转发到 {@link IotDataSinkDO} 数据目的 * * @author 芋道源码 */ @@ -45,18 +52,54 @@ public class IotDataRuleDO { private Integer status; /** - * 数据源编号 - * - * 关联 {@link IotDataRuleSourceDO#getId()} + * 数据源配置数组 */ - private List sourceIds; + @TableField(typeHandler = JacksonTypeHandler.class) + private List sourceConfigs; /** * 数据目的编号 * - * 关联 {@link IotDataRuleSinkDO#getId()} + * 关联 {@link IotDataSinkDO#getId()} */ + @TableField(typeHandler = LongListTypeHandler.class) private List sinkIds; // TODO @芋艿:未来考虑使用 groovy;支持数据处理; + /** + * 数据源配置 + */ + @Data + public static class SourceConfig { + + /** + * 消息方法 + * + * 枚举 {@link IotDeviceMessageMethodEnum} 中的 upstream 上行部分 + */ + private String method; + + /** + * 产品编号 + * + * 关联 {@link IotProductDO#getId()} + */ + private Long productId; + /** + * 设备编号 + * + * 关联 {@link IotDeviceDO#getId()} + * 特殊:如果为 {@link IotDeviceDO#DEVICE_ID_ALL} 时,则是全部设备 + */ + private Long deviceId; + + /** + * 标识符 + * + * 1. 物模型时,对应:{@link IotThingModelDO#getIdentifier()} + */ + private String identifier; + + } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleSourceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleSourceDO.java deleted file mode 100644 index 87dd36ae79..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleSourceDO.java +++ /dev/null @@ -1,79 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.rule; - -import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; -import com.baomidou.mybatisplus.annotation.KeySequence; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; - -/** - * IoT 数据流转的数据源 DO - * - * @author 芋道源码 - */ -@TableName(value = "iot_data_flow_source", autoResultMap = true) -@KeySequence("iot_data_flow_source_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class IotDataRuleSourceDO { - - /** - * 数据源编号 - */ - private Long id; - /** - * 数据源名称 - */ - private String name; - - /** - * 配置数组 - */ - private List configs; - - /** - * 配置 - */ - @Data - public static class Config { - - /** - * 消息方法 - * - * 枚举 {@link IotDeviceMessageMethodEnum} 中的 upstream 上行部分 - */ - private String method; - - /** - * 产品编号 - * - * 关联 {@link IotProductDO#getId()} - */ - private Long productId; - /** - * 设备编号 - * - * 关联 {@link IotDeviceDO#getId()} - * 特殊:如果为 {@link IotDeviceDO#DEVICE_ID_ALL} 时,则是全部设备 - */ - private Long deviceId; - - /** - * 标识符 - * - * 1. 物模型时,对应:{@link IotThingModelDO#getIdentifier()} - */ - private String identifier; - - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleSinkDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataSinkDO.java similarity index 62% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleSinkDO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataSinkDO.java index 1214e710d3..16b3d6398f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleSinkDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataSinkDO.java @@ -2,28 +2,30 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.rule; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeAbstractConfig; -import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgeDirectionEnum; -import cn.iocoder.yudao.module.iot.enums.rule.IotDataRuleSinkTypeEnum; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataBridgeAbstractConfig; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataSinkTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; -import lombok.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; /** - * IoT 数据流转的数据目的 DO + * IoT 数据流转目的 DO * * @author 芋道源码 */ -@TableName(value = "iot_data_bridge", autoResultMap = true) +@TableName(value = "iot_data_sink", autoResultMap = true) @KeySequence("iot_data_bridge_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Builder @NoArgsConstructor @AllArgsConstructor -public class IotDataRuleSinkDO extends BaseDO { +public class IotDataSinkDO extends BaseDO { /** * 数据目的编号 @@ -39,27 +41,18 @@ public class IotDataRuleSinkDO extends BaseDO { */ private String description; /** - * 桥梁状态 + * 数据目的状态 * - * 枚举 {@link CommonStatusEnum} + * 枚举 {@link CommonStatusEnum} */ - @Deprecated // TODO @puhui999:这个删除 private Integer status; - /** - * 桥梁方向 - * - * 枚举 {@link IotDataBridgeDirectionEnum} - */ - @Deprecated // TODO @puhui999:这个删除 - private Integer direction; /** * 数据目的类型 * - * 枚举 {@link IotDataRuleSinkTypeEnum} + * 枚举 {@link IotDataSinkTypeEnum} */ private Integer type; - /** * 数据目的配置 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java index 741d93d2c9..845b18989c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java @@ -201,7 +201,7 @@ public class IotRuleSceneDO extends TenantBaseDO { * 数据桥接编号 * * 必填:当 {@link #type} 为 {@link IotRuleSceneActionTypeEnum#DATA_BRIDGE} 时 - * 关联:{@link IotDataRuleSinkDO#getId()} + * 关联:{@link IotDataSinkDO#getId()} */ private Long dataBridgeId; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeAbstractConfig.java similarity index 79% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeAbstractConfig.java index 62fa5558cd..d15008b939 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeAbstractConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeAbstractConfig.java @@ -1,6 +1,6 @@ -package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; +package cn.iocoder.yudao.module.iot.dal.dataobject.rule.config; -import cn.iocoder.yudao.module.iot.enums.rule.IotDataRuleSinkTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataSinkTypeEnum; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import lombok.Data; @@ -8,7 +8,7 @@ import lombok.Data; /** * IoT IotDataBridgeConfig 抽象类 * - * 用于表示数据桥梁配置数据的通用类型,根据具体的 "type" 字段动态映射到对应的子类 + * 用于表示数据目的配置数据的通用类型,根据具体的 "type" 字段动态映射到对应的子类 * 提供多态支持,适用于不同类型的数据结构序列化和反序列化场景。 * * @author HUIHUI @@ -28,7 +28,7 @@ public abstract class IotDataBridgeAbstractConfig { /** * 配置类型 * - * 枚举 {@link IotDataRuleSinkTypeEnum#getType()} + * 枚举 {@link IotDataSinkTypeEnum#getType()} */ private String type; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeHttpConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeHttpConfig.java similarity index 87% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeHttpConfig.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeHttpConfig.java index eca35c76ec..7e65bd4b45 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeHttpConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeHttpConfig.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; +package cn.iocoder.yudao.module.iot.dal.dataobject.rule.config; import lombok.Data; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeKafkaMQConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeKafkaMQConfig.java similarity index 86% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeKafkaMQConfig.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeKafkaMQConfig.java index 1201214d12..e0ecd43792 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeKafkaMQConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeKafkaMQConfig.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; +package cn.iocoder.yudao.module.iot.dal.dataobject.rule.config; import lombok.Data; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeMqttConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeMqttConfig.java similarity index 86% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeMqttConfig.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeMqttConfig.java index 448b21501d..7500fa35ab 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeMqttConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeMqttConfig.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; +package cn.iocoder.yudao.module.iot.dal.dataobject.rule.config; import lombok.Data; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRabbitMQConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeRabbitMQConfig.java similarity index 90% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRabbitMQConfig.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeRabbitMQConfig.java index 2c247d1d58..b899b5fadb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRabbitMQConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeRabbitMQConfig.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; +package cn.iocoder.yudao.module.iot.dal.dataobject.rule.config; import lombok.Data; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRedisStreamConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeRedisStreamConfig.java similarity index 86% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRedisStreamConfig.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeRedisStreamConfig.java index fc7a4c3f2e..5ece7f6cf1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRedisStreamConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeRedisStreamConfig.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; +package cn.iocoder.yudao.module.iot.dal.dataobject.rule.config; import lombok.Data; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRocketMQConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeRocketMQConfig.java similarity index 88% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRocketMQConfig.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeRocketMQConfig.java index e23e3061a1..4cc73c5c5a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/databridge/config/IotDataBridgeRocketMQConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeRocketMQConfig.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config; +package cn.iocoder.yudao.module.iot.dal.dataobject.rule.config; import lombok.Data; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java deleted file mode 100644 index dc7f0964bc..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.mysql.rule; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgePageReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleSinkDO; -import org.apache.ibatis.annotations.Mapper; - -import java.util.List; - -/** - * IoT 数据桥梁 Mapper - * - * @author HUIHUI - */ -@Mapper -public interface IotDataBridgeMapper extends BaseMapperX { - - default PageResult selectPage(IotDataBridgePageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .likeIfPresent(IotDataRuleSinkDO::getName, reqVO.getName()) - .eqIfPresent(IotDataRuleSinkDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(IotDataRuleSinkDO::getCreateTime, reqVO.getCreateTime()) - .orderByDesc(IotDataRuleSinkDO::getId)); - } - - default List selectList(Integer status) { - return selectList(new LambdaQueryWrapperX() - .eqIfPresent(IotDataRuleSinkDO::getStatus, status) - .orderByDesc(IotDataRuleSinkDO::getId)); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataSinkMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataSinkMapper.java new file mode 100644 index 0000000000..e65001db86 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataSinkMapper.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.rule; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink.IotDataSinkPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * IoT 数据流转目的 Mapper + * + * @author HUIHUI + */ +@Mapper +public interface IotDataSinkMapper extends BaseMapperX { + + default PageResult selectPage(IotDataSinkPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(IotDataSinkDO::getName, reqVO.getName()) + .eqIfPresent(IotDataSinkDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(IotDataSinkDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(IotDataSinkDO::getId)); + } + + default List selectListByStatus(Integer status) { + return selectList(IotDataSinkDO::getStatus, status); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/rule/IotRuleSceneJob.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/rule/IotRuleSceneJob.java index 594f9ef0b0..352162e188 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/rule/IotRuleSceneJob.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/rule/IotRuleSceneJob.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.job.rule; import cn.hutool.core.map.MapUtil; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; -import cn.iocoder.yudao.module.iot.service.rule.IotRuleSceneService; +import cn.iocoder.yudao.module.iot.service.rule.scene.IotRuleSceneService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.quartz.JobExecutionContext; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java index 38bc3423b3..4212a78a47 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.mq.consumer.rule; import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.service.rule.IotRuleSceneService; +import cn.iocoder.yudao.module.iot.service.rule.scene.IotRuleSceneService; import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java deleted file mode 100644 index 8559940a8c..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java +++ /dev/null @@ -1,64 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.rule; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgePageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgeSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleSinkDO; -import jakarta.validation.Valid; - -import java.util.List; - -/** - * IoT 数据桥梁 Service 接口 - * - * @author HUIHUI - */ -public interface IotDataBridgeService { - - /** - * 创建数据桥梁 - * - * @param createReqVO 创建信息 - * @return 编号 - */ - Long createDataBridge(@Valid IotDataBridgeSaveReqVO createReqVO); - - /** - * 更新数据桥梁 - * - * @param updateReqVO 更新信息 - */ - void updateDataBridge(@Valid IotDataBridgeSaveReqVO updateReqVO); - - /** - * 删除数据桥梁 - * - * @param id 编号 - */ - void deleteDataBridge(Long id); - - /** - * 获得数据桥梁 - * - * @param id 编号 - * @return 数据桥梁 - */ - IotDataRuleSinkDO getDataBridge(Long id); - - /** - * 获得数据桥梁分页 - * - * @param pageReqVO 分页查询 - * @return 数据桥梁分页 - */ - PageResult getDataBridgePage(IotDataBridgePageReqVO pageReqVO); - - /** - * 获取数据桥梁列表 - * - * @param status 状态,如果为空,则不进行筛选 - * @return 数据桥梁列表 - */ - List getDataBridgeList(Integer status); - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java deleted file mode 100644 index f10ebc0577..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java +++ /dev/null @@ -1,77 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.rule; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgePageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.IotDataBridgeSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleSinkDO; -import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotDataBridgeMapper; -import jakarta.annotation.Resource; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import java.util.List; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DATA_BRIDGE_NOT_EXISTS; - -/** - * IoT 数据桥梁 Service 实现类 - * - * @author HUIHUI - */ -@Service -@Validated -public class IotDataBridgeServiceImpl implements IotDataBridgeService { - - @Resource - private IotDataBridgeMapper dataBridgeMapper; - - @Override - public Long createDataBridge(IotDataBridgeSaveReqVO createReqVO) { - // 插入 - IotDataRuleSinkDO dataBridge = BeanUtils.toBean(createReqVO, IotDataRuleSinkDO.class); - dataBridgeMapper.insert(dataBridge); - // 返回 - return dataBridge.getId(); - } - - @Override - public void updateDataBridge(IotDataBridgeSaveReqVO updateReqVO) { - // 校验存在 - validateDataBridgeExists(updateReqVO.getId()); - // 更新 - IotDataRuleSinkDO updateObj = BeanUtils.toBean(updateReqVO, IotDataRuleSinkDO.class); - dataBridgeMapper.updateById(updateObj); - } - - @Override - public void deleteDataBridge(Long id) { - // 校验存在 - validateDataBridgeExists(id); - // 删除 - dataBridgeMapper.deleteById(id); - } - - private void validateDataBridgeExists(Long id) { - if (dataBridgeMapper.selectById(id) == null) { - throw exception(DATA_BRIDGE_NOT_EXISTS); - } - } - - @Override - public IotDataRuleSinkDO getDataBridge(Long id) { - return dataBridgeMapper.selectById(id); - } - - @Override - public PageResult getDataBridgePage(IotDataBridgePageReqVO pageReqVO) { - return dataBridgeMapper.selectPage(pageReqVO); - } - - @Override - public List getDataBridgeList(Integer status) { - return dataBridgeMapper.selectList(status); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkService.java new file mode 100644 index 0000000000..6057303f43 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkService.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.iot.service.rule.data; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink.IotDataSinkPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink.IotDataSinkSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; +import jakarta.validation.Valid; + +import java.util.List; + +/** + * IoT 数据流转目的 Service 接口 + * + * @author HUIHUI + */ +public interface IotDataSinkService { + + /** + * 创建数据目的 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDataSink(@Valid IotDataSinkSaveReqVO createReqVO); + + /** + * 更新数据目的 + * + * @param updateReqVO 更新信息 + */ + void updateDataSink(@Valid IotDataSinkSaveReqVO updateReqVO); + + /** + * 删除数据目的 + * + * @param id 编号 + */ + void deleteDataSink(Long id); + + /** + * 获得数据目的 + * + * @param id 编号 + * @return 数据目的 + */ + IotDataSinkDO getDataSink(Long id); + + /** + * 获得数据目的分页 + * + * @param pageReqVO 分页查询 + * @return 数据目的分页 + */ + PageResult getDataSinkPage(IotDataSinkPageReqVO pageReqVO); + + /** + * 获取数据目的列表 + * + * @param status 状态,如果为空,则不进行筛选 + * @return 数据目的列表 + */ + List getDataSinkListByStatus(Integer status); + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkServiceImpl.java new file mode 100644 index 0000000000..fba06cac69 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkServiceImpl.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.iot.service.rule.data; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink.IotDataSinkPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink.IotDataSinkSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; +import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotDataSinkMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DATA_BRIDGE_NOT_EXISTS; + +/** + * IoT 数据流转目的 Service 实现类 + * + * @author HUIHUI + */ +@Service +@Validated +public class IotDataSinkServiceImpl implements IotDataSinkService { + + @Resource + private IotDataSinkMapper dataSinkMapper; + + @Override + public Long createDataSink(IotDataSinkSaveReqVO createReqVO) { + IotDataSinkDO dataBridge = BeanUtils.toBean(createReqVO, IotDataSinkDO.class); + dataSinkMapper.insert(dataBridge); + return dataBridge.getId(); + } + + @Override + public void updateDataSink(IotDataSinkSaveReqVO updateReqVO) { + // 校验存在 + validateDataBridgeExists(updateReqVO.getId()); + // 更新 + IotDataSinkDO updateObj = BeanUtils.toBean(updateReqVO, IotDataSinkDO.class); + dataSinkMapper.updateById(updateObj); + } + + @Override + public void deleteDataSink(Long id) { + // 校验存在 + validateDataBridgeExists(id); + // 删除 + dataSinkMapper.deleteById(id); + } + + private void validateDataBridgeExists(Long id) { + if (dataSinkMapper.selectById(id) == null) { + throw exception(DATA_BRIDGE_NOT_EXISTS); + } + } + + @Override + public IotDataSinkDO getDataSink(Long id) { + return dataSinkMapper.selectById(id); + } + + @Override + public PageResult getDataSinkPage(IotDataSinkPageReqVO pageReqVO) { + return dataSinkMapper.selectPage(pageReqVO); + } + + @Override + public List getDataSinkListByStatus(Integer status) { + return dataSinkMapper.selectListByStatus(status); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotRuleSceneDataBridgeAction.java similarity index 80% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotRuleSceneDataBridgeAction.java index ca73c8bd66..459f959981 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotRuleSceneDataBridgeAction.java @@ -1,13 +1,13 @@ -package cn.iocoder.yudao.module.iot.service.rule.action; +package cn.iocoder.yudao.module.iot.service.rule.data; import cn.hutool.core.lang.Assert; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleSinkDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; -import cn.iocoder.yudao.module.iot.service.rule.IotDataBridgeService; -import cn.iocoder.yudao.module.iot.service.rule.action.databridge.IotDataBridgeExecute; +import cn.iocoder.yudao.module.iot.service.rule.data.action.IotDataBridgeExecute; +import cn.iocoder.yudao.module.iot.service.rule.scene.action.IotRuleSceneAction; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -19,12 +19,13 @@ import java.util.List; * * @author 芋道源码 */ +@Deprecated @Component @Slf4j public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { @Resource - private IotDataBridgeService dataBridgeService; + private IotDataSinkService dataBridgeService; @Resource private List> dataBridgeExecutes; @@ -36,7 +37,7 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { } // 1.2 获得数据桥梁 Assert.notNull(config.getDataBridgeId(), "数据桥梁编号不能为空"); - IotDataRuleSinkDO dataBridge = dataBridgeService.getDataBridge(config.getDataBridgeId()); + IotDataSinkDO dataBridge = dataBridgeService.getDataSink(config.getDataBridgeId()); if (dataBridge == null || dataBridge.getConfig() == null) { log.error("[execute][message({}) config({}) 对应的数据桥梁不存在]", message, config); return; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/AbstractCacheableDataBridgeExecute.java similarity index 94% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/AbstractCacheableDataBridgeExecute.java index 3f5b1e5372..e78a1e4683 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/AbstractCacheableDataBridgeExecute.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.module.iot.service.rule.action.databridge; +package cn.iocoder.yudao.module.iot.service.rule.data.action; import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleSinkDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; @@ -100,7 +100,7 @@ public abstract class AbstractCacheableDataBridgeExecute imple @Override @SuppressWarnings({"unchecked"}) - public void execute(IotDeviceMessage message, IotDataRuleSinkDO dataBridge) { + public void execute(IotDeviceMessage message, IotDataSinkDO dataBridge) { if (ObjUtil.notEqual(dataBridge.getType(), getType())) { return; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotDataBridgeExecute.java similarity index 79% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotDataBridgeExecute.java index d5dab1124f..e2b69a907b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotDataBridgeExecute.java @@ -1,7 +1,7 @@ -package cn.iocoder.yudao.module.iot.service.rule.action.databridge; +package cn.iocoder.yudao.module.iot.service.rule.data.action; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleSinkDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; /** * IoT 数据桥梁的执行器 execute 接口 @@ -24,7 +24,7 @@ public interface IotDataBridgeExecute { * @param dataBridge 数据桥梁 */ @SuppressWarnings({"unchecked"}) - default void execute(IotDeviceMessage message, IotDataRuleSinkDO dataBridge) throws Exception { + default void execute(IotDeviceMessage message, IotDataSinkDO dataBridge) throws Exception { // 1.1 校验数据桥梁类型 if (!getType().equals(dataBridge.getType())) { return; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataBridgeExecute.java similarity index 92% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataBridgeExecute.java index 9d628acd96..7229a23bff 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotHttpDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataBridgeExecute.java @@ -1,11 +1,11 @@ -package cn.iocoder.yudao.module.iot.service.rule.action.databridge; +package cn.iocoder.yudao.module.iot.service.rule.data.action; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.util.http.HttpUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.databridge.config.IotDataBridgeHttpConfig; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataBridgeHttpConfig; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.enums.rule.IotDataRuleSinkTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotDataSinkTypeEnum; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.http.*; @@ -30,7 +30,7 @@ public class IotHttpDataBridgeExecute implements IotDataBridgeExecute action, IotDataBridgeAbstractConfig config, String type) throws Exception { log.info("[test{}DataBridge][第一次执行,应该会创建新的 producer]", type); - action.execute(message, new IotDataRuleSinkDO().setType(action.getType()).setConfig(config)); + action.execute(message, new IotDataSinkDO().setType(action.getType()).setConfig(config)); log.info("[test{}DataBridge][第二次执行,应该会复用缓存的 producer]", type); - action.execute(message, new IotDataRuleSinkDO().setType(action.getType()).setConfig(config)); + action.execute(message, new IotDataSinkDO().setType(action.getType()).setConfig(config)); } } From 956418d31fa247b42247d36add038d8b99530e16 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 24 Jun 2025 21:21:35 +0800 Subject: [PATCH 04/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E5=88=9D=E6=AD=A5=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E2=80=9C=E6=95=B0=E6=8D=AE=E6=B5=81=E8=BD=AC=E2=80=9D=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 11 +-- .../admin/rule/IotDataRuleController.java | 72 +++++++++++++++++++ .../admin/rule/IotDataSinkController.java | 2 +- .../vo/data/rule/IotDataRulePageReqVO.java | 26 +++++++ .../rule/vo/data/rule/IotDataRuleRespVO.java | 35 +++++++++ .../vo/data/rule/IotDataRuleSaveReqVO.java | 40 +++++++++++ .../rule/vo/data/sink/IotDataSinkRespVO.java | 4 +- .../vo/data/sink/IotDataSinkSaveReqVO.java | 4 +- .../dal/dataobject/rule/IotDataRuleDO.java | 20 +++--- .../dal/dataobject/rule/IotDataSinkDO.java | 16 ++--- .../dal/dataobject/rule/IotRuleSceneDO.java | 3 +- ...ig.java => IotAbstractDataSinkConfig.java} | 14 ++-- ...Config.java => IotDataSinkHttpConfig.java} | 4 +- ...onfig.java => IotDataSinkKafkaConfig.java} | 4 +- ...Config.java => IotDataSinkMqttConfig.java} | 4 +- ...ig.java => IotDataSinkRabbitMQConfig.java} | 4 +- ...java => IotDataSinkRedisStreamConfig.java} | 4 +- ...ig.java => IotDataSinkRocketMQConfig.java} | 4 +- .../iot/dal/mysql/rule/IotDataRuleMapper.java | 26 +++++++ .../service/rule/data/IotDataRuleService.java | 54 ++++++++++++++ .../rule/data/IotDataRuleServiceImpl.java | 68 ++++++++++++++++++ .../service/rule/data/IotDataSinkService.java | 18 ++--- .../data/IotRuleSceneDataBridgeAction.java | 10 +-- .../AbstractCacheableDataBridgeExecute.java | 2 +- .../data/action/IotDataBridgeExecute.java | 16 ++--- .../data/action/IotHttpDataBridgeExecute.java | 6 +- .../action/IotKafkaMQDataBridgeExecute.java | 8 +-- .../action/IotRabbitMQDataBridgeExecute.java | 8 +-- .../IotRedisStreamDataBridgeExecute.java | 8 +-- .../action/IotRocketMQDataBridgeExecute.java | 8 +-- .../databridge/IotDataBridgeExecuteTest.java | 14 ++-- 31 files changed, 423 insertions(+), 94 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataRuleController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRulePageReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRuleRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRuleSaveReqVO.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/{IotDataBridgeAbstractConfig.java => IotAbstractDataSinkConfig.java} (58%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/{IotDataBridgeHttpConfig.java => IotDataSinkHttpConfig.java} (77%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/{IotDataBridgeKafkaMQConfig.java => IotDataSinkKafkaConfig.java} (75%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/{IotDataBridgeMqttConfig.java => IotDataSinkMqttConfig.java} (75%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/{IotDataBridgeRabbitMQConfig.java => IotDataSinkRabbitMQConfig.java} (81%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/{IotDataBridgeRedisStreamConfig.java => IotDataSinkRedisStreamConfig.java} (73%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/{IotDataBridgeRocketMQConfig.java => IotDataSinkRocketMQConfig.java} (77%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataRuleMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index e12b3640e7..4bacac016d 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -54,10 +54,13 @@ public interface ErrorCodeConstants { ErrorCode OTA_UPGRADE_RECORD_DUPLICATE = new ErrorCode(1_050_008_201, "升级记录重复"); ErrorCode OTA_UPGRADE_RECORD_CANNOT_RETRY = new ErrorCode(1_050_008_202, "升级记录不能重试"); - // ========== IoT 数据桥梁 1-050-010-000 ========== - ErrorCode DATA_BRIDGE_NOT_EXISTS = new ErrorCode(1_050_010_000, "IoT 数据桥梁不存在"); + // ========== IoT 数据流转规则 1-050-010-000 ========== + ErrorCode DATA_RULE_NOT_EXISTS = new ErrorCode(1_050_010_000, "数据流转规则不存在"); - // ========== IoT 场景联动 1-050-011-000 ========== - ErrorCode RULE_SCENE_NOT_EXISTS = new ErrorCode(1_050_011_000, "IoT 场景联动不存在"); + // ========== IoT 数据流转目的 1-050-011-000 ========== + ErrorCode DATA_BRIDGE_NOT_EXISTS = new ErrorCode(1_050_011_000, "数据桥梁不存在"); + + // ========== IoT 场景联动 1-050-012-000 ========== + ErrorCode RULE_SCENE_NOT_EXISTS = new ErrorCode(1_050_012_000, "场景联动不存在"); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataRuleController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataRuleController.java new file mode 100644 index 0000000000..f7e64b160d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataRuleController.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRulePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRuleRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRuleSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleDO; +import cn.iocoder.yudao.module.iot.service.rule.data.IotDataRuleService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - IoT 数据流转规则") +@RestController +@RequestMapping("/iot/data-rule") +@Validated +public class IotDataRuleController { + + @Resource + private IotDataRuleService dataRuleService; + + @PostMapping("/create") + @Operation(summary = "创建数据流转规则") + @PreAuthorize("@ss.hasPermission('iot:data-rule:create')") + public CommonResult createDataRule(@Valid @RequestBody IotDataRuleSaveReqVO createReqVO) { + return success(dataRuleService.createDataRule(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新数据流转规则") + @PreAuthorize("@ss.hasPermission('iot:data-rule:update')") + public CommonResult updateDataRule(@Valid @RequestBody IotDataRuleSaveReqVO updateReqVO) { + dataRuleService.updateDataRule(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除数据流转规则") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:data-rule:delete')") + public CommonResult deleteDataRule(@RequestParam("id") Long id) { + dataRuleService.deleteDataRule(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得数据流转规则") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:data-rule:query')") + public CommonResult getDataRule(@RequestParam("id") Long id) { + IotDataRuleDO dataRule = dataRuleService.getDataRule(id); + return success(BeanUtils.toBean(dataRule, IotDataRuleRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得数据流转规则分页") + @PreAuthorize("@ss.hasPermission('iot:data-rule:query')") + public CommonResult> getDataRulePage(@Valid IotDataRulePageReqVO pageReqVO) { + PageResult pageResult = dataRuleService.getDataRulePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotDataRuleRespVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataSinkController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataSinkController.java index c5232d3d08..6e1aae797c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataSinkController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotDataSinkController.java @@ -75,7 +75,7 @@ public class IotDataSinkController { @GetMapping("/simple-list") @Operation(summary = "获取数据目的的精简信息列表", description = "主要用于前端的下拉选项") - public CommonResult> getSimpleDataSinkList() { + public CommonResult> getDataSinkSimpleList() { List list = dataSinkService.getDataSinkListByStatus(CommonStatusEnum.ENABLE.getStatus()); return success(convertList(list, sink -> // 只返回 id、name 字段 new IotDataSinkRespVO().setId(sink.getId()).setName(sink.getName()))); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRulePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRulePageReqVO.java new file mode 100644 index 0000000000..9cbb747db4 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRulePageReqVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - IoT 数据流转规则分页 Request VO") +@Data +public class IotDataRulePageReqVO extends PageParam { + + @Schema(description = "场景名称", example = "芋艿") + private String name; + + @Schema(description = "场景状态", example = "1") + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRuleRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRuleRespVO.java new file mode 100644 index 0000000000..374b08a7cd --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRuleRespVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule; + +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleDO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - IoT 数据流转规则 Response VO") +@Data +public class IotDataRuleRespVO { + + @Schema(description = "场景编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8540") + private Long id; + + @Schema(description = "场景名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + private String name; + + @Schema(description = "场景描述", example = "你猜") + private String description; + + @Schema(description = "场景状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "数据源配置数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List sourceConfigs; + + @Schema(description = "数据目的编号数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List sinkIds; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRuleSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRuleSaveReqVO.java new file mode 100644 index 0000000000..2928861169 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRuleSaveReqVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleDO; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.List; + +@Schema(description = "管理后台 - IoT 数据流转规则新增/修改 Request VO") +@Data +public class IotDataRuleSaveReqVO { + + @Schema(description = "场景编号", example = "8540") + private Long id; + + @Schema(description = "场景名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @NotEmpty(message = "场景名称不能为空") + private String name; + + @Schema(description = "场景描述", example = "你猜") + private String description; + + @Schema(description = "场景状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "场景状态不能为空") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @Schema(description = "数据源配置数组", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "数据源配置数组不能为空") + private List sourceConfigs; + + @Schema(description = "数据目的编号数组", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "数据目的编号数组不能为空") + private List sinkIds; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/sink/IotDataSinkRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/sink/IotDataSinkRespVO.java index b00e8a3b79..0ced03c225 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/sink/IotDataSinkRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/sink/IotDataSinkRespVO.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataBridgeAbstractConfig; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotAbstractDataSinkConfig; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -26,7 +26,7 @@ public class IotDataSinkRespVO { private Integer type; @Schema(description = "数据目的配置") - private IotDataBridgeAbstractConfig config; + private IotAbstractDataSinkConfig config; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime createTime; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/sink/IotDataSinkSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/sink/IotDataSinkSaveReqVO.java index b178e09c56..b0e49dedd7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/sink/IotDataSinkSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/sink/IotDataSinkSaveReqVO.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataBridgeAbstractConfig; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotAbstractDataSinkConfig; import cn.iocoder.yudao.module.iot.enums.rule.IotDataSinkTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; @@ -35,6 +35,6 @@ public class IotDataSinkSaveReqVO { @Schema(description = "数据目的配置") @NotNull(message = "数据目的配置不能为空") - private IotDataBridgeAbstractConfig config; + private IotAbstractDataSinkConfig config; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleDO.java index 1cf766c488..191df10d06 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataRuleDO.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.rule; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; @@ -10,6 +11,7 @@ import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import jakarta.validation.constraints.NotEmpty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -24,28 +26,28 @@ import java.util.List; * * @author 芋道源码 */ -@TableName(value = "iot_data_flow", autoResultMap = true) -@KeySequence("iot_data_flow_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@TableName(value = "iot_data_rule", autoResultMap = true) +@KeySequence("iot_data_rule_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Builder @NoArgsConstructor @AllArgsConstructor -public class IotDataRuleDO { +public class IotDataRuleDO extends BaseDO { /** - * 数据流转编号 + * 数据流转规格编号 */ private Long id; /** - * 数据流转名称 + * 数据流转规格名称 */ private String name; /** - * 数据流转描述 + * 数据流转规格描述 */ private String description; /** - * 数据流转状态 + * 数据流转规格状态 * * 枚举 {@link CommonStatusEnum} */ @@ -57,7 +59,7 @@ public class IotDataRuleDO { @TableField(typeHandler = JacksonTypeHandler.class) private List sourceConfigs; /** - * 数据目的编号 + * 数据目的编号数组 * * 关联 {@link IotDataSinkDO#getId()} */ @@ -77,6 +79,7 @@ public class IotDataRuleDO { * * 枚举 {@link IotDeviceMessageMethodEnum} 中的 upstream 上行部分 */ + @NotEmpty(message = "消息方法不能为空") private String method; /** @@ -91,6 +94,7 @@ public class IotDataRuleDO { * 关联 {@link IotDeviceDO#getId()} * 特殊:如果为 {@link IotDeviceDO#DEVICE_ID_ALL} 时,则是全部设备 */ + @NotEmpty(message = "设备编号不能为空") private Long deviceId; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataSinkDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataSinkDO.java index 16b3d6398f..a3cb48e3fd 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataSinkDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataSinkDO.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.rule; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataBridgeAbstractConfig; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotAbstractDataSinkConfig; import cn.iocoder.yudao.module.iot.enums.rule.IotDataSinkTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; @@ -28,35 +28,35 @@ import lombok.NoArgsConstructor; public class IotDataSinkDO extends BaseDO { /** - * 数据目的编号 + * 数据流转目的编号 */ @TableId private Long id; /** - * 数据目的名称 + * 数据流转目的名称 */ private String name; /** - * 数据目的描述 + * 数据流转目的描述 */ private String description; /** - * 数据目的状态 + * 数据流转目的状态 * * 枚举 {@link CommonStatusEnum} */ private Integer status; /** - * 数据目的类型 + * 数据流转目的类型 * * 枚举 {@link IotDataSinkTypeEnum} */ private Integer type; /** - * 数据目的配置 + * 数据流转目的配置 */ @TableField(typeHandler = JacksonTypeHandler.class) - private IotDataBridgeAbstractConfig config; + private IotAbstractDataSinkConfig config; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java index 845b18989c..9d25d66c7b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java @@ -22,8 +22,9 @@ import lombok.NoArgsConstructor; import java.util.List; import java.util.Map; +// TODO @芋艿:优化注释; /** - * IoT 场景联动 DO + * IoT 场景联动规则 DO * * @author 芋道源码 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeAbstractConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotAbstractDataSinkConfig.java similarity index 58% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeAbstractConfig.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotAbstractDataSinkConfig.java index d15008b939..4d08d43410 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeAbstractConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotAbstractDataSinkConfig.java @@ -16,14 +16,14 @@ import lombok.Data; @Data @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true) @JsonSubTypes({ - @JsonSubTypes.Type(value = IotDataBridgeHttpConfig.class, name = "1"), - @JsonSubTypes.Type(value = IotDataBridgeMqttConfig.class, name = "10"), - @JsonSubTypes.Type(value = IotDataBridgeRedisStreamConfig.class, name = "21"), - @JsonSubTypes.Type(value = IotDataBridgeRocketMQConfig.class, name = "30"), - @JsonSubTypes.Type(value = IotDataBridgeRabbitMQConfig.class, name = "31"), - @JsonSubTypes.Type(value = IotDataBridgeKafkaMQConfig.class, name = "32"), + @JsonSubTypes.Type(value = IotDataSinkHttpConfig.class, name = "1"), + @JsonSubTypes.Type(value = IotDataSinkMqttConfig.class, name = "10"), + @JsonSubTypes.Type(value = IotDataSinkRedisStreamConfig.class, name = "21"), + @JsonSubTypes.Type(value = IotDataSinkRocketMQConfig.class, name = "30"), + @JsonSubTypes.Type(value = IotDataSinkRabbitMQConfig.class, name = "31"), + @JsonSubTypes.Type(value = IotDataSinkKafkaConfig.class, name = "32"), }) -public abstract class IotDataBridgeAbstractConfig { +public abstract class IotAbstractDataSinkConfig { /** * 配置类型 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeHttpConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkHttpConfig.java similarity index 77% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeHttpConfig.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkHttpConfig.java index 7e65bd4b45..1a702b4ae0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeHttpConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkHttpConfig.java @@ -5,12 +5,12 @@ import lombok.Data; import java.util.Map; /** - * IoT HTTP 配置 {@link IotDataBridgeAbstractConfig} 实现类 + * IoT HTTP 配置 {@link IotAbstractDataSinkConfig} 实现类 * * @author HUIHUI */ @Data -public class IotDataBridgeHttpConfig extends IotDataBridgeAbstractConfig { +public class IotDataSinkHttpConfig extends IotAbstractDataSinkConfig { /** * 请求 URL diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeKafkaMQConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkKafkaConfig.java similarity index 75% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeKafkaMQConfig.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkKafkaConfig.java index e0ecd43792..1516918df3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeKafkaMQConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkKafkaConfig.java @@ -3,12 +3,12 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.rule.config; import lombok.Data; /** - * IoT Kafka 配置 {@link IotDataBridgeAbstractConfig} 实现类 + * IoT Kafka 配置 {@link IotAbstractDataSinkConfig} 实现类 * * @author HUIHUI */ @Data -public class IotDataBridgeKafkaMQConfig extends IotDataBridgeAbstractConfig { +public class IotDataSinkKafkaConfig extends IotAbstractDataSinkConfig { /** * Kafka 服务器地址 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeMqttConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkMqttConfig.java similarity index 75% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeMqttConfig.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkMqttConfig.java index 7500fa35ab..ebc0869e15 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeMqttConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkMqttConfig.java @@ -3,12 +3,12 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.rule.config; import lombok.Data; /** - * IoT MQTT 配置 {@link IotDataBridgeAbstractConfig} 实现类 + * IoT MQTT 配置 {@link IotAbstractDataSinkConfig} 实现类 * * @author HUIHUI */ @Data -public class IotDataBridgeMqttConfig extends IotDataBridgeAbstractConfig { +public class IotDataSinkMqttConfig extends IotAbstractDataSinkConfig { /** * MQTT 服务器地址 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeRabbitMQConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkRabbitMQConfig.java similarity index 81% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeRabbitMQConfig.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkRabbitMQConfig.java index b899b5fadb..0e95603849 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeRabbitMQConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkRabbitMQConfig.java @@ -3,12 +3,12 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.rule.config; import lombok.Data; /** - * IoT RabbitMQ 配置 {@link IotDataBridgeAbstractConfig} 实现类 + * IoT RabbitMQ 配置 {@link IotAbstractDataSinkConfig} 实现类 * * @author HUIHUI */ @Data -public class IotDataBridgeRabbitMQConfig extends IotDataBridgeAbstractConfig { +public class IotDataSinkRabbitMQConfig extends IotAbstractDataSinkConfig { /** * RabbitMQ 服务器地址 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeRedisStreamConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkRedisStreamConfig.java similarity index 73% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeRedisStreamConfig.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkRedisStreamConfig.java index 5ece7f6cf1..4df0ad7c38 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeRedisStreamConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkRedisStreamConfig.java @@ -3,12 +3,12 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.rule.config; import lombok.Data; /** - * IoT Redis Stream 配置 {@link IotDataBridgeAbstractConfig} 实现类 + * IoT Redis Stream 配置 {@link IotAbstractDataSinkConfig} 实现类 * * @author HUIHUI */ @Data -public class IotDataBridgeRedisStreamConfig extends IotDataBridgeAbstractConfig { +public class IotDataSinkRedisStreamConfig extends IotAbstractDataSinkConfig { /** * Redis 服务器地址 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeRocketMQConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkRocketMQConfig.java similarity index 77% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeRocketMQConfig.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkRocketMQConfig.java index 4cc73c5c5a..65fd3e0532 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataBridgeRocketMQConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkRocketMQConfig.java @@ -3,12 +3,12 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.rule.config; import lombok.Data; /** - * IoT RocketMQ 配置 {@link IotDataBridgeAbstractConfig} 实现类 + * IoT RocketMQ 配置 {@link IotAbstractDataSinkConfig} 实现类 * * @author HUIHUI */ @Data -public class IotDataBridgeRocketMQConfig extends IotDataBridgeAbstractConfig { +public class IotDataSinkRocketMQConfig extends IotAbstractDataSinkConfig { /** * RocketMQ 名称服务器地址 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataRuleMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataRuleMapper.java new file mode 100644 index 0000000000..6f8d7b860a --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataRuleMapper.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.rule; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRulePageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * IoT 数据流转规则 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface IotDataRuleMapper extends BaseMapperX { + + default PageResult selectPage(IotDataRulePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(IotDataRuleDO::getName, reqVO.getName()) + .eqIfPresent(IotDataRuleDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(IotDataRuleDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(IotDataRuleDO::getId)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleService.java new file mode 100644 index 0000000000..a51e384139 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleService.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.iot.service.rule.data; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRulePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRuleSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleDO; +import jakarta.validation.Valid; + +/** + * IoT 数据流转规则 Service 接口 + * + * @author 芋道源码 + */ +public interface IotDataRuleService { + + /** + * 创建数据流转规则 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDataRule(@Valid IotDataRuleSaveReqVO createReqVO); + + /** + * 更新数据流转规则 + * + * @param updateReqVO 更新信息 + */ + void updateDataRule(@Valid IotDataRuleSaveReqVO updateReqVO); + + /** + * 删除数据流转规则 + * + * @param id 编号 + */ + void deleteDataRule(Long id); + + /** + * 获得数据流转规则 + * + * @param id 编号 + * @return 数据流转规则 + */ + IotDataRuleDO getDataRule(Long id); + + /** + * 获得数据流转规则分页 + * + * @param pageReqVO 分页查询 + * @return 数据流转规则分页 + */ + PageResult getDataRulePage(IotDataRulePageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java new file mode 100644 index 0000000000..df6d3e11f4 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.module.iot.service.rule.data; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRulePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRuleSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleDO; +import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotDataRuleMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DATA_RULE_NOT_EXISTS; + +/** + * IoT 数据流转规则 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class IotDataRuleServiceImpl implements IotDataRuleService { + + @Resource + private IotDataRuleMapper dataRuleMapper; + + @Override + public Long createDataRule(IotDataRuleSaveReqVO createReqVO) { + IotDataRuleDO dataRule = BeanUtils.toBean(createReqVO, IotDataRuleDO.class); + dataRuleMapper.insert(dataRule); + return dataRule.getId(); + } + + @Override + public void updateDataRule(IotDataRuleSaveReqVO updateReqVO) { + // 校验存在 + validateDataRuleExists(updateReqVO.getId()); + // 更新 + IotDataRuleDO updateObj = BeanUtils.toBean(updateReqVO, IotDataRuleDO.class); + dataRuleMapper.updateById(updateObj); + } + + @Override + public void deleteDataRule(Long id) { + // 校验存在 + validateDataRuleExists(id); + // 删除 + dataRuleMapper.deleteById(id); + } + + private void validateDataRuleExists(Long id) { + if (dataRuleMapper.selectById(id) == null) { + throw exception(DATA_RULE_NOT_EXISTS); + } + } + + @Override + public IotDataRuleDO getDataRule(Long id) { + return dataRuleMapper.selectById(id); + } + + @Override + public PageResult getDataRulePage(IotDataRulePageReqVO pageReqVO) { + return dataRuleMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkService.java index 6057303f43..4c325f0a24 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkService.java @@ -16,7 +16,7 @@ import java.util.List; public interface IotDataSinkService { /** - * 创建数据目的 + * 创建数据流转目的 * * @param createReqVO 创建信息 * @return 编号 @@ -24,40 +24,40 @@ public interface IotDataSinkService { Long createDataSink(@Valid IotDataSinkSaveReqVO createReqVO); /** - * 更新数据目的 + * 更新数据流转目的 * * @param updateReqVO 更新信息 */ void updateDataSink(@Valid IotDataSinkSaveReqVO updateReqVO); /** - * 删除数据目的 + * 删除数据流转目的 * * @param id 编号 */ void deleteDataSink(Long id); /** - * 获得数据目的 + * 获得数据流转目的 * * @param id 编号 - * @return 数据目的 + * @return 数据流转目的 */ IotDataSinkDO getDataSink(Long id); /** - * 获得数据目的分页 + * 获得数据流转目的分页 * * @param pageReqVO 分页查询 - * @return 数据目的分页 + * @return 数据流转目的分页 */ PageResult getDataSinkPage(IotDataSinkPageReqVO pageReqVO); /** - * 获取数据目的列表 + * 获取数据流转目的列表 * * @param status 状态,如果为空,则不进行筛选 - * @return 数据目的列表 + * @return 数据流转目的列表 */ List getDataSinkListByStatus(Integer status); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotRuleSceneDataBridgeAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotRuleSceneDataBridgeAction.java index 459f959981..08b76be5df 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotRuleSceneDataBridgeAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotRuleSceneDataBridgeAction.java @@ -15,7 +15,7 @@ import org.springframework.stereotype.Component; import java.util.List; /** - * IoT 数据桥梁的 {@link IotRuleSceneAction} 实现类 + * IoT 数据流转目的的 {@link IotRuleSceneAction} 实现类 * * @author 芋道源码 */ @@ -35,15 +35,15 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { if (message == null) { return; } - // 1.2 获得数据桥梁 - Assert.notNull(config.getDataBridgeId(), "数据桥梁编号不能为空"); + // 1.2 获得数据流转目的 + Assert.notNull(config.getDataBridgeId(), "数据流转目的编号不能为空"); IotDataSinkDO dataBridge = dataBridgeService.getDataSink(config.getDataBridgeId()); if (dataBridge == null || dataBridge.getConfig() == null) { - log.error("[execute][message({}) config({}) 对应的数据桥梁不存在]", message, config); + log.error("[execute][message({}) config({}) 对应的数据流转目的不存在]", message, config); return; } if (CommonStatusEnum.isDisable(dataBridge.getStatus())) { - log.info("[execute][message({}) config({}) 对应的数据桥梁({}) 状态为禁用]", message, config, dataBridge); + log.info("[execute][message({}) config({}) 对应的数据流转目的({}) 状态为禁用]", message, config, dataBridge); return; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/AbstractCacheableDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/AbstractCacheableDataBridgeExecute.java index e78a1e4683..584285e53c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/AbstractCacheableDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/AbstractCacheableDataBridgeExecute.java @@ -17,7 +17,7 @@ import java.time.Duration; // TODO @芋艿:websocket /** - * 带缓存功能的数据桥梁执行器抽象类 + * 带缓存功能的数据流转目的执行器抽象类 * * 该类提供了一个通用的缓存机制,用于管理各类数据桥接的生产者(Producer)实例。 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotDataBridgeExecute.java index e2b69a907b..48e7f47cc3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotDataBridgeExecute.java @@ -4,38 +4,38 @@ import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; /** - * IoT 数据桥梁的执行器 execute 接口 + * IoT 数据流转目的的执行器 execute 接口 * * @author HUIHUI */ public interface IotDataBridgeExecute { /** - * 获取数据桥梁类型 + * 获取数据流转目的类型 * - * @return 数据桥梁类型 + * @return 数据流转目的类型 */ Integer getType(); /** - * 执行数据桥梁操作 + * 执行数据流转目的操作 * * @param message 设备消息 - * @param dataBridge 数据桥梁 + * @param dataBridge 数据流转目的 */ @SuppressWarnings({"unchecked"}) default void execute(IotDeviceMessage message, IotDataSinkDO dataBridge) throws Exception { - // 1.1 校验数据桥梁类型 + // 1.1 校验数据流转目的类型 if (!getType().equals(dataBridge.getType())) { return; } - // 1.2 执行对应的数据桥梁发送消息 + // 1.2 执行对应的数据流转目的发送消息 execute0(message, (Config) dataBridge.getConfig()); } /** - * 【真正】执行数据桥梁操作 + * 【真正】执行数据流转目的操作 * * @param message 设备消息 * @param config 桥梁配置 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataBridgeExecute.java index 7229a23bff..da02677aae 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataBridgeExecute.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.service.rule.data.action; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.util.http.HttpUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataBridgeHttpConfig; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataSinkHttpConfig; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.enums.rule.IotDataSinkTypeEnum; import jakarta.annotation.Resource; @@ -23,7 +23,7 @@ import java.util.Map; */ @Component @Slf4j -public class IotHttpDataBridgeExecute implements IotDataBridgeExecute { +public class IotHttpDataBridgeExecute implements IotDataBridgeExecute { @Resource private RestTemplate restTemplate; @@ -35,7 +35,7 @@ public class IotHttpDataBridgeExecute implements IotDataBridgeExecute requestEntity = null; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotKafkaMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotKafkaMQDataBridgeExecute.java index 9ee08b0435..ec7eade63f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotKafkaMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotKafkaMQDataBridgeExecute.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.service.rule.data.action; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataBridgeKafkaMQConfig; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataSinkKafkaConfig; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.enums.rule.IotDataSinkTypeEnum; import lombok.extern.slf4j.Slf4j; @@ -25,7 +25,7 @@ import java.util.concurrent.TimeUnit; @Component @Slf4j public class IotKafkaMQDataBridgeExecute extends - AbstractCacheableDataBridgeExecute> { + AbstractCacheableDataBridgeExecute> { private static final Duration SEND_TIMEOUT = Duration.ofMillis(10000); // 10 秒超时时间 @@ -35,7 +35,7 @@ public class IotKafkaMQDataBridgeExecute extends } @Override - public void execute0(IotDeviceMessage message, IotDataBridgeKafkaMQConfig config) throws Exception { + public void execute0(IotDeviceMessage message, IotDataSinkKafkaConfig config) throws Exception { // 1. 获取或创建 KafkaTemplate KafkaTemplate kafkaTemplate = getProducer(config); @@ -46,7 +46,7 @@ public class IotKafkaMQDataBridgeExecute extends } @Override - protected KafkaTemplate initProducer(IotDataBridgeKafkaMQConfig config) { + protected KafkaTemplate initProducer(IotDataSinkKafkaConfig config) { // 1.1 构建生产者配置 Map props = new HashMap<>(); props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, config.getBootstrapServers()); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRabbitMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRabbitMQDataBridgeExecute.java index 597bbf3f17..d8abaa7602 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRabbitMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRabbitMQDataBridgeExecute.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.service.rule.data.action; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataBridgeRabbitMQConfig; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataSinkRabbitMQConfig; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.enums.rule.IotDataSinkTypeEnum; import com.rabbitmq.client.Channel; @@ -21,7 +21,7 @@ import java.nio.charset.StandardCharsets; @Component @Slf4j public class IotRabbitMQDataBridgeExecute extends - AbstractCacheableDataBridgeExecute { + AbstractCacheableDataBridgeExecute { @Override @@ -30,7 +30,7 @@ public class IotRabbitMQDataBridgeExecute extends } @Override - public void execute0(IotDeviceMessage message, IotDataBridgeRabbitMQConfig config) throws Exception { + public void execute0(IotDeviceMessage message, IotDataSinkRabbitMQConfig config) throws Exception { // 1. 获取或创建 Channel Channel channel = getProducer(config); @@ -47,7 +47,7 @@ public class IotRabbitMQDataBridgeExecute extends @Override @SuppressWarnings("resource") - protected Channel initProducer(IotDataBridgeRabbitMQConfig config) throws Exception { + protected Channel initProducer(IotDataSinkRabbitMQConfig config) throws Exception { // 1. 创建连接工厂 ConnectionFactory factory = new ConnectionFactory(); factory.setHost(config.getHost()); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRedisStreamDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRedisStreamDataBridgeExecute.java index 7906bec9a2..be3370461a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRedisStreamDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRedisStreamDataBridgeExecute.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.iot.service.rule.data.action; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataBridgeRedisStreamConfig; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataSinkRedisStreamConfig; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.enums.rule.IotDataSinkTypeEnum; import lombok.extern.slf4j.Slf4j; @@ -25,7 +25,7 @@ import org.springframework.stereotype.Component; @Component @Slf4j public class IotRedisStreamDataBridgeExecute extends - AbstractCacheableDataBridgeExecute> { + AbstractCacheableDataBridgeExecute> { @Override public Integer getType() { @@ -33,7 +33,7 @@ public class IotRedisStreamDataBridgeExecute extends } @Override - public void execute0(IotDeviceMessage message, IotDataBridgeRedisStreamConfig config) throws Exception { + public void execute0(IotDeviceMessage message, IotDataSinkRedisStreamConfig config) throws Exception { // 1. 获取 RedisTemplate RedisTemplate redisTemplate = getProducer(config); @@ -45,7 +45,7 @@ public class IotRedisStreamDataBridgeExecute extends } @Override - protected RedisTemplate initProducer(IotDataBridgeRedisStreamConfig config) { + protected RedisTemplate initProducer(IotDataSinkRedisStreamConfig config) { // 1.1 创建 Redisson 配置 Config redissonConfig = new Config(); SingleServerConfig serverConfig = redissonConfig.useSingleServer() diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRocketMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRocketMQDataBridgeExecute.java index 910b644d8a..6a8d66842b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRocketMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRocketMQDataBridgeExecute.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.service.rule.data.action; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataBridgeRocketMQConfig; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataSinkRocketMQConfig; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.enums.rule.IotDataSinkTypeEnum; import lombok.extern.slf4j.Slf4j; @@ -21,7 +21,7 @@ import org.springframework.stereotype.Component; @Component @Slf4j public class IotRocketMQDataBridgeExecute extends - AbstractCacheableDataBridgeExecute { + AbstractCacheableDataBridgeExecute { @Override public Integer getType() { @@ -29,7 +29,7 @@ public class IotRocketMQDataBridgeExecute extends } @Override - public void execute0(IotDeviceMessage message, IotDataBridgeRocketMQConfig config) throws Exception { + public void execute0(IotDeviceMessage message, IotDataSinkRocketMQConfig config) throws Exception { // 1. 获取或创建 Producer DefaultMQProducer producer = getProducer(config); @@ -50,7 +50,7 @@ public class IotRocketMQDataBridgeExecute extends } @Override - protected DefaultMQProducer initProducer(IotDataBridgeRocketMQConfig config) throws Exception { + protected DefaultMQProducer initProducer(IotDataSinkRocketMQConfig config) throws Exception { DefaultMQProducer producer = new DefaultMQProducer(config.getGroup()); producer.setNamesrvAddr(config.getNameServer()); producer.start(); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java index 802cc6ab26..52599c455f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java @@ -2,8 +2,8 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; import cn.iocoder.yudao.module.iot.service.rule.data.action.*; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; @@ -54,7 +54,7 @@ public class IotDataBridgeExecuteTest extends BaseMockitoUnitTest { IotKafkaMQDataBridgeExecute action = new IotKafkaMQDataBridgeExecute(); // 2. 创建配置 - IotDataBridgeKafkaMQConfig config = new IotDataBridgeKafkaMQConfig() + IotDataSinkKafkaConfig config = new IotDataSinkKafkaConfig() .setBootstrapServers("127.0.0.1:9092") .setTopic("test-topic") .setSsl(false) @@ -71,7 +71,7 @@ public class IotDataBridgeExecuteTest extends BaseMockitoUnitTest { IotRabbitMQDataBridgeExecute action = new IotRabbitMQDataBridgeExecute(); // 2. 创建配置 - IotDataBridgeRabbitMQConfig config = new IotDataBridgeRabbitMQConfig() + IotDataSinkRabbitMQConfig config = new IotDataSinkRabbitMQConfig() .setHost("localhost") .setPort(5672) .setVirtualHost("/") @@ -91,7 +91,7 @@ public class IotDataBridgeExecuteTest extends BaseMockitoUnitTest { IotRedisStreamDataBridgeExecute action = new IotRedisStreamDataBridgeExecute(); // 2. 创建配置 - IotDataBridgeRedisStreamConfig config = new IotDataBridgeRedisStreamConfig() + IotDataSinkRedisStreamConfig config = new IotDataSinkRedisStreamConfig() .setHost("127.0.0.1") .setPort(6379) .setDatabase(0) @@ -108,7 +108,7 @@ public class IotDataBridgeExecuteTest extends BaseMockitoUnitTest { IotRocketMQDataBridgeExecute action = new IotRocketMQDataBridgeExecute(); // 2. 创建配置 - IotDataBridgeRocketMQConfig config = new IotDataBridgeRocketMQConfig() + IotDataSinkRocketMQConfig config = new IotDataSinkRocketMQConfig() .setNameServer("127.0.0.1:9876") .setGroup("test-group") .setTopic("test-topic") @@ -125,7 +125,7 @@ public class IotDataBridgeExecuteTest extends BaseMockitoUnitTest { .thenReturn(new ResponseEntity<>("Success", HttpStatus.OK)); // 2. 创建配置 - IotDataBridgeHttpConfig config = new IotDataBridgeHttpConfig() + IotDataSinkHttpConfig config = new IotDataSinkHttpConfig() .setUrl("https://doc.iocoder.cn/").setMethod(HttpMethod.GET.name()); // 3. 执行测试 @@ -142,7 +142,7 @@ public class IotDataBridgeExecuteTest extends BaseMockitoUnitTest { * @param type MQ 类型 * @throws Exception 如果执行过程中发生异常 */ - private void executeAndVerifyCache(IotDataBridgeExecute action, IotDataBridgeAbstractConfig config, String type) + private void executeAndVerifyCache(IotDataBridgeExecute action, IotAbstractDataSinkConfig config, String type) throws Exception { log.info("[test{}DataBridge][第一次执行,应该会创建新的 producer]", type); action.execute(message, new IotDataSinkDO().setType(action.getType()).setConfig(config)); From 2a04bdc3fe8998c02ea12477deeb251923e0083c Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 25 Jun 2025 21:45:02 +0800 Subject: [PATCH 05/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E5=AE=8C=E6=95=B4=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E2=80=9C=E6=95=B0=E6=8D=AE=E6=B5=81=E8=BD=AC=E2=80=9D=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=88=E5=90=8E=E5=8F=B0=E7=AE=A1=E7=90=86=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 3 +- .../admin/device/IotDeviceController.java | 10 +-- .../admin/product/IotProductController.java | 2 +- .../vo/data/rule/IotDataRulePageReqVO.java | 4 +- .../rule/vo/data/rule/IotDataRuleRespVO.java | 8 +- .../vo/data/rule/IotDataRuleSaveReqVO.java | 12 +-- .../iot/dal/mysql/device/IotDeviceMapper.java | 7 +- .../iot/dal/mysql/rule/IotDataRuleMapper.java | 8 ++ .../iot/service/device/IotDeviceService.java | 8 ++ .../service/device/IotDeviceServiceImpl.java | 11 +++ .../service/product/IotProductService.java | 7 ++ .../product/IotProductServiceImpl.java | 13 +++ .../service/rule/data/IotDataRuleService.java | 10 +++ .../rule/data/IotDataRuleServiceImpl.java | 79 +++++++++++++++++++ .../service/rule/data/IotDataSinkService.java | 8 ++ .../rule/data/IotDataSinkServiceImpl.java | 27 ++++++- .../thingmodel/IotThingModelService.java | 9 +++ .../thingmodel/IotThingModelServiceImpl.java | 15 ++++ 18 files changed, 216 insertions(+), 25 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 4bacac016d..8217a5b2ae 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -58,7 +58,8 @@ public interface ErrorCodeConstants { ErrorCode DATA_RULE_NOT_EXISTS = new ErrorCode(1_050_010_000, "数据流转规则不存在"); // ========== IoT 数据流转目的 1-050-011-000 ========== - ErrorCode DATA_BRIDGE_NOT_EXISTS = new ErrorCode(1_050_011_000, "数据桥梁不存在"); + ErrorCode DATA_SINK_NOT_EXISTS = new ErrorCode(1_050_011_000, "数据桥梁不存在"); + ErrorCode DATA_SINK_DELETE_FAIL_USED_BY_RULE = new ErrorCode(1_050_011_001, "数据流转目的正在被数据流转规则使用,无法删除"); // ========== IoT 场景联动 1-050-012-000 ========== ErrorCode RULE_SCENE_NOT_EXISTS = new ErrorCode(1_050_012_000, "场景联动不存在"); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java index 60ae9eb87f..052d34edc4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -9,7 +9,6 @@ import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; -import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceMessageService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -38,8 +37,6 @@ public class IotDeviceController { @Resource private IotDeviceService deviceService; - @Resource - private IotDeviceMessageService deviceMessageService; @PostMapping("/create") @Operation(summary = "创建设备") @@ -125,11 +122,12 @@ public class IotDeviceController { @GetMapping("/simple-list") @Operation(summary = "获取设备的精简信息列表", description = "主要用于前端的下拉选项") @Parameter(name = "deviceType", description = "设备类型", example = "1") - public CommonResult> getSimpleDeviceList( + public CommonResult> getDeviceSimpleList( @RequestParam(value = "deviceType", required = false) Integer deviceType) { List list = deviceService.getDeviceListByDeviceType(deviceType); - return success(convertList(list, device -> // 只返回 id、name 字段 - new IotDeviceRespVO().setId(device.getId()).setDeviceName(device.getDeviceName()))); + return success(convertList(list, device -> // 只返回 id、name、productId 字段 + new IotDeviceRespVO().setId(device.getId()).setDeviceName(device.getDeviceName()) + .setProductId(device.getProductId()))); } @PostMapping("/import") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java index 17f7e2d3ec..adcc4d2e0a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java @@ -143,7 +143,7 @@ public class IotProductController { @GetMapping("/simple-list") @Operation(summary = "获取产品的精简信息列表", description = "主要用于前端的下拉选项") - public CommonResult> getSimpleProductList() { + public CommonResult> getProductSimpleList() { List list = productService.getProductList(); return success(convertList(list, product -> // 只返回 id、name 字段 new IotProductRespVO().setId(product.getId()).setName(product.getName()) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRulePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRulePageReqVO.java index 9cbb747db4..8e21c7992c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRulePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRulePageReqVO.java @@ -13,10 +13,10 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @Data public class IotDataRulePageReqVO extends PageParam { - @Schema(description = "场景名称", example = "芋艿") + @Schema(description = "数据流转规则名称", example = "芋艿") private String name; - @Schema(description = "场景状态", example = "1") + @Schema(description = "数据流转规则状态", example = "1") private Integer status; @Schema(description = "创建时间") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRuleRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRuleRespVO.java index 374b08a7cd..3427370f7c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRuleRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRuleRespVO.java @@ -11,16 +11,16 @@ import java.util.List; @Data public class IotDataRuleRespVO { - @Schema(description = "场景编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8540") + @Schema(description = "数据流转规则编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8540") private Long id; - @Schema(description = "场景名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @Schema(description = "数据流转规则名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") private String name; - @Schema(description = "场景描述", example = "你猜") + @Schema(description = "数据流转规则描述", example = "你猜") private String description; - @Schema(description = "场景状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @Schema(description = "数据流转规则状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer status; @Schema(description = "数据源配置数组", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRuleSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRuleSaveReqVO.java index 2928861169..47748c6eb1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRuleSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/rule/IotDataRuleSaveReqVO.java @@ -14,18 +14,18 @@ import java.util.List; @Data public class IotDataRuleSaveReqVO { - @Schema(description = "场景编号", example = "8540") + @Schema(description = "数据流转规则编号", example = "8540") private Long id; - @Schema(description = "场景名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") - @NotEmpty(message = "场景名称不能为空") + @Schema(description = "数据流转规则名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @NotEmpty(message = "数据流转规则名称不能为空") private String name; - @Schema(description = "场景描述", example = "你猜") + @Schema(description = "数据流转规则描述", example = "你猜") private String description; - @Schema(description = "场景状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @NotNull(message = "场景状态不能为空") + @Schema(description = "数据流转规则状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "数据流转规则状态不能为空") @InEnum(CommonStatusEnum.class) private Integer status; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index 4746107122..32477221ac 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -6,9 +6,9 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import jakarta.annotation.Nullable; import org.apache.ibatis.annotations.Mapper; -import javax.annotation.Nullable; import java.time.LocalDateTime; import java.util.Collection; import java.util.List; @@ -50,8 +50,9 @@ public interface IotDeviceMapper extends BaseMapperX { return selectCount(IotDeviceDO::getProductId, productId); } - default List selectListByDeviceType(Integer deviceType) { - return selectList(IotDeviceDO::getDeviceType, deviceType); + default List selectListByDeviceType(@Nullable Integer deviceType) { + return selectList(new LambdaQueryWrapperX() + .geIfPresent(IotDeviceDO::getDeviceType, deviceType)); } default List selectListByState(Integer state) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataRuleMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataRuleMapper.java index 6f8d7b860a..d59023290a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataRuleMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataRuleMapper.java @@ -3,10 +3,13 @@ package cn.iocoder.yudao.module.iot.dal.mysql.rule; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRulePageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleDO; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + /** * IoT 数据流转规则 Mapper * @@ -23,4 +26,9 @@ public interface IotDataRuleMapper extends BaseMapperX { .orderByDesc(IotDataRuleDO::getId)); } + default List selectListBySinkId(Long sinkId) { + return selectList(new LambdaQueryWrapperX() + .apply(MyBatisUtils.findInSet("sink_ids", sinkId))); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index e2258e3d66..c3a6868945 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -13,6 +13,7 @@ import java.time.LocalDateTime; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Set; /** * IoT 设备 Service 接口 @@ -255,4 +256,11 @@ public interface IotDeviceService { */ boolean authDevice(@Valid IotDeviceAuthReqDTO authReqDTO); + /** + * 校验设备是否存在 + * + * @param ids 设备编号数组 + */ + void validateDevicesExist(Set ids); + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index d7543cd2c4..604a8ae9b5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -483,6 +483,17 @@ public class IotDeviceServiceImpl implements IotDeviceService { return true; } + @Override + public void validateDevicesExist(Set ids) { + if (CollUtil.isEmpty(ids)) { + return; + } + List deviceIds = deviceMapper.selectByIds(ids); + if (deviceIds.size() != ids.size()) { + throw exception(DEVICE_NOT_EXISTS); + } + } + private IotDeviceServiceImpl getSelf() { return SpringUtil.getBean(getClass()); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java index 9d94219c50..70e6afd03a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java @@ -8,6 +8,7 @@ import jakarta.validation.Valid; import javax.annotation.Nullable; import java.time.LocalDateTime; +import java.util.Collection; import java.util.List; /** @@ -112,5 +113,11 @@ public interface IotProductService { */ Long getProductCount(@Nullable LocalDateTime createTime); + /** + * 批量校验产品存在 + * + * @param ids 产品编号集合 + */ + void validateProductsExist(Collection ids); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index 44e4819938..fb198c8a3b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.service.product; +import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; @@ -20,6 +21,7 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import java.time.LocalDateTime; +import java.util.Collection; import java.util.List; import java.util.Objects; @@ -157,4 +159,15 @@ public class IotProductServiceImpl implements IotProductService { return productMapper.selectCountByCreateTime(createTime); } + @Override + public void validateProductsExist(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return; + } + List products = productMapper.selectByIds(ids); + if (products.size() != ids.size()) { + throw exception(PRODUCT_NOT_EXISTS); + } + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleService.java index a51e384139..42fdf3099b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleService.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.iot.service.rule.data; +import java.util.List; + import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRulePageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRuleSaveReqVO; @@ -51,4 +53,12 @@ public interface IotDataRuleService { */ PageResult getDataRulePage(IotDataRulePageReqVO pageReqVO); + /** + * 根据数据目的编号,获得数据流转规则列表 + * + * @param sinkId 数据目的编号 + * @return 是否被使用 + */ + List getDataRuleBySinkId(Long sinkId); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java index df6d3e11f4..65c7a393ea 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java @@ -1,16 +1,26 @@ package cn.iocoder.yudao.module.iot.service.rule.data; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRulePageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRuleSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleDO; import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotDataRuleMapper; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; +import cn.iocoder.yudao.module.iot.service.product.IotProductService; +import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.*; + import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DATA_RULE_NOT_EXISTS; /** @@ -25,8 +35,20 @@ public class IotDataRuleServiceImpl implements IotDataRuleService { @Resource private IotDataRuleMapper dataRuleMapper; + @Resource + private IotProductService productService; + @Resource + private IotDeviceService deviceService; + @Resource + private IotThingModelService thingModelService; + @Resource + private IotDataSinkService dataSinkService; + @Override public Long createDataRule(IotDataRuleSaveReqVO createReqVO) { + // 校验数据源配置和数据目的 + validateDataRuleConfig(createReqVO); + // 新增 IotDataRuleDO dataRule = BeanUtils.toBean(createReqVO, IotDataRuleDO.class); dataRuleMapper.insert(dataRule); return dataRule.getId(); @@ -36,6 +58,9 @@ public class IotDataRuleServiceImpl implements IotDataRuleService { public void updateDataRule(IotDataRuleSaveReqVO updateReqVO) { // 校验存在 validateDataRuleExists(updateReqVO.getId()); + // 校验数据源配置和数据目的 + validateDataRuleConfig(updateReqVO); + // 更新 IotDataRuleDO updateObj = BeanUtils.toBean(updateReqVO, IotDataRuleDO.class); dataRuleMapper.updateById(updateObj); @@ -55,6 +80,55 @@ public class IotDataRuleServiceImpl implements IotDataRuleService { } } + /** + * 校验数据流转规则配置 + * + * @param reqVO 数据流转规则保存请求VO + */ + private void validateDataRuleConfig(IotDataRuleSaveReqVO reqVO) { + // 1. 校验数据源配置 + validateSourceConfigs(reqVO.getSourceConfigs()); + // 2. 校验数据目的 + dataSinkService.validateDataSinksExist(reqVO.getSinkIds()); + } + + /** + * 校验数据源配置 + * + * @param sourceConfigs 数据源配置列表 + */ + private void validateSourceConfigs(List sourceConfigs) { + // 1. 校验产品 + productService.validateProductsExist( + convertSet(sourceConfigs, IotDataRuleDO.SourceConfig::getProductId)); + + // 2. 校验设备 + deviceService.validateDevicesExist(convertSet(sourceConfigs, IotDataRuleDO.SourceConfig::getDeviceId, + config -> ObjUtil.notEqual(config.getDeviceId(), IotDeviceDO.DEVICE_ID_ALL))); + + // 3. 校验物模型存在 + validateThingModelsExist(sourceConfigs); + } + + /** + * 校验物模型存在 + * + * @param sourceConfigs 数据源配置列表 + */ + private void validateThingModelsExist(List sourceConfigs) { + Map> productIdToIdentifiers = new HashMap<>(); + for (IotDataRuleDO.SourceConfig config : sourceConfigs) { + if (StrUtil.isEmpty(config.getIdentifier())) { + continue; + } + productIdToIdentifiers.computeIfAbsent(config.getProductId(), + productId -> new HashSet<>()).add(config.getIdentifier()); + } + for (Map.Entry> entry : productIdToIdentifiers.entrySet()) { + thingModelService.validateThingModelsExist(entry.getKey(), entry.getValue()); + } + } + @Override public IotDataRuleDO getDataRule(Long id) { return dataRuleMapper.selectById(id); @@ -65,4 +139,9 @@ public class IotDataRuleServiceImpl implements IotDataRuleService { return dataRuleMapper.selectPage(pageReqVO); } + @Override + public List getDataRuleBySinkId(Long sinkId) { + return dataRuleMapper.selectListBySinkId(sinkId); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkService.java index 4c325f0a24..307163a8ec 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkService.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink.IotDataSin import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; import jakarta.validation.Valid; +import java.util.Collection; import java.util.List; /** @@ -61,4 +62,11 @@ public interface IotDataSinkService { */ List getDataSinkListByStatus(Integer status); + /** + * 批量校验数据目的存在 + * + * @param ids 数据目的编号集合 + */ + void validateDataSinksExist(Collection ids); + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkServiceImpl.java index fba06cac69..2b964c9952 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkServiceImpl.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.service.rule.data; +import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink.IotDataSinkPageReqVO; @@ -7,13 +8,16 @@ import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink.IotDataSin import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotDataSinkMapper; import jakarta.annotation.Resource; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.Collection; import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DATA_BRIDGE_NOT_EXISTS; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DATA_SINK_NOT_EXISTS; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DATA_SINK_DELETE_FAIL_USED_BY_RULE; /** * IoT 数据流转目的 Service 实现类 @@ -27,6 +31,10 @@ public class IotDataSinkServiceImpl implements IotDataSinkService { @Resource private IotDataSinkMapper dataSinkMapper; + @Resource + @Lazy // 延迟,避免循环依赖报错 + private IotDataRuleService dataRuleService; + @Override public Long createDataSink(IotDataSinkSaveReqVO createReqVO) { IotDataSinkDO dataBridge = BeanUtils.toBean(createReqVO, IotDataSinkDO.class); @@ -47,13 +55,17 @@ public class IotDataSinkServiceImpl implements IotDataSinkService { public void deleteDataSink(Long id) { // 校验存在 validateDataBridgeExists(id); + // 校验是否被数据流转规则使用 + if (CollUtil.isNotEmpty(dataRuleService.getDataRuleBySinkId(id))) { + throw exception(DATA_SINK_DELETE_FAIL_USED_BY_RULE); + } // 删除 dataSinkMapper.deleteById(id); } private void validateDataBridgeExists(Long id) { if (dataSinkMapper.selectById(id) == null) { - throw exception(DATA_BRIDGE_NOT_EXISTS); + throw exception(DATA_SINK_NOT_EXISTS); } } @@ -72,4 +84,15 @@ public class IotDataSinkServiceImpl implements IotDataSinkService { return dataSinkMapper.selectListByStatus(status); } + @Override + public void validateDataSinksExist(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return; + } + List sinks = dataSinkMapper.selectByIds(ids); + if (sinks.size() != ids.size()) { + throw exception(DATA_SINK_NOT_EXISTS); + } + } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java index feae3b8adc..b4af6f663d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java @@ -9,6 +9,7 @@ import jakarta.validation.Valid; import java.util.Collection; import java.util.List; +import java.util.Set; /** * IoT 产品物模型 Service 接口 @@ -99,4 +100,12 @@ public interface IotThingModelService { */ List getThingModelList(IotThingModelListReqVO reqVO); + /** + * 批量校验物模型存在 + * + * @param productId 产品编号 + * @param identifiers 标识符集合 + */ + void validateThingModelsExist(Long productId, Set identifiers); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java index b56063e265..1de8dd5cc8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java @@ -158,6 +158,21 @@ public class IotThingModelServiceImpl implements IotThingModelService { return thingModelMapper.selectList(reqVO); } + @Override + public void validateThingModelsExist(Long productId, Set identifiers) { + if (CollUtil.isEmpty(identifiers)) { + return; + } + List thingModels = thingModelMapper.selectListByProductIdAndIdentifiers( + productId, identifiers); + Set foundIdentifiers = convertSet(thingModels, IotThingModelDO::getIdentifier); + for (String identifier : identifiers) { + if (!foundIdentifiers.contains(identifier)) { + throw exception(THING_MODEL_NOT_EXISTS); + } + } + } + /** * 校验功能是否存在 * From ea1f0cb462520cc0a3bd1633e02672a6c0ebac97 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 26 Jun 2025 09:58:34 +0800 Subject: [PATCH 06/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E5=AE=9E=E7=8E=B0=E2=80=9C=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=B5=81=E8=BD=AC=E2=80=9D=E5=8A=9F=E8=83=BD=E7=9A=84?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=EF=BC=8880%=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IotDeviceMessageIdentifierEnum.java | 1 + .../rule/IotRuleSceneActionTypeEnum.java | 4 +- .../iot/dal/mysql/rule/IotDataRuleMapper.java | 4 + .../iot/dal/redis/RedisKeyConstants.java | 16 +++ .../rule/IotDataRuleMessageHandler.java | 50 ++++++++ .../service/rule/data/IotDataRuleService.java | 14 +- .../rule/data/IotDataRuleServiceImpl.java | 120 +++++++++++++++++- .../service/rule/data/IotDataSinkService.java | 8 ++ .../rule/data/IotDataSinkServiceImpl.java | 12 +- .../data/IotRuleSceneDataBridgeAction.java | 61 --------- .../data/action/IotDataBridgeExecute.java | 45 ------- .../rule/data/action/IotDataRuleAction.java | 28 ++++ ...e.java => IotDataRuleCacheableAction.java} | 29 +++-- ...xecute.java => IotHttpDataSinkAction.java} | 13 +- ...ecute.java => IotKafkaDataRuleAction.java} | 10 +- ...te.java => IotRabbitMQDataRuleAction.java} | 18 +-- ...ute.java => IotRedisStreamRuleAction.java} | 8 +- ...te.java => IotRocketMQDataRuleAction.java} | 8 +- .../rule/scene/IotRuleSceneServiceImpl.java | 5 - .../databridge/IotDataBridgeExecuteTest.java | 14 +- 20 files changed, 296 insertions(+), 172 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotDataRuleMessageHandler.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotRuleSceneDataBridgeAction.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotDataBridgeExecute.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotDataRuleAction.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/{AbstractCacheableDataBridgeExecute.java => IotDataRuleCacheableAction.java} (83%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/{IotHttpDataBridgeExecute.java => IotHttpDataSinkAction.java} (88%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/{IotKafkaMQDataBridgeExecute.java => IotKafkaDataRuleAction.java} (87%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/{IotRabbitMQDataBridgeExecute.java => IotRabbitMQDataRuleAction.java} (84%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/{IotRedisStreamDataBridgeExecute.java => IotRedisStreamRuleAction.java} (90%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/{IotRocketMQDataBridgeExecute.java => IotRocketMQDataRuleAction.java} (88%) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java index a06b43ce96..e9dbe2f658 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java @@ -7,6 +7,7 @@ import lombok.RequiredArgsConstructor; /** * IoT 设备消息标识符枚举 */ +@Deprecated @Getter @RequiredArgsConstructor public enum IotDeviceMessageIdentifierEnum { diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java index 6e6843b093..5251852312 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java @@ -40,9 +40,7 @@ public enum IotRuleSceneActionTypeEnum implements ArrayValuable { @Deprecated ALERT(2), // 告警执行 - - @Deprecated - DATA_BRIDGE(3); // 桥接执行 + ; private final Integer type; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataRuleMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataRuleMapper.java index d59023290a..7c0c17d3bc 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataRuleMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataRuleMapper.java @@ -31,4 +31,8 @@ public interface IotDataRuleMapper extends BaseMapperX { .apply(MyBatisUtils.findInSet("sink_ids", sinkId))); } + default List selectListByStatus(Integer status) { + return selectList(IotDataRuleDO::getStatus, status); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java index 5c4b7429f0..1187677e54 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java @@ -60,4 +60,20 @@ public interface RedisKeyConstants { */ String THING_MODEL_LIST = "iot:thing_model_list"; + /** + * 数据流转规则的数据缓存,使用 Spring Cache 操作 + * + * KEY 格式:data_rule_list_${deviceId}_${method}_${identifier} + * VALUE 数据类型:String 数组(JSON),即 {@link cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleDO} 列表 + */ + String DATA_RULE_LIST = "iot:data_rule_list"; + + /** + * 数据目的的数据缓存,使用 Spring Cache 操作 + * + * KEY 格式:data_sink_${id} + * VALUE 数据类型:String(JSON),即 {@link cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO} + */ + String DATA_SINK = "iot:data_sink"; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotDataRuleMessageHandler.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotDataRuleMessageHandler.java new file mode 100644 index 0000000000..c2b82262c7 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotDataRuleMessageHandler.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.iot.mq.consumer.rule; + +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber; +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.service.rule.data.IotDataRuleService; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +// TODO @puhui999:后面重构哈 + +/** + * 针对 {@link IotDeviceMessage} 的消费者,处理数据流转 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class IotDataRuleMessageHandler implements IotMessageSubscriber { + + @Resource + private IotDataRuleService dataRuleService; + + @Resource + private IotMessageBus messageBus; + + @PostConstruct + public void init() { + messageBus.register(this); + } + + @Override + public String getTopic() { + return IotDeviceMessage.MESSAGE_BUS_DEVICE_MESSAGE_TOPIC; + } + + @Override + public String getGroup() { + return "iot_data_rule_consumer"; + } + + @Override + public void onMessage(IotDeviceMessage message) { + TenantUtils.execute(message.getTenantId(), () -> dataRuleService.executeDataRule(message)); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleService.java index 42fdf3099b..1e0a813305 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleService.java @@ -1,13 +1,14 @@ package cn.iocoder.yudao.module.iot.service.rule.data; -import java.util.List; - import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRulePageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRuleSaveReqVO; +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleDO; import jakarta.validation.Valid; +import java.util.List; + /** * IoT 数据流转规则 Service 接口 * @@ -59,6 +60,13 @@ public interface IotDataRuleService { * @param sinkId 数据目的编号 * @return 是否被使用 */ - List getDataRuleBySinkId(Long sinkId); + List getDataRuleListBySinkId(Long sinkId); + + /** + * 执行数据流转规则 + * + * @param message 消息 + */ + void executeDataRule(IotDeviceMessage message); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java index 65c7a393ea..d7370c0a64 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java @@ -3,17 +3,28 @@ package cn.iocoder.yudao.module.iot.service.rule.data; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.framework.common.util.spring.SpringUtils; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRulePageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.rule.IotDataRuleSaveReqVO; +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataRuleDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotDataRuleMapper; +import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import cn.iocoder.yudao.module.iot.service.product.IotProductService; +import cn.iocoder.yudao.module.iot.service.rule.data.action.IotDataRuleAction; import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -30,6 +41,7 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DATA_RULE_NOT */ @Service @Validated +@Slf4j public class IotDataRuleServiceImpl implements IotDataRuleService { @Resource @@ -44,7 +56,11 @@ public class IotDataRuleServiceImpl implements IotDataRuleService { @Resource private IotDataSinkService dataSinkService; + @Resource + private List dataRuleActions; + @Override + @CacheEvict(value = RedisKeyConstants.DATA_RULE_LIST, allEntries = true) public Long createDataRule(IotDataRuleSaveReqVO createReqVO) { // 校验数据源配置和数据目的 validateDataRuleConfig(createReqVO); @@ -55,6 +71,7 @@ public class IotDataRuleServiceImpl implements IotDataRuleService { } @Override + @CacheEvict(value = RedisKeyConstants.DATA_RULE_LIST, allEntries = true) public void updateDataRule(IotDataRuleSaveReqVO updateReqVO) { // 校验存在 validateDataRuleExists(updateReqVO.getId()); @@ -67,6 +84,7 @@ public class IotDataRuleServiceImpl implements IotDataRuleService { } @Override + @CacheEvict(value = RedisKeyConstants.DATA_RULE_LIST, allEntries = true) public void deleteDataRule(Long id) { // 校验存在 validateDataRuleExists(id); @@ -116,15 +134,15 @@ public class IotDataRuleServiceImpl implements IotDataRuleService { * @param sourceConfigs 数据源配置列表 */ private void validateThingModelsExist(List sourceConfigs) { - Map> productIdToIdentifiers = new HashMap<>(); + Map> productIdIdentifiers = new HashMap<>(); for (IotDataRuleDO.SourceConfig config : sourceConfigs) { if (StrUtil.isEmpty(config.getIdentifier())) { continue; } - productIdToIdentifiers.computeIfAbsent(config.getProductId(), + productIdIdentifiers.computeIfAbsent(config.getProductId(), productId -> new HashSet<>()).add(config.getIdentifier()); } - for (Map.Entry> entry : productIdToIdentifiers.entrySet()) { + for (Map.Entry> entry : productIdIdentifiers.entrySet()) { thingModelService.validateThingModelsExist(entry.getKey(), entry.getValue()); } } @@ -140,8 +158,102 @@ public class IotDataRuleServiceImpl implements IotDataRuleService { } @Override - public List getDataRuleBySinkId(Long sinkId) { + public List getDataRuleListBySinkId(Long sinkId) { return dataRuleMapper.selectListBySinkId(sinkId); } + @Cacheable(value = RedisKeyConstants.DATA_RULE_LIST, + key = "#deviceId + '_' + #method + '_' + (#identifier ?: '')") + public List getDataRuleListByConditionFromCache(Long deviceId, String method, String identifier) { + // 1. 查询所有开启的数据流转规则 + List rules = dataRuleMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()); + // 2. 内存里过滤匹配的规则 + List matchedRules = new ArrayList<>(); + for (IotDataRuleDO rule : rules) { + IotDataRuleDO.SourceConfig found = CollUtil.findOne(rule.getSourceConfigs(), + config -> ObjectUtils.equalsAny(config.getDeviceId(), deviceId, IotDeviceDO.DEVICE_ID_ALL) + && (StrUtil.isNotEmpty(config.getMethod()) || ObjUtil.equal(config.getMethod(), method)) + && (StrUtil.isEmpty(config.getIdentifier()) || ObjUtil.equal(config.getIdentifier(), identifier))); + if (found != null) { + matchedRules.add(new IotDataRuleDO().setId(rule.getId()).setSinkIds(rule.getSinkIds())); + } + } + return matchedRules; + } + + @Override + public void executeDataRule(IotDeviceMessage message) { + try { + // 1. 获取匹配的数据流转规则 + Long deviceId = message.getDeviceId(); + String method = message.getMethod(); + String identifier = IotDeviceMessageUtils.getIdentifier(message); + List rules = getSelf().getDataRuleListByConditionFromCache(deviceId, method, identifier); + if (CollUtil.isEmpty(rules)) { + log.debug("[executeDataRule][设备({}) 方法({}) 标识符({}) 没有匹配的数据流转规则]", + deviceId, method, identifier); + return; + } + log.info("[executeDataRule][设备({}) 方法({}) 标识符({}) 匹配到 {} 条数据流转规则]", + deviceId, method, identifier, rules.size()); + + // 2. 遍历规则,执行数据流转 + rules.forEach(rule -> executeDataRule(message, rule)); + } catch (Exception e) { + log.error("[executeDataRule][消息({}) 执行数据流转规则异常]", message, e); + } + } + + /** + * 为指定规则的所有数据目的执行数据流转 + * + * @param message 设备消息 + * @param rule 数据流转规则 + */ + private void executeDataRule(IotDeviceMessage message, IotDataRuleDO rule) { + rule.getSinkIds().forEach(sinkId -> { + try { + // 获取数据目的配置 + IotDataSinkDO dataSink = dataSinkService.getDataSinkFromCache(sinkId); + if (dataSink == null) { + log.error("[executeDataRule][规则({}) 对应的数据目的({}) 不存在]", rule.getId(), sinkId); + return; + } + if (CommonStatusEnum.isDisable(dataSink.getStatus())) { + log.info("[executeDataRule][规则({}) 对应的数据目的({}) 状态为禁用]", rule.getId(), sinkId); + return; + } + + // 执行数据桥接操作 + executeDataRuleAction(message, dataSink); + } catch (Exception e) { + log.error("[executeDataRule][规则({}) 数据目的({}) 执行异常]", rule.getId(), sinkId, e); + } + }); + } + + /** + * 执行数据流转操作 + * + * @param message 设备消息 + * @param dataSink 数据目的 + */ + private void executeDataRuleAction(IotDeviceMessage message, IotDataSinkDO dataSink) { + dataRuleActions.forEach(action -> { + if (ObjUtil.notEqual(action.getType(), dataSink.getType())) { + return; + } + try { + action.execute(message, dataSink); + log.info("[executeDataRuleAction][消息({}) 数据目的({}) 执行成功]", message.getId(), dataSink.getId()); + } catch (Exception e) { + log.error("[executeDataRuleAction][消息({}) 数据目的({}) 执行异常]", message.getId(), dataSink.getId(), e); + } + }); + } + + private IotDataRuleServiceImpl getSelf() { + return SpringUtils.getBean(IotDataRuleServiceImpl.class); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkService.java index 307163a8ec..d0e2a5282e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkService.java @@ -46,6 +46,14 @@ public interface IotDataSinkService { */ IotDataSinkDO getDataSink(Long id); + /** + * 从缓存中获得数据流转目的 + * + * @param id 编号 + * @return 数据流转目的 + */ + IotDataSinkDO getDataSinkFromCache(Long id); + /** * 获得数据流转目的分页 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkServiceImpl.java index 2b964c9952..9977afba22 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataSinkServiceImpl.java @@ -7,7 +7,9 @@ import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink.IotDataSin import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.data.sink.IotDataSinkSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotDataSinkMapper; +import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants; import jakarta.annotation.Resource; +import org.springframework.cache.annotation.Cacheable; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -16,8 +18,8 @@ import java.util.Collection; import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DATA_SINK_NOT_EXISTS; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DATA_SINK_DELETE_FAIL_USED_BY_RULE; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DATA_SINK_NOT_EXISTS; /** * IoT 数据流转目的 Service 实现类 @@ -56,7 +58,7 @@ public class IotDataSinkServiceImpl implements IotDataSinkService { // 校验存在 validateDataBridgeExists(id); // 校验是否被数据流转规则使用 - if (CollUtil.isNotEmpty(dataRuleService.getDataRuleBySinkId(id))) { + if (CollUtil.isNotEmpty(dataRuleService.getDataRuleListBySinkId(id))) { throw exception(DATA_SINK_DELETE_FAIL_USED_BY_RULE); } // 删除 @@ -74,6 +76,12 @@ public class IotDataSinkServiceImpl implements IotDataSinkService { return dataSinkMapper.selectById(id); } + @Override + @Cacheable(value = RedisKeyConstants.DATA_SINK, key = "#id") + public IotDataSinkDO getDataSinkFromCache(Long id) { + return dataSinkMapper.selectById(id); + } + @Override public PageResult getDataSinkPage(IotDataSinkPageReqVO pageReqVO) { return dataSinkMapper.selectPage(pageReqVO); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotRuleSceneDataBridgeAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotRuleSceneDataBridgeAction.java deleted file mode 100644 index 08b76be5df..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotRuleSceneDataBridgeAction.java +++ /dev/null @@ -1,61 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.rule.data; - -import cn.hutool.core.lang.Assert; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; -import cn.iocoder.yudao.module.iot.service.rule.data.action.IotDataBridgeExecute; -import cn.iocoder.yudao.module.iot.service.rule.scene.action.IotRuleSceneAction; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import java.util.List; - -/** - * IoT 数据流转目的的 {@link IotRuleSceneAction} 实现类 - * - * @author 芋道源码 - */ -@Deprecated -@Component -@Slf4j -public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { - - @Resource - private IotDataSinkService dataBridgeService; - @Resource - private List> dataBridgeExecutes; - - @Override - public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) throws Exception { - // 1.1 如果消息为空,直接返回 - if (message == null) { - return; - } - // 1.2 获得数据流转目的 - Assert.notNull(config.getDataBridgeId(), "数据流转目的编号不能为空"); - IotDataSinkDO dataBridge = dataBridgeService.getDataSink(config.getDataBridgeId()); - if (dataBridge == null || dataBridge.getConfig() == null) { - log.error("[execute][message({}) config({}) 对应的数据流转目的不存在]", message, config); - return; - } - if (CommonStatusEnum.isDisable(dataBridge.getStatus())) { - log.info("[execute][message({}) config({}) 对应的数据流转目的({}) 状态为禁用]", message, config, dataBridge); - return; - } - - // 2. 执行数据桥接操作 - for (IotDataBridgeExecute execute : dataBridgeExecutes) { - execute.execute(message, dataBridge); - } - } - - @Override - public IotRuleSceneActionTypeEnum getType() { - return IotRuleSceneActionTypeEnum.DATA_BRIDGE; - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotDataBridgeExecute.java deleted file mode 100644 index 48e7f47cc3..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotDataBridgeExecute.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.rule.data.action; - -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; - -/** - * IoT 数据流转目的的执行器 execute 接口 - * - * @author HUIHUI - */ -public interface IotDataBridgeExecute { - - /** - * 获取数据流转目的类型 - * - * @return 数据流转目的类型 - */ - Integer getType(); - - /** - * 执行数据流转目的操作 - * - * @param message 设备消息 - * @param dataBridge 数据流转目的 - */ - @SuppressWarnings({"unchecked"}) - default void execute(IotDeviceMessage message, IotDataSinkDO dataBridge) throws Exception { - // 1.1 校验数据流转目的类型 - if (!getType().equals(dataBridge.getType())) { - return; - } - - // 1.2 执行对应的数据流转目的发送消息 - execute0(message, (Config) dataBridge.getConfig()); - } - - /** - * 【真正】执行数据流转目的操作 - * - * @param message 设备消息 - * @param config 桥梁配置 - */ - void execute0(IotDeviceMessage message, Config config) throws Exception; - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotDataRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotDataRuleAction.java new file mode 100644 index 0000000000..8e6458ba86 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotDataRuleAction.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.iot.service.rule.data.action; + +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; + +/** + * IoT 数据流转目的的执行器 action 接口 + * + * @author HUIHUI + */ +public interface IotDataRuleAction { + + /** + * 获取数据流转目的类型 + * + * @return 数据流转目的类型 + */ + Integer getType(); + + /** + * 执行数据流转目的操作 + * + * @param message 设备消息 + * @param dataSink 数据流转目的 + */ + void execute(IotDeviceMessage message, IotDataSinkDO dataSink); + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/AbstractCacheableDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotDataRuleCacheableAction.java similarity index 83% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/AbstractCacheableDataBridgeExecute.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotDataRuleCacheableAction.java index 584285e53c..4319469082 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/AbstractCacheableDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotDataRuleCacheableAction.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.service.rule.data.action; +import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; @@ -17,14 +18,14 @@ import java.time.Duration; // TODO @芋艿:websocket /** - * 带缓存功能的数据流转目的执行器抽象类 + * 可缓存的 {@link IotDataRuleAction} 抽象实现 * * 该类提供了一个通用的缓存机制,用于管理各类数据桥接的生产者(Producer)实例。 * * 主要特点: * - 基于Guava Cache实现高效的生产者实例缓存管理 * - 自动处理生产者的生命周期(创建、获取、关闭) - * - 支持30分钟未访问自动过期清理机制 + * - 支持 30 分钟未访问自动过期清理机制 * - 异常处理与日志记录,便于问题排查 * * 子类需要实现: @@ -36,7 +37,7 @@ import java.time.Duration; * @author HUIHUI */ @Slf4j -public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridgeExecute { +public abstract class IotDataRuleCacheableAction implements IotDataRuleAction { /** * Producer 缓存 @@ -45,10 +46,6 @@ public abstract class AbstractCacheableDataBridgeExecute imple .expireAfterAccess(Duration.ofMinutes(30)) // 30 分钟未访问就提前过期 .removalListener((RemovalListener) notification -> { Producer producer = notification.getValue(); - if (producer == null) { - return; - } - try { closeProducer(producer); log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已关闭]", notification.getKey()); @@ -100,15 +97,21 @@ public abstract class AbstractCacheableDataBridgeExecute imple @Override @SuppressWarnings({"unchecked"}) - public void execute(IotDeviceMessage message, IotDataSinkDO dataBridge) { - if (ObjUtil.notEqual(dataBridge.getType(), getType())) { - return; - } + public void execute(IotDeviceMessage message, IotDataSinkDO dataSink) { + Assert.isTrue(ObjUtil.equal(dataSink.getType(), getType()), "类型({})不匹配", dataSink.getType()); try { - execute0(message, (Config) dataBridge.getConfig()); + execute(message, (Config) dataSink.getConfig()); } catch (Exception e) { - log.error("[execute][桥梁配置 config({}) 对应的 message({}) 发送异常]", dataBridge.getConfig(), message, e); + log.error("[execute][桥梁配置 config({}) 对应的 message({}) 发送异常]", dataSink.getConfig(), message, e); } } + /** + * 执行数据流转 + * + * @param message 设备消息 + * @param config 配置信息 + */ + protected abstract void execute(IotDeviceMessage message, Config config) throws Exception; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataSinkAction.java similarity index 88% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataBridgeExecute.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataSinkAction.java index da02677aae..c23e346dbf 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataSinkAction.java @@ -1,10 +1,12 @@ package cn.iocoder.yudao.module.iot.service.rule.data.action; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; import cn.iocoder.yudao.framework.common.util.http.HttpUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataSinkHttpConfig; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataSinkHttpConfig; import cn.iocoder.yudao.module.iot.enums.rule.IotDataSinkTypeEnum; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -17,13 +19,13 @@ import java.util.HashMap; import java.util.Map; /** - * Http 的 {@link IotDataBridgeExecute} 实现类 + * HTTP 的 {@link IotDataRuleAction} 实现类 * * @author HUIHUI */ @Component @Slf4j -public class IotHttpDataBridgeExecute implements IotDataBridgeExecute { +public class IotHttpDataSinkAction implements IotDataRuleAction { @Resource private RestTemplate restTemplate; @@ -34,8 +36,9 @@ public class IotHttpDataBridgeExecute implements IotDataBridgeExecute requestEntity = null; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotKafkaMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotKafkaDataRuleAction.java similarity index 87% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotKafkaMQDataBridgeExecute.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotKafkaDataRuleAction.java index ec7eade63f..5bbbe07b4b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotKafkaMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotKafkaDataRuleAction.java @@ -17,17 +17,17 @@ import java.util.Map; import java.util.concurrent.TimeUnit; /** - * Kafka 的 {@link IotDataBridgeExecute} 实现类 + * Kafka 的 {@link IotDataRuleAction} 实现类 * * @author HUIHUI */ @ConditionalOnClass(name = "org.springframework.kafka.core.KafkaTemplate") @Component @Slf4j -public class IotKafkaMQDataBridgeExecute extends - AbstractCacheableDataBridgeExecute> { +public class IotKafkaDataRuleAction extends + IotDataRuleCacheableAction> { - private static final Duration SEND_TIMEOUT = Duration.ofMillis(10000); // 10 秒超时时间 + private static final Duration SEND_TIMEOUT = Duration.ofSeconds(10); @Override public Integer getType() { @@ -35,7 +35,7 @@ public class IotKafkaMQDataBridgeExecute extends } @Override - public void execute0(IotDeviceMessage message, IotDataSinkKafkaConfig config) throws Exception { + public void execute(IotDeviceMessage message, IotDataSinkKafkaConfig config) throws Exception { // 1. 获取或创建 KafkaTemplate KafkaTemplate kafkaTemplate = getProducer(config); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRabbitMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRabbitMQDataRuleAction.java similarity index 84% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRabbitMQDataBridgeExecute.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRabbitMQDataRuleAction.java index d8abaa7602..89d3500c6a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRabbitMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRabbitMQDataRuleAction.java @@ -13,16 +13,15 @@ import org.springframework.stereotype.Component; import java.nio.charset.StandardCharsets; /** - * RabbitMQ 的 {@link IotDataBridgeExecute} 实现类 + * RabbitMQ 的 {@link IotDataRuleAction} 实现类 * * @author HUIHUI */ @ConditionalOnClass(name = "com.rabbitmq.client.Channel") @Component @Slf4j -public class IotRabbitMQDataBridgeExecute extends - AbstractCacheableDataBridgeExecute { - +public class IotRabbitMQDataRuleAction extends + IotDataRuleCacheableAction { @Override public Integer getType() { @@ -30,16 +29,15 @@ public class IotRabbitMQDataBridgeExecute extends } @Override - public void execute0(IotDeviceMessage message, IotDataSinkRabbitMQConfig config) throws Exception { - // 1. 获取或创建 Channel + public void execute(IotDeviceMessage message, IotDataSinkRabbitMQConfig config) throws Exception { + // 1.1 获取或创建 Channel Channel channel = getProducer(config); - - // 2.1 声明交换机、队列和绑定关系 + // 1.2 声明交换机、队列和绑定关系 channel.exchangeDeclare(config.getExchange(), "direct", true); channel.queueDeclare(config.getQueue(), true, false, false, null); channel.queueBind(config.getQueue(), config.getExchange(), config.getRoutingKey()); - // 2.2 发送消息 + // 2. 发送消息 channel.basicPublish(config.getExchange(), config.getRoutingKey(), null, message.toString().getBytes(StandardCharsets.UTF_8)); log.info("[executeRabbitMQ][message({}) config({}) 发送成功]", message, config); @@ -55,10 +53,8 @@ public class IotRabbitMQDataBridgeExecute extends factory.setVirtualHost(config.getVirtualHost()); factory.setUsername(config.getUsername()); factory.setPassword(config.getPassword()); - // 2. 创建连接 Connection connection = factory.newConnection(); - // 3. 创建信道 return connection.createChannel(); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRedisStreamDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRedisStreamRuleAction.java similarity index 90% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRedisStreamDataBridgeExecute.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRedisStreamRuleAction.java index be3370461a..9870c7d464 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRedisStreamDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRedisStreamRuleAction.java @@ -18,14 +18,14 @@ import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.stereotype.Component; /** - * Redis Stream 的 {@link IotDataBridgeExecute} 实现类 + * Redis Stream 的 {@link IotDataRuleAction} 实现类 * * @author HUIHUI */ @Component @Slf4j -public class IotRedisStreamDataBridgeExecute extends - AbstractCacheableDataBridgeExecute> { +public class IotRedisStreamRuleAction extends + IotDataRuleCacheableAction> { @Override public Integer getType() { @@ -33,7 +33,7 @@ public class IotRedisStreamDataBridgeExecute extends } @Override - public void execute0(IotDeviceMessage message, IotDataSinkRedisStreamConfig config) throws Exception { + public void execute(IotDeviceMessage message, IotDataSinkRedisStreamConfig config) throws Exception { // 1. 获取 RedisTemplate RedisTemplate redisTemplate = getProducer(config); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRocketMQDataBridgeExecute.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRocketMQDataRuleAction.java similarity index 88% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRocketMQDataBridgeExecute.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRocketMQDataRuleAction.java index 6a8d66842b..1a212ec5ea 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRocketMQDataBridgeExecute.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRocketMQDataRuleAction.java @@ -13,15 +13,15 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.stereotype.Component; /** - * RocketMQ 的 {@link IotDataBridgeExecute} 实现类 + * RocketMQ 的 {@link IotDataRuleAction} 实现类 * * @author HUIHUI */ @ConditionalOnClass(name = "org.apache.rocketmq.client.producer.DefaultMQProducer") @Component @Slf4j -public class IotRocketMQDataBridgeExecute extends - AbstractCacheableDataBridgeExecute { +public class IotRocketMQDataRuleAction extends + IotDataRuleCacheableAction { @Override public Integer getType() { @@ -29,7 +29,7 @@ public class IotRocketMQDataBridgeExecute extends } @Override - public void execute0(IotDeviceMessage message, IotDataSinkRocketMQConfig config) throws Exception { + public void execute(IotDeviceMessage message, IotDataSinkRocketMQConfig config) throws Exception { // 1. 获取或创建 Producer DefaultMQProducer producer = getProducer(config); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java index b422e0d509..fc77180fde 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java @@ -214,11 +214,6 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { .build()); action01.setDeviceControl(actionDeviceControl01); // ruleScene01.getActions().add(action01); // TODO 芋艿:先不测试了 - // 数据桥接(http) - IotRuleSceneDO.ActionConfig action02 = new IotRuleSceneDO.ActionConfig(); - action02.setType(IotRuleSceneActionTypeEnum.DATA_BRIDGE.getType()); - action02.setDataBridgeId(1L); - ruleScene01.getActions().add(action02); return ListUtil.toList(ruleScene01); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java index 52599c455f..d8cf9ee66e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java @@ -23,7 +23,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; /** - * {@link IotDataBridgeExecute} 实现类的单元测试 + * {@link IotDataRuleAction} 实现类的单元测试 * * @author HUIHUI */ @@ -37,7 +37,7 @@ public class IotDataBridgeExecuteTest extends BaseMockitoUnitTest { private RestTemplate restTemplate; @InjectMocks - private IotHttpDataBridgeExecute httpDataBridgeExecute; + private IotHttpDataSinkAction httpDataBridgeExecute; @BeforeEach public void setUp() { @@ -51,7 +51,7 @@ public class IotDataBridgeExecuteTest extends BaseMockitoUnitTest { @Test public void testKafkaMQDataBridge() throws Exception { // 1. 创建执行器实例 - IotKafkaMQDataBridgeExecute action = new IotKafkaMQDataBridgeExecute(); + IotKafkaDataRuleAction action = new IotKafkaDataRuleAction(); // 2. 创建配置 IotDataSinkKafkaConfig config = new IotDataSinkKafkaConfig() @@ -68,7 +68,7 @@ public class IotDataBridgeExecuteTest extends BaseMockitoUnitTest { @Test public void testRabbitMQDataBridge() throws Exception { // 1. 创建执行器实例 - IotRabbitMQDataBridgeExecute action = new IotRabbitMQDataBridgeExecute(); + IotRabbitMQDataRuleAction action = new IotRabbitMQDataRuleAction(); // 2. 创建配置 IotDataSinkRabbitMQConfig config = new IotDataSinkRabbitMQConfig() @@ -88,7 +88,7 @@ public class IotDataBridgeExecuteTest extends BaseMockitoUnitTest { @Test public void testRedisStreamDataBridge() throws Exception { // 1. 创建执行器实例 - IotRedisStreamDataBridgeExecute action = new IotRedisStreamDataBridgeExecute(); + IotRedisStreamRuleAction action = new IotRedisStreamRuleAction(); // 2. 创建配置 IotDataSinkRedisStreamConfig config = new IotDataSinkRedisStreamConfig() @@ -105,7 +105,7 @@ public class IotDataBridgeExecuteTest extends BaseMockitoUnitTest { @Test public void testRocketMQDataBridge() throws Exception { // 1. 创建执行器实例 - IotRocketMQDataBridgeExecute action = new IotRocketMQDataBridgeExecute(); + IotRocketMQDataRuleAction action = new IotRocketMQDataRuleAction(); // 2. 创建配置 IotDataSinkRocketMQConfig config = new IotDataSinkRocketMQConfig() @@ -142,7 +142,7 @@ public class IotDataBridgeExecuteTest extends BaseMockitoUnitTest { * @param type MQ 类型 * @throws Exception 如果执行过程中发生异常 */ - private void executeAndVerifyCache(IotDataBridgeExecute action, IotAbstractDataSinkConfig config, String type) + private void executeAndVerifyCache(IotDataRuleAction action, IotAbstractDataSinkConfig config, String type) throws Exception { log.info("[test{}DataBridge][第一次执行,应该会创建新的 producer]", type); action.execute(message, new IotDataSinkDO().setType(action.getType()).setConfig(config)); From 456423b5aaba305d25ede93d2fd74d9c153d2209 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Thu, 26 Jun 2025 17:44:20 +0800 Subject: [PATCH 07/33] =?UTF-8?q?fix:=E3=80=90IoT=20=E7=89=A9=E8=81=94?= =?UTF-8?q?=E7=BD=91=E3=80=91=E4=BF=AE=E5=A4=8D=E5=90=AF=E5=8A=A8=E6=8A=A5?= =?UTF-8?q?=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/dal/dataobject/ota/IotOtaFirmwareDO.java | 9 ++++++--- .../dal/dataobject/ota/IotOtaUpgradeTaskDO.java | 8 ++++++-- .../databridge/IotDataBridgeExecuteTest.java | 14 ++++++-------- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java index fa56f6938e..fd635c66f6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java @@ -2,9 +2,12 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.ota; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.KeySequence; -import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; /** * IoT OTA 固件 DO @@ -24,7 +27,7 @@ public class IotOtaFirmwareDO extends BaseDO { /** * 固件编号 */ - @TableField + @TableId private Long id; /** * 固件名称 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java index 221bdc56cd..6f59f3f931 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java @@ -4,9 +4,13 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; -import lombok.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; import java.util.List; @@ -26,7 +30,7 @@ public class IotOtaUpgradeTaskDO extends BaseDO { /** * 任务编号 */ - @TableField + @TableId private Long id; /** * 任务名称 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java index d8cf9ee66e..a1f7700394 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java @@ -2,8 +2,8 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.*; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataSinkDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.*; import cn.iocoder.yudao.module.iot.service.rule.data.action.*; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; @@ -16,8 +16,6 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; -import java.time.LocalDateTime; - import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; @@ -42,10 +40,10 @@ public class IotDataBridgeExecuteTest extends BaseMockitoUnitTest { @BeforeEach public void setUp() { // 创建共享的测试消息 - message = IotDeviceMessage.builder().messageId("TEST-001").reportTime(LocalDateTime.now()) - .productKey("testProduct").deviceName("testDevice") - .type("property").identifier("temperature").data("{\"value\": 60}") - .build(); + //message = IotDeviceMessage.builder().messageId("TEST-001").reportTime(LocalDateTime.now()) + // .productKey("testProduct").deviceName("testDevice") + // .type("property").identifier("temperature").data("{\"value\": 60}") + // .build(); } @Test @@ -142,7 +140,7 @@ public class IotDataBridgeExecuteTest extends BaseMockitoUnitTest { * @param type MQ 类型 * @throws Exception 如果执行过程中发生异常 */ - private void executeAndVerifyCache(IotDataRuleAction action, IotAbstractDataSinkConfig config, String type) + private void executeAndVerifyCache(IotDataRuleAction action, IotAbstractDataSinkConfig config, String type) throws Exception { log.info("[test{}DataBridge][第一次执行,应该会创建新的 producer]", type); action.execute(message, new IotDataSinkDO().setType(action.getType()).setConfig(config)); From 0faee76ffd9013235427c5e998ba25d0a508a36f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 26 Jun 2025 23:39:29 +0800 Subject: [PATCH 08/33] =?UTF-8?q?reactor=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E6=B8=85=E7=90=86=20yudao-module-io?= =?UTF-8?q?t-api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-module-iot/pom.xml | 1 - yudao-module-iot/yudao-module-iot-api/pom.xml | 53 ------------------- .../upstream/IotDeviceEventReportReqDTO.java | 26 --------- .../IotDevicePropertyReportReqDTO.java | 22 -------- .../IotDeviceUpstreamAbstractReqDTO.java | 45 ---------------- yudao-module-iot/yudao-module-iot-biz/pom.xml | 5 -- .../{rule => alert}/IotAlertConfigDO.java | 29 ++++++---- .../{rule => alert}/IotAlertRecordDO.java | 15 +++--- .../dal/dataobject/rule/IotSceneRuleDO.java | 1 + .../module/iot/enums/DictTypeConstants.java | 1 + .../module/iot/enums/ErrorCodeConstants.java | 0 .../alert}/IotAlertConfigReceiveTypeEnum.java | 2 +- .../IotDeviceMessageIdentifierEnum.java | 0 .../device/IotDeviceMessageTypeEnum.java | 0 .../ota/IotOtaUpgradeRecordStatusEnum.java | 0 .../enums/ota/IotOtaUpgradeTaskScopeEnum.java | 0 .../ota/IotOtaUpgradeTaskStatusEnum.java | 0 .../iot/enums/product/IotNetTypeEnum.java | 0 .../product/IotProductDeviceTypeEnum.java | 0 .../enums/product/IotProductStatusEnum.java | 0 .../iot/enums/rule/IotDataSinkTypeEnum.java | 11 ++-- .../rule/IotRuleSceneActionTypeEnum.java | 0 .../IotRuleSceneConditionOperatorEnum.java | 0 .../rule/IotRuleSceneConditionTypeEnum.java | 0 .../rule/IotRuleSceneTriggerTypeEnum.java | 0 .../thingmodel/IotDataSpecsDataTypeEnum.java | 0 .../IotThingModelAccessModeEnum.java | 0 .../IotThingModelParamDirectionEnum.java | 0 .../IotThingModelServiceCallTypeEnum.java | 0 .../IotThingModelServiceEventTypeEnum.java | 0 .../thingmodel/IotThingModelTypeEnum.java | 0 .../device/IotDeviceMessageSubscriber.java | 7 ++- .../message/IotDeviceMessageServiceImpl.java | 17 +++--- .../rule/data/IotDataRuleServiceImpl.java | 2 +- .../data/action/IotHttpDataSinkAction.java | 15 +++--- .../data/action/IotKafkaDataRuleAction.java | 28 +++++++--- .../action/IotRabbitMQDataRuleAction.java | 34 ++++++------ .../data/action/IotRedisStreamRuleAction.java | 11 ++-- .../action/IotRocketMQDataRuleAction.java | 16 +++--- .../databridge/IotDataBridgeExecuteTest.java | 1 + .../enums/IotDeviceMessageMethodEnum.java | 6 +-- .../iot/core/mq/message/IotDeviceMessage.java | 10 ++-- .../iot/core/util/IotDeviceMessageUtils.java | 9 +++- .../emqx/router/IotEmqxAuthEventHandler.java | 2 +- .../http/router/IotHttpAuthHandler.java | 2 +- 45 files changed, 123 insertions(+), 248 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-api/pom.xml delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEventReportReqDTO.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDevicePropertyReportReqDTO.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceUpstreamAbstractReqDTO.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/{rule => alert}/IotAlertConfigDO.java (60%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/{rule => alert}/IotAlertRecordDO.java (83%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java (88%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java (100%) rename yudao-module-iot/{yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule => yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/alert}/IotAlertConfigReceiveTypeEnum.java (93%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java (100%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java (100%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeRecordStatusEnum.java (100%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskScopeEnum.java (100%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskStatusEnum.java (100%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java (100%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java (100%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java (100%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataSinkTypeEnum.java (63%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java (100%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionOperatorEnum.java (100%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionTypeEnum.java (100%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java (100%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java (100%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java (100%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java (100%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java (100%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java (100%) rename yudao-module-iot/{yudao-module-iot-api => yudao-module-iot-biz}/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelTypeEnum.java (100%) diff --git a/yudao-module-iot/pom.xml b/yudao-module-iot/pom.xml index 074c42e17a..97df8e5185 100644 --- a/yudao-module-iot/pom.xml +++ b/yudao-module-iot/pom.xml @@ -7,7 +7,6 @@ ${revision} - yudao-module-iot-api yudao-module-iot-biz yudao-module-iot-core yudao-module-iot-gateway diff --git a/yudao-module-iot/yudao-module-iot-api/pom.xml b/yudao-module-iot/yudao-module-iot-api/pom.xml deleted file mode 100644 index ef65715aae..0000000000 --- a/yudao-module-iot/yudao-module-iot-api/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - yudao-module-iot - cn.iocoder.boot - ${revision} - - 4.0.0 - yudao-module-iot-api - jar - - ${project.artifactId} - - - 物联网 模块 API,暴露给其它模块调用 - - - - - cn.iocoder.boot - yudao-common - - - - - org.springframework - spring-web - provided - - - - - com.fasterxml.jackson.core - jackson-databind - provided - - - - - - - - - - org.springframework.boot - spring-boot-starter-validation - true - - - - diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEventReportReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEventReportReqDTO.java deleted file mode 100644 index 34e6283d90..0000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEventReportReqDTO.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream; - -import jakarta.validation.constraints.NotEmpty; -import lombok.Data; - -import java.util.Map; - -/** - * IoT 设备【事件】上报 Request DTO - * - * @author 芋道源码 - */ -@Data -public class IotDeviceEventReportReqDTO extends IotDeviceUpstreamAbstractReqDTO { - - /** - * 事件标识 - */ - @NotEmpty(message = "事件标识不能为空") - private String identifier; - /** - * 事件参数 - */ - private Map params; - -} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDevicePropertyReportReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDevicePropertyReportReqDTO.java deleted file mode 100644 index 4a276bd226..0000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDevicePropertyReportReqDTO.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream; - -import jakarta.validation.constraints.NotEmpty; -import lombok.Data; - -import java.util.Map; - -/** - * IoT 设备【属性】上报 Request DTO - * - * @author 芋道源码 - */ -@Data -public class IotDevicePropertyReportReqDTO extends IotDeviceUpstreamAbstractReqDTO { - - /** - * 属性参数 - */ - @NotEmpty(message = "属性参数不能为空") - private Map properties; - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceUpstreamAbstractReqDTO.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceUpstreamAbstractReqDTO.java deleted file mode 100644 index a0c8ce92ac..0000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceUpstreamAbstractReqDTO.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream; - -import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import jakarta.validation.constraints.NotEmpty; -import lombok.Data; - -import java.time.LocalDateTime; - -/** - * IoT 设备上行的抽象 Request DTO - * - * @author 芋道源码 - */ -@Data -public abstract class IotDeviceUpstreamAbstractReqDTO { - - /** - * 请求编号 - */ - private String requestId; - - /** - * 插件实例的进程编号 - */ - private String processId; - - /** - * 产品标识 - */ - @NotEmpty(message = "产品标识不能为空") - private String productKey; - /** - * 设备名称 - */ - @NotEmpty(message = "设备名称不能为空") - private String deviceName; - - /** - * 上报时间 - */ - @JsonSerialize(using = TimestampLocalDateTimeSerializer.class) // 解决 iot plugins 序列化 LocalDateTime 是数组,导致无法解析的问题 - private LocalDateTime reportTime; - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index aca7e303f0..1f83a7acb2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -23,11 +23,6 @@ yudao-module-system ${revision} - - cn.iocoder.boot - yudao-module-iot-api - ${revision} - cn.iocoder.boot yudao-module-iot-core diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertConfigDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertConfigDO.java similarity index 60% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertConfigDO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertConfigDO.java index 14e7d741fe..b7e5fd781c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertConfigDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertConfigDO.java @@ -1,14 +1,21 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.rule; +package cn.iocoder.yudao.module.iot.dal.dataobject.alert; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.iot.enums.rule.IotAlertConfigReceiveTypeEnum; +import cn.iocoder.yudao.framework.mybatis.core.type.IntegerListTypeHandler; +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; +import cn.iocoder.yudao.module.iot.enums.DictTypeConstants; +import cn.iocoder.yudao.module.iot.enums.alert.IotAlertConfigReceiveTypeEnum; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; -import lombok.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; import java.util.List; @@ -41,37 +48,37 @@ public class IotAlertConfigDO extends BaseDO { /** * 配置状态 * - * TODO 数据字典 + * 字典 {@link DictTypeConstants#ALERT_LEVEL} */ private Integer level; /** * 配置状态 * - * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + * 枚举 {@link CommonStatusEnum} */ private Integer status; /** - * 关联的规则场景编号数组 + * 关联的场景联动规则编号数组 * * 关联 {@link IotRuleSceneDO#getId()} */ - @TableField(typeHandler = JacksonTypeHandler.class) - private List ruleSceneIds; + @TableField(typeHandler = LongListTypeHandler.class) + private List sceneRuleIds; /** * 接收的用户编号数组 * * 关联 {@link AdminUserRespDTO#getId()} */ - @TableField(typeHandler = JacksonTypeHandler.class) + @TableField(typeHandler = LongListTypeHandler.class) private List receiveUserIds; /** * 接收的类型数组 * * 枚举 {@link IotAlertConfigReceiveTypeEnum} */ - @TableField(typeHandler = JacksonTypeHandler.class) + @TableField(typeHandler = IntegerListTypeHandler.class) private List receiveTypes; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertRecordDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertRecordDO.java similarity index 83% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertRecordDO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertRecordDO.java index 43a1c6360f..7b5202d244 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotAlertRecordDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertRecordDO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.rule; +package cn.iocoder.yudao.module.iot.dal.dataobject.alert; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; @@ -45,17 +45,17 @@ public class IotAlertRecordDO extends BaseDO { private String name; /** - * 产品标识 + * 产品编号 * - * 关联 {@link IotProductDO#getProductKey()} ()} + * 关联 {@link IotProductDO#getId()} */ - private String productKey; + private Long productId; /** - * 设备名称 + * 设备编号 * - * 冗余 {@link IotDeviceDO#getDeviceName()} + * 关联 {@link IotDeviceDO#getId()} */ - private String deviceName; + private String deviceId; // TODO @芋艿:有没更好的方式 /** @@ -64,7 +64,6 @@ public class IotAlertRecordDO extends BaseDO { @TableField(typeHandler = JacksonTypeHandler.class) private IotDeviceMessage deviceMessage; - // TODO @芋艿:换成枚举,枚举对应 ApiErrorLogProcessStatusEnum /** * 处理状态 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotSceneRuleDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotSceneRuleDO.java index 78eb7fb11b..a65e0f3cf2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotSceneRuleDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotSceneRuleDO.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.rule; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java similarity index 88% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java index 37c8044211..b7750bd0b0 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java @@ -14,5 +14,6 @@ public class DictTypeConstants { public static final String DEVICE_STATE = "iot_device_state"; + public static final String ALERT_LEVEL = "iot_alert_level"; } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotAlertConfigReceiveTypeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/alert/IotAlertConfigReceiveTypeEnum.java similarity index 93% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotAlertConfigReceiveTypeEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/alert/IotAlertConfigReceiveTypeEnum.java index 3fdd53234b..0f3315ba21 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotAlertConfigReceiveTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/alert/IotAlertConfigReceiveTypeEnum.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.enums.rule; +package cn.iocoder.yudao.module.iot.enums.alert; import cn.iocoder.yudao.framework.common.core.ArrayValuable; import lombok.Getter; diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeRecordStatusEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeRecordStatusEnum.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeRecordStatusEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeRecordStatusEnum.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskScopeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskScopeEnum.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskScopeEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskScopeEnum.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskStatusEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskStatusEnum.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskStatusEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskStatusEnum.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataSinkTypeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataSinkTypeEnum.java similarity index 63% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataSinkTypeEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataSinkTypeEnum.java index ed341c618b..33b3558775 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataSinkTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataSinkTypeEnum.java @@ -16,14 +16,13 @@ import java.util.Arrays; public enum IotDataSinkTypeEnum implements ArrayValuable { HTTP(1, "HTTP"), - TCP(2, "TCP"), - WEBSOCKET(3, "WebSocket"), + TCP(2, "TCP"), // TODO @puhui999:待实现; + WEBSOCKET(3, "WebSocket"), // TODO @puhui999:待实现; - MQTT(10, "MQTT"), + MQTT(10, "MQTT"), // TODO 待实现; - DATABASE(20, "Database"), - // TODO @芋艿:改成 Redis;通过 execute 通用化; - REDIS_STREAM(21, "Redis Stream"), + DATABASE(20, "Database"), // TODO @puhui999:待实现;可以简单点,对应的表名是什么,字段先固定了。 + REDIS_STREAM(21, "Redis Stream"), // TODO @puhui999:改成 Redis;然后枚举不同的数据结构?这样,枚举就可以是 Redis 了 ROCKETMQ(30, "RocketMQ"), RABBITMQ(31, "RabbitMQ"), diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionOperatorEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionOperatorEnum.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionOperatorEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionOperatorEnum.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionTypeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionTypeEnum.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionTypeEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionTypeEnum.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelTypeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelTypeEnum.java similarity index 100% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelTypeEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelTypeEnum.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceMessageSubscriber.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceMessageSubscriber.java index 3eaa019fd2..c6e0ba4221 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceMessageSubscriber.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceMessageSubscriber.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.iot.mq.consumer.device; import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum; @@ -19,6 +18,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import java.time.LocalDateTime; +import java.util.Objects; /** * 针对 {@link IotDeviceMessage} 的业务处理器:调用 method 对应的逻辑。例如说: @@ -83,15 +83,14 @@ public class IotDeviceMessageSubscriber implements IotMessageSubscriber ObjectUtils.equalsAny(config.getDeviceId(), deviceId, IotDeviceDO.DEVICE_ID_ALL) - && (StrUtil.isNotEmpty(config.getMethod()) || ObjUtil.equal(config.getMethod(), method)) + && Objects.equals(config.getMethod(), method) && (StrUtil.isEmpty(config.getIdentifier()) || ObjUtil.equal(config.getIdentifier(), identifier))); if (found != null) { matchedRules.add(new IotDataRuleDO().setId(rule.getId()).setSinkIds(rule.getSinkIds())); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataSinkAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataSinkAction.java index c23e346dbf..3f4b8eb028 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataSinkAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataSinkAction.java @@ -18,6 +18,8 @@ import org.springframework.web.util.UriComponentsBuilder; import java.util.HashMap; import java.util.Map; +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; + /** * HTTP 的 {@link IotDataRuleAction} 实现类 * @@ -36,6 +38,7 @@ public class IotHttpDataSinkAction implements IotDataRuleAction { } @Override + @SuppressWarnings("unchecked") public void execute(IotDeviceMessage message, IotDataSinkDO dataSink) { IotDataSinkHttpConfig config = (IotDataSinkHttpConfig) dataSink.getConfig(); Assert.notNull(config, "配置({})不能为空", dataSink.getId()); @@ -49,8 +52,7 @@ public class IotHttpDataSinkAction implements IotDataRuleAction { if (CollUtil.isNotEmpty(config.getHeaders())) { config.getHeaders().putAll(config.getHeaders()); } - // TODO @puhui999:@yunai:可能需要通过设备查询到租户,然后 set -// headers.add(HEADER_TENANT_ID, message.getTenantId().toString()); + headers.add(HEADER_TENANT_ID, message.getTenantId().toString()); // 1.2 构建 URL UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(config.getUrl()); if (CollUtil.isNotEmpty(config.getQuery())) { @@ -72,18 +74,17 @@ public class IotHttpDataSinkAction implements IotDataRuleAction { requestEntity = new HttpEntity<>(JsonUtils.toJsonString(requestBody), headers); } - // 2.1 发送请求 + // 2. 发送请求 responseEntity = restTemplate.exchange(url, method, requestEntity, String.class); - // 2.2 记录日志 if (responseEntity.getStatusCode().is2xxSuccessful()) { - log.info("[executeHttp][message({}) config({}) url({}) method({}) requestEntity({}) 请求成功({})]", + log.info("[execute][message({}) config({}) url({}) method({}) requestEntity({}) 请求成功({})]", message, config, url, method, requestEntity, responseEntity); } else { - log.error("[executeHttp][message({}) config({}) url({}) method({}) requestEntity({}) 请求失败({})]", + log.error("[execute][message({}) config({}) url({}) method({}) requestEntity({}) 请求失败({})]", message, config, url, method, requestEntity, responseEntity); } } catch (Exception e) { - log.error("[executeHttp][message({}) config({}) url({}) method({}) requestEntity({}) 请求异常({})]", + log.error("[execute][message({}) config({}) url({}) method({}) requestEntity({}) 请求异常({})]", message, config, url, method, requestEntity, responseEntity, e); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotKafkaDataRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotKafkaDataRuleAction.java index 5bbbe07b4b..6d85798bff 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotKafkaDataRuleAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotKafkaDataRuleAction.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.service.rule.data.action; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataSinkKafkaConfig; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.enums.rule.IotDataSinkTypeEnum; @@ -9,6 +10,7 @@ import org.apache.kafka.common.serialization.StringSerializer; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.support.SendResult; import org.springframework.stereotype.Component; import java.time.Duration; @@ -36,13 +38,27 @@ public class IotKafkaDataRuleAction extends @Override public void execute(IotDeviceMessage message, IotDataSinkKafkaConfig config) throws Exception { - // 1. 获取或创建 KafkaTemplate - KafkaTemplate kafkaTemplate = getProducer(config); + try { + // 1. 获取或创建 KafkaTemplate + KafkaTemplate kafkaTemplate = getProducer(config); - // 2. 发送消息并等待结果 - kafkaTemplate.send(config.getTopic(), message.toString()) - .get(SEND_TIMEOUT.getSeconds(), TimeUnit.SECONDS); // 添加超时等待 - log.info("[execute0][message({}) 发送成功]", message); + // 2. 发送消息并等待结果 + SendResult sendResult = kafkaTemplate.send(config.getTopic(), JsonUtils.toJsonString(message)) + .get(SEND_TIMEOUT.getSeconds(), TimeUnit.SECONDS); + // 3. 处理发送结果 + if (sendResult != null && sendResult.getRecordMetadata() != null) { + log.info("[execute][message({}) config({}) 发送成功,结果: partition={}, offset={}, timestamp={}]", + message, config, + sendResult.getRecordMetadata().partition(), + sendResult.getRecordMetadata().offset(), + sendResult.getRecordMetadata().timestamp()); + } else { + log.warn("[execute][message({}) config({}) 发送结果为空]", message, config); + } + } catch (Exception e) { + log.error("[execute][message({}) config({}) 发送失败]", message, config, e); + throw e; + } } @Override diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRabbitMQDataRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRabbitMQDataRuleAction.java index 89d3500c6a..075871a376 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRabbitMQDataRuleAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRabbitMQDataRuleAction.java @@ -1,7 +1,8 @@ package cn.iocoder.yudao.module.iot.service.rule.data.action; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataSinkRabbitMQConfig; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataSinkRabbitMQConfig; import cn.iocoder.yudao.module.iot.enums.rule.IotDataSinkTypeEnum; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; @@ -10,8 +11,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.stereotype.Component; -import java.nio.charset.StandardCharsets; - /** * RabbitMQ 的 {@link IotDataRuleAction} 实现类 * @@ -20,8 +19,8 @@ import java.nio.charset.StandardCharsets; @ConditionalOnClass(name = "com.rabbitmq.client.Channel") @Component @Slf4j -public class IotRabbitMQDataRuleAction extends - IotDataRuleCacheableAction { +public class IotRabbitMQDataRuleAction + extends IotDataRuleCacheableAction { @Override public Integer getType() { @@ -30,17 +29,22 @@ public class IotRabbitMQDataRuleAction extends @Override public void execute(IotDeviceMessage message, IotDataSinkRabbitMQConfig config) throws Exception { - // 1.1 获取或创建 Channel - Channel channel = getProducer(config); - // 1.2 声明交换机、队列和绑定关系 - channel.exchangeDeclare(config.getExchange(), "direct", true); - channel.queueDeclare(config.getQueue(), true, false, false, null); - channel.queueBind(config.getQueue(), config.getExchange(), config.getRoutingKey()); + try { + // 1.1 获取或创建 Channel + Channel channel = getProducer(config); + // 1.2 声明交换机、队列和绑定关系 + channel.exchangeDeclare(config.getExchange(), "direct", true); + channel.queueDeclare(config.getQueue(), true, false, false, null); + channel.queueBind(config.getQueue(), config.getExchange(), config.getRoutingKey()); - // 2. 发送消息 - channel.basicPublish(config.getExchange(), config.getRoutingKey(), null, - message.toString().getBytes(StandardCharsets.UTF_8)); - log.info("[executeRabbitMQ][message({}) config({}) 发送成功]", message, config); + // 2. 发送消息 + channel.basicPublish(config.getExchange(), config.getRoutingKey(), null, + JsonUtils.toJsonByte(message)); + log.info("[execute][message({}) config({}) 发送成功]", message, config); + } catch (Exception e) { + log.error("[execute][message({}) config({}) 发送失败]", message, config, e); + throw e; + } } @Override diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRedisStreamRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRedisStreamRuleAction.java index 9870c7d464..d3bb81c8e9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRedisStreamRuleAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRedisStreamRuleAction.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.service.rule.data.action; import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataSinkRedisStreamConfig; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.enums.rule.IotDataSinkTypeEnum; @@ -38,10 +39,10 @@ public class IotRedisStreamRuleAction extends RedisTemplate redisTemplate = getProducer(config); // 2. 创建并发送 Stream 记录 - ObjectRecord record = StreamRecords.newRecord() - .ofObject(message).withStreamKey(config.getTopic()); + ObjectRecord record = StreamRecords.newRecord() + .ofObject(JsonUtils.toJsonString(message)).withStreamKey(config.getTopic()); String recordId = String.valueOf(redisTemplate.opsForStream().add(record)); - log.info("[executeRedisStream][消息发送成功] messageId: {}, config: {}", recordId, config); + log.info("[execute][消息发送成功] messageId: {}, config: {}", recordId, config); } @Override @@ -56,11 +57,11 @@ public class IotRedisStreamRuleAction extends serverConfig.setPassword(config.getPassword()); } - // 创建 RedisTemplate 并配置 + // 2.1 创建 RedisTemplate 并配置 RedissonClient redisson = Redisson.create(redissonConfig); RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(new RedissonConnectionFactory(redisson)); - // 设置序列化器 + // 2.2 设置序列化器 template.setKeySerializer(RedisSerializer.string()); template.setHashKeySerializer(RedisSerializer.string()); template.setValueSerializer(RedisSerializer.json()); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRocketMQDataRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRocketMQDataRuleAction.java index 1a212ec5ea..d73205c6df 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRocketMQDataRuleAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotRocketMQDataRuleAction.java @@ -1,14 +1,14 @@ package cn.iocoder.yudao.module.iot.service.rule.data.action; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataSinkRocketMQConfig; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.config.IotDataSinkRocketMQConfig; import cn.iocoder.yudao.module.iot.enums.rule.IotDataSinkTypeEnum; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.client.producer.DefaultMQProducer; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.common.message.Message; -import org.apache.rocketmq.remoting.common.RemotingHelper; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.stereotype.Component; @@ -33,19 +33,15 @@ public class IotRocketMQDataRuleAction extends // 1. 获取或创建 Producer DefaultMQProducer producer = getProducer(config); - // 2.1 创建消息对象,指定Topic、Tag和消息体 - Message msg = new Message( - config.getTopic(), - config.getTags(), - message.toString().getBytes(RemotingHelper.DEFAULT_CHARSET) - ); + // 2.1 创建消息对象,指定 Topic、Tag 和消息体 + Message msg = new Message(config.getTopic(), config.getTags(), JsonUtils.toJsonByte(message)); // 2.2 发送同步消息并处理结果 SendResult sendResult = producer.send(msg); // 2.3 处理发送结果 if (SendStatus.SEND_OK.equals(sendResult.getSendStatus())) { - log.info("[executeRocketMQ][message({}) config({}) 发送成功,结果({})]", message, config, sendResult); + log.info("[execute][message({}) config({}) 发送成功,结果({})]", message, config, sendResult); } else { - log.error("[executeRocketMQ][message({}) config({}) 发送失败,结果({})]", message, config, sendResult); + log.error("[execute][message({}) config({}) 发送失败,结果({})]", message, config, sendResult); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java index a1f7700394..5394008022 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java @@ -39,6 +39,7 @@ public class IotDataBridgeExecuteTest extends BaseMockitoUnitTest { @BeforeEach public void setUp() { + // TODO @芋艿:@puhui999:需要调整下; // 创建共享的测试消息 //message = IotDeviceMessage.builder().messageId("TEST-001").reportTime(LocalDateTime.now()) // .productKey("testProduct").deviceName("testDevice") diff --git a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums/IotDeviceMessageMethodEnum.java b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums/IotDeviceMessageMethodEnum.java index 92fe71f033..cb343e33ec 100644 --- a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums/IotDeviceMessageMethodEnum.java +++ b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums/IotDeviceMessageMethodEnum.java @@ -19,10 +19,6 @@ public enum IotDeviceMessageMethodEnum implements ArrayValuable { // ========== 设备状态 ========== - // TODO @芋艿:要合并下;thing.state.update - STATE_ONLINE("thing.state.online", "设备上线", true), - STATE_OFFLINE("thing.state.offline", "设备下线", true), - STATE_UPDATE("thing.state.update", "设备状态更新", true), // ========== 设备属性 ========== @@ -52,7 +48,7 @@ public enum IotDeviceMessageMethodEnum implements ArrayValuable { /** * 不进行 reply 回复的方法集合 */ - public static final Set REPLY_DISABLED = Set.of(STATE_ONLINE.getMethod(), STATE_OFFLINE.getMethod()); + public static final Set REPLY_DISABLED = Set.of(STATE_UPDATE.getMethod()); private final String method; diff --git a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/mq/message/IotDeviceMessage.java b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/mq/message/IotDeviceMessage.java index 046e75f61f..01af310081 100644 --- a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/mq/message/IotDeviceMessage.java +++ b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/mq/message/IotDeviceMessage.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.iot.core.mq.message; +import cn.hutool.core.map.MapUtil; import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; +import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum; import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; import lombok.AllArgsConstructor; import lombok.Builder; @@ -128,12 +130,14 @@ public class IotDeviceMessage { // ========== 核心方法:在 of 基础方法之上,添加对应 method ========== - public static IotDeviceMessage buildStateOnline() { - return requestOf(IotDeviceMessageMethodEnum.STATE_ONLINE.getMethod()); + public static IotDeviceMessage buildStateUpdateOnline() { + return requestOf(IotDeviceMessageMethodEnum.STATE_UPDATE.getMethod(), + MapUtil.of("state", IotDeviceStateEnum.ONLINE.getState())); } public static IotDeviceMessage buildStateOffline() { - return requestOf(IotDeviceMessageMethodEnum.STATE_OFFLINE.getMethod()); + return requestOf(IotDeviceMessageMethodEnum.STATE_UPDATE.getMethod(), + MapUtil.of("state", IotDeviceStateEnum.OFFLINE.getState())); } } diff --git a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotDeviceMessageUtils.java b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotDeviceMessageUtils.java index a82d4139c8..5b7778ea0c 100644 --- a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotDeviceMessageUtils.java +++ b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotDeviceMessageUtils.java @@ -55,11 +55,16 @@ public class IotDeviceMessageUtils { */ @SuppressWarnings("unchecked") public static String getIdentifier(IotDeviceMessage message) { + if (message.getParams() == null) { + return null; + } if (StrUtil.equalsAny(message.getMethod(), IotDeviceMessageMethodEnum.EVENT_POST.getMethod(), - message.getMethod(), IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod()) - && message.getParams() != null) { + IotDeviceMessageMethodEnum.SERVICE_INVOKE.getMethod())) { Map params = (Map) message.getParams(); return MapUtil.getStr(params, "identifier"); + } else if (StrUtil.equalsAny(message.getMethod(), IotDeviceMessageMethodEnum.STATE_UPDATE.getMethod())) { + Map params = (Map) message.getParams(); + return MapUtil.getStr(params, "state"); } return null; } diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxAuthEventHandler.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxAuthEventHandler.java index 6bf33e2b76..d6957bd52f 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxAuthEventHandler.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxAuthEventHandler.java @@ -209,7 +209,7 @@ public class IotEmqxAuthEventHandler { try { // 2. 构建设备状态消息 - IotDeviceMessage message = online ? IotDeviceMessage.buildStateOnline() + IotDeviceMessage message = online ? IotDeviceMessage.buildStateUpdateOnline() : IotDeviceMessage.buildStateOffline(); // 3. 发送设备状态消息 diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpAuthHandler.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpAuthHandler.java index 7b2e923349..e6a52cdf0f 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpAuthHandler.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpAuthHandler.java @@ -78,7 +78,7 @@ public class IotHttpAuthHandler extends IotHttpAbstractHandler { Assert.notBlank(token, "生成 token 不能为空位"); // 3. 执行上线 - IotDeviceMessage message = IotDeviceMessage.buildStateOnline(); + IotDeviceMessage message = IotDeviceMessage.buildStateUpdateOnline(); deviceMessageService.sendDeviceMessage(message, deviceInfo.getProductKey(), deviceInfo.getDeviceName(), protocol.getServerId()); From 4ebaa3d60c51a03bf5a82e4958a01634f512fbcb Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 27 Jun 2025 20:29:43 +0800 Subject: [PATCH 09/33] =?UTF-8?q?reactor=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E7=AE=80=E5=8C=96=E7=89=A9=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E7=9A=84=20CRUD=20=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mysql/thingmodel/IotThingModelMapper.java | 13 -- .../thingmodel/IotThingModelServiceImpl.java | 187 +----------------- 2 files changed, 8 insertions(+), 192 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java index ac9638b972..64529dfd08 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java @@ -25,8 +25,6 @@ public interface IotThingModelMapper extends BaseMapperX { .likeIfPresent(IotThingModelDO::getName, reqVO.getName()) .eqIfPresent(IotThingModelDO::getType, reqVO.getType()) .eqIfPresent(IotThingModelDO::getProductId, reqVO.getProductId()) - // TODO @芋艿:看看要不要加枚举 - .notIn(IotThingModelDO::getIdentifier, "get", "set", "post") .orderByDesc(IotThingModelDO::getId)); } @@ -36,8 +34,6 @@ public interface IotThingModelMapper extends BaseMapperX { .likeIfPresent(IotThingModelDO::getName, reqVO.getName()) .eqIfPresent(IotThingModelDO::getType, reqVO.getType()) .eqIfPresent(IotThingModelDO::getProductId, reqVO.getProductId()) - // TODO @芋艿:看看要不要加枚举 - .notIn(IotThingModelDO::getIdentifier, "get", "set", "post") .orderByDesc(IotThingModelDO::getId)); } @@ -61,15 +57,6 @@ public interface IotThingModelMapper extends BaseMapperX { IotThingModelDO::getType, type); } - default List selectListByProductIdAndIdentifiersAndTypes(Long productId, - List identifiers, - List types) { - return selectList(new LambdaQueryWrapperX() - .eq(IotThingModelDO::getProductId, productId) - .in(IotThingModelDO::getIdentifier, identifiers) - .in(IotThingModelDO::getType, types)); - } - default IotThingModelDO selectByProductIdAndName(Long productId, String name) { return selectOne(IotThingModelDO::getProductId, productId, IotThingModelDO::getName, name); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java index 1de8dd5cc8..dc7c71c6ee 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java @@ -5,11 +5,7 @@ import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelParam; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelListReqVO; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelSaveReqVO; @@ -19,7 +15,6 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import cn.iocoder.yudao.module.iot.dal.mysql.thingmodel.IotThingModelMapper; import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; -import cn.iocoder.yudao.module.iot.enums.thingmodel.*; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -29,10 +24,13 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; -import java.util.*; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; /** @@ -65,12 +63,7 @@ public class IotThingModelServiceImpl implements IotThingModelService { IotThingModelDO thingModel = IotThingModelConvert.INSTANCE.convert(createReqVO); thingModelMapper.insert(thingModel); - // 3. 如果创建的是属性,需要更新默认的事件和服务 - if (Objects.equals(createReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { - createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); - } - - // 4. 删除缓存 + // 3. 删除缓存 deleteThingModelListCache(createReqVO.getProductKey()); return thingModel.getId(); } @@ -89,12 +82,7 @@ public class IotThingModelServiceImpl implements IotThingModelService { IotThingModelDO thingModel = IotThingModelConvert.INSTANCE.convert(updateReqVO); thingModelMapper.updateById(thingModel); - // 3. 如果更新的是属性,需要更新默认的事件和服务 - if (Objects.equals(updateReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { - createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey()); - } - - // 4. 删除缓存 + // 3. 删除缓存 deleteThingModelListCache(updateReqVO.getProductKey()); } @@ -112,12 +100,7 @@ public class IotThingModelServiceImpl implements IotThingModelService { // 2. 删除功能 thingModelMapper.deleteById(id); - // 3. 如果删除的是属性,需要更新默认的事件和服务 - if (Objects.equals(thingModel.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { - createDefaultEventsAndServices(thingModel.getProductId(), thingModel.getProductKey()); - } - - // 4. 删除缓存 + // 3. 删除缓存 deleteThingModelListCache(thingModel.getProductKey()); } @@ -221,160 +204,6 @@ public class IotThingModelServiceImpl implements IotThingModelService { } } - /** - * 创建默认的事件和服务 - * - * @param productId 产品编号 - * @param productKey 产品标识 - */ - public void createDefaultEventsAndServices(Long productId, String productKey) { - // 1. 获取当前属性列表 - List properties = thingModelMapper - .selectListByProductIdAndType(productId, IotThingModelTypeEnum.PROPERTY.getType()); - - // 2. 生成新的事件和服务列表 - List newThingModels = new ArrayList<>(); - // 2.1 生成属性上报事件 - ThingModelEvent propertyPostEvent = generatePropertyPostEvent(properties); - if (propertyPostEvent != null) { - newThingModels.add(buildEventThingModel(productId, productKey, propertyPostEvent, "属性上报事件")); - } - // 2.2 生成属性设置服务 - ThingModelService propertySetService = generatePropertySetService(properties); - if (propertySetService != null) { - newThingModels.add(buildServiceThingModel(productId, productKey, propertySetService, "属性设置服务")); - } - // 2.3 生成属性获取服务 - ThingModelService propertyGetService = generatePropertyGetService(properties); - if (propertyGetService != null) { - newThingModels.add(buildServiceThingModel(productId, productKey, propertyGetService, "属性获取服务")); - } - - // 3.1 获取数据库中的默认的旧事件和服务列表 - List oldThingModels = thingModelMapper.selectListByProductIdAndIdentifiersAndTypes( - productId, - Arrays.asList("post", "set", "get"), - Arrays.asList(IotThingModelTypeEnum.EVENT.getType(), IotThingModelTypeEnum.SERVICE.getType()) - ); - // 3.2 创建默认的事件和服务 - createDefaultEventsAndServices(oldThingModels, newThingModels); - } - - /** - * 创建默认的事件和服务 - */ - private void createDefaultEventsAndServices(List oldThingModels, - List newThingModels) { - // 使用 diffList 方法比较新旧列表 - List> diffResult = diffList(oldThingModels, newThingModels, - (oldVal, newVal) -> { - // 继续使用 identifier 和 type 进行比较:这样可以准确地匹配对应的功能对象。 - boolean same = Objects.equals(oldVal.getIdentifier(), newVal.getIdentifier()) - && Objects.equals(oldVal.getType(), newVal.getType()); - if (same) { - newVal.setId(oldVal.getId()); // 设置编号 - } - return same; - }); - // 批量添加、修改、删除 - if (CollUtil.isNotEmpty(diffResult.get(0))) { - thingModelMapper.insertBatch(diffResult.get(0)); - } - if (CollUtil.isNotEmpty(diffResult.get(1))) { - thingModelMapper.updateBatch(diffResult.get(1)); - } - if (CollUtil.isNotEmpty(diffResult.get(2))) { - thingModelMapper.deleteByIds(convertSet(diffResult.get(2), IotThingModelDO::getId)); - } - } - - /** - * 构建事件功能对象 - */ - private IotThingModelDO buildEventThingModel(Long productId, String productKey, - ThingModelEvent event, String description) { - return new IotThingModelDO().setProductId(productId).setProductKey(productKey) - .setIdentifier(event.getIdentifier()).setName(event.getName()).setDescription(description) - .setType(IotThingModelTypeEnum.EVENT.getType()).setEvent(event); - } - - /** - * 构建服务功能对象 - */ - private IotThingModelDO buildServiceThingModel(Long productId, String productKey, - ThingModelService service, String description) { - return new IotThingModelDO().setProductId(productId).setProductKey(productKey) - .setIdentifier(service.getIdentifier()).setName(service.getName()).setDescription(description) - .setType(IotThingModelTypeEnum.SERVICE.getType()).setService(service); - } - - // TODO @haohao:是不是不用生成这个?目前属性上报,是个批量接口 - - /** - * 生成属性上报事件 - */ - private ThingModelEvent generatePropertyPostEvent(List thingModels) { - // 没有属性则不生成 - if (CollUtil.isEmpty(thingModels)) { - return null; - } - - // 生成属性上报事件 - return new ThingModelEvent().setIdentifier("post").setName("属性上报").setMethod("thing.event.property.post") - .setType(IotThingModelServiceEventTypeEnum.INFO.getType()) - .setOutputParams(buildInputOutputParam(thingModels, IotThingModelParamDirectionEnum.OUTPUT)); - } - - // TODO @haohao:是不是不用生成这个?目前属性上报,是个批量接口 - - /** - * 生成属性设置服务 - */ - private ThingModelService generatePropertySetService(List thingModels) { - // 1.1 过滤出所有可写属性 - thingModels = filterList(thingModels, thingModel -> - IotThingModelAccessModeEnum.READ_WRITE.getMode().equals(thingModel.getProperty().getAccessMode())); - // 1.2 没有可写属性则不生成 - if (CollUtil.isEmpty(thingModels)) { - return null; - } - - // 2. 生成属性设置服务 - return new ThingModelService().setIdentifier("set").setName("属性设置").setMethod("thing.service.property.set") - .setCallType(IotThingModelServiceCallTypeEnum.ASYNC.getType()) - .setInputParams(buildInputOutputParam(thingModels, IotThingModelParamDirectionEnum.INPUT)) - .setOutputParams(Collections.emptyList()); // 属性设置服务一般不需要输出参数 - } - - /** - * 生成属性获取服务 - */ - private ThingModelService generatePropertyGetService(List thingModels) { - // 1.1 没有属性则不生成 - if (CollUtil.isEmpty(thingModels)) { - return null; - } - - // 1.2 生成属性获取服务 - return new ThingModelService().setIdentifier("get").setName("属性获取").setMethod("thing.service.property.get") - .setCallType(IotThingModelServiceCallTypeEnum.ASYNC.getType()) - .setInputParams(buildInputOutputParam(thingModels, IotThingModelParamDirectionEnum.INPUT)) - .setOutputParams(buildInputOutputParam(thingModels, IotThingModelParamDirectionEnum.OUTPUT)); - } - - /** - * 构建输入/输出参数列表 - * - * @param thingModels 属性列表 - * @return 输入/输出参数列表 - */ - private List buildInputOutputParam(List thingModels, - IotThingModelParamDirectionEnum direction) { - return convertList(thingModels, thingModel -> - BeanUtils.toBean(thingModel.getProperty(), ThingModelParam.class).setParaOrder(0) // TODO @puhui999: 先搞个默认值看看怎么个事 - .setDirection(direction.getDirection())); - } - private void deleteThingModelListCache(String productKey) { // 保证 Spring AOP 触发 getSelf().deleteThingModelListCache0(productKey); From 9d6b37c47637fc883ba7c1ad0218f7b91ecdd82a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 27 Jun 2025 22:39:25 +0800 Subject: [PATCH 10/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E5=88=9D=E5=A7=8B=E5=8C=96=E5=91=8A?= =?UTF-8?q?=E8=AD=A6=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/alert/IotAlertConfigController.java | 82 +++++++++++++++++++ .../alert/vo/IotAlertConfigPageReqVO.java | 26 ++++++ .../admin/alert/vo/IotAlertConfigRespVO.java | 40 +++++++++ .../alert/vo/IotAlertConfigSaveReqVO.java | 47 +++++++++++ .../dal/mysql/alert/IotAlertConfigMapper.java | 26 ++++++ .../module/iot/enums/ErrorCodeConstants.java | 3 + .../service/alert/IotAlertConfigService.java | 54 ++++++++++++ .../alert/IotAlertConfigServiceImpl.java | 68 +++++++++++++++ 8 files changed, 346 insertions(+) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertConfigController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigPageReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigSaveReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertConfigMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertConfigController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertConfigController.java new file mode 100644 index 0000000000..228926bb70 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertConfigController.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.iot.controller.admin.alert; + +import org.springframework.web.bind.annotation.*; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import jakarta.validation.constraints.*; +import jakarta.validation.*; +import jakarta.servlet.http.*; +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; +import cn.iocoder.yudao.module.iot.service.alert.IotAlertConfigService; + +@Tag(name = "管理后台 - IoT 告警配置") +@RestController +@RequestMapping("/iot/alert-config") +@Validated +public class IotAlertConfigController { + + @Resource + private IotAlertConfigService alertConfigService; + + @PostMapping("/create") + @Operation(summary = "创建告警配置") + @PreAuthorize("@ss.hasPermission('iot:alert-config:create')") + public CommonResult createAlertConfig(@Valid @RequestBody IotAlertConfigSaveReqVO createReqVO) { + return success(alertConfigService.createAlertConfig(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新告警配置") + @PreAuthorize("@ss.hasPermission('iot:alert-config:update')") + public CommonResult updateAlertConfig(@Valid @RequestBody IotAlertConfigSaveReqVO updateReqVO) { + alertConfigService.updateAlertConfig(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除告警配置") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:alert-config:delete')") + public CommonResult deleteAlertConfig(@RequestParam("id") Long id) { + alertConfigService.deleteAlertConfig(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得告警配置") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:alert-config:query')") + public CommonResult getAlertConfig(@RequestParam("id") Long id) { + IotAlertConfigDO alertConfig = alertConfigService.getAlertConfig(id); + return success(BeanUtils.toBean(alertConfig, IotAlertConfigRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得告警配置分页") + @PreAuthorize("@ss.hasPermission('iot:alert-config:query')") + public CommonResult> getAlertConfigPage(@Valid IotAlertConfigPageReqVO pageReqVO) { + PageResult pageResult = alertConfigService.getAlertConfigPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotAlertConfigRespVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigPageReqVO.java new file mode 100644 index 0000000000..2a6ecdf7c6 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigPageReqVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.iot.controller.admin.alert.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - IoT 告警配置分页 Request VO") +@Data +public class IotAlertConfigPageReqVO extends PageParam { + + @Schema(description = "配置名称", example = "赵六") + private String name; + + @Schema(description = "配置状态", example = "1") + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigRespVO.java new file mode 100644 index 0000000000..d15ec4b2ab --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigRespVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.iot.controller.admin.alert.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - IoT 告警配置 Response VO") +@Data +public class IotAlertConfigRespVO { + + @Schema(description = "配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3566") + private Long id; + + @Schema(description = "配置名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + private String name; + + @Schema(description = "配置描述", example = "你猜") + private String description; + + @Schema(description = "告警级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer level; + + @Schema(description = "配置状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "关联的场景联动规则编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3") + private List sceneRuleIds; + + @Schema(description = "接收的用户编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "100,200") + private List receiveUserIds; + + @Schema(description = "接收的类型数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3") + private List receiveTypes; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigSaveReqVO.java new file mode 100644 index 0000000000..231bd4717a --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigSaveReqVO.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.iot.controller.admin.alert.vo; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.List; + +@Schema(description = "管理后台 - IoT 告警配置新增/修改 Request VO") +@Data +public class IotAlertConfigSaveReqVO { + + @Schema(description = "配置编号", example = "3566") + private Long id; + + @Schema(description = "配置名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + @NotEmpty(message = "配置名称不能为空") + private String name; + + @Schema(description = "配置描述", example = "你猜") + private String description; + + @Schema(description = "告警级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "告警级别不能为空") + private Integer level; + + @Schema(description = "配置状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "配置状态不能为空") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @Schema(description = "关联的场景联动规则编号数组") + @NotEmpty(message = "关联的场景联动规则编号数组不能为空") + private List sceneRuleIds; + + @Schema(description = "接收的用户编号数组") + @NotEmpty(message = "接收的用户编号数组不能为空") + private List receiveUserIds; + + @Schema(description = "接收的类型数组") + @NotEmpty(message = "接收的类型数组不能为空") + private List receiveTypes; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertConfigMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertConfigMapper.java new file mode 100644 index 0000000000..6871763211 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertConfigMapper.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.alert; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.IotAlertConfigPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * IoT 告警配置 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface IotAlertConfigMapper extends BaseMapperX { + + default PageResult selectPage(IotAlertConfigPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(IotAlertConfigDO::getName, reqVO.getName()) + .eqIfPresent(IotAlertConfigDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(IotAlertConfigDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(IotAlertConfigDO::getId)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 8217a5b2ae..d186cd2f86 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -64,4 +64,7 @@ public interface ErrorCodeConstants { // ========== IoT 场景联动 1-050-012-000 ========== ErrorCode RULE_SCENE_NOT_EXISTS = new ErrorCode(1_050_012_000, "场景联动不存在"); + // ========== IoT 告警配置 1-050-013-000 ========== + ErrorCode ALERT_CONFIG_NOT_EXISTS = new ErrorCode(1_050_013_000, "IoT 告警配置不存在"); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigService.java new file mode 100644 index 0000000000..cf539f6a88 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigService.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.iot.service.alert; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.IotAlertConfigPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.IotAlertConfigSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; +import jakarta.validation.Valid; + +/** + * IoT 告警配置 Service 接口 + * + * @author 芋道源码 + */ +public interface IotAlertConfigService { + + /** + * 创建告警配置 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createAlertConfig(@Valid IotAlertConfigSaveReqVO createReqVO); + + /** + * 更新告警配置 + * + * @param updateReqVO 更新信息 + */ + void updateAlertConfig(@Valid IotAlertConfigSaveReqVO updateReqVO); + + /** + * 删除告警配置 + * + * @param id 编号 + */ + void deleteAlertConfig(Long id); + + /** + * 获得告警配置 + * + * @param id 编号 + * @return 告警配置 + */ + IotAlertConfigDO getAlertConfig(Long id); + + /** + * 获得告警配置分页 + * + * @param pageReqVO 分页查询 + * @return 告警配置分页 + */ + PageResult getAlertConfigPage(IotAlertConfigPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java new file mode 100644 index 0000000000..ead8559dd7 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.module.iot.service.alert; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.IotAlertConfigPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.IotAlertConfigSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; +import cn.iocoder.yudao.module.iot.dal.mysql.alert.IotAlertConfigMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.ALERT_CONFIG_NOT_EXISTS; + +/** + * IoT 告警配置 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class IotAlertConfigServiceImpl implements IotAlertConfigService { + + @Resource + private IotAlertConfigMapper alertConfigMapper; + + @Override + public Long createAlertConfig(IotAlertConfigSaveReqVO createReqVO) { + IotAlertConfigDO alertConfig = BeanUtils.toBean(createReqVO, IotAlertConfigDO.class); + alertConfigMapper.insert(alertConfig); + return alertConfig.getId(); + } + + @Override + public void updateAlertConfig(IotAlertConfigSaveReqVO updateReqVO) { + // 校验存在 + validateAlertConfigExists(updateReqVO.getId()); + // 更新 + IotAlertConfigDO updateObj = BeanUtils.toBean(updateReqVO, IotAlertConfigDO.class); + alertConfigMapper.updateById(updateObj); + } + + @Override + public void deleteAlertConfig(Long id) { + // 校验存在 + validateAlertConfigExists(id); + // 删除 + alertConfigMapper.deleteById(id); + } + + private void validateAlertConfigExists(Long id) { + if (alertConfigMapper.selectById(id) == null) { + throw exception(ALERT_CONFIG_NOT_EXISTS); + } + } + + @Override + public IotAlertConfigDO getAlertConfig(Long id) { + return alertConfigMapper.selectById(id); + } + + @Override + public PageResult getAlertConfigPage(IotAlertConfigPageReqVO pageReqVO) { + return alertConfigMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file From 1beb5c039cad0fc7679c5abc176fd9ad328bf316 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 27 Jun 2025 23:46:53 +0800 Subject: [PATCH 11/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E5=AE=8C=E6=88=90=E5=91=8A=E8=AD=A6?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=9A=84=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/alert/IotAlertConfigController.java | 55 ++++++++++--------- .../admin/alert/vo/IotAlertConfigRespVO.java | 3 + .../admin/rule/IotRuleSceneController.java | 12 ++++ .../dataobject/alert/IotAlertConfigDO.java | 6 +- .../dal/mysql/rule/IotRuleSceneMapper.java | 6 ++ ...Enum.java => IotAlertReceiveTypeEnum.java} | 9 +-- .../alert/IotAlertConfigServiceImpl.java | 16 ++++++ .../rule/scene/IotRuleSceneService.java | 17 ++++++ .../rule/scene/IotRuleSceneServiceImpl.java | 19 +++++++ 9 files changed, 111 insertions(+), 32 deletions(-) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/alert/{IotAlertConfigReceiveTypeEnum.java => IotAlertReceiveTypeEnum.java} (65%) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertConfigController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertConfigController.java index 228926bb70..d650fa9d7d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertConfigController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertConfigController.java @@ -1,33 +1,30 @@ package cn.iocoder.yudao.module.iot.controller.admin.alert; -import org.springframework.web.bind.annotation.*; -import jakarta.annotation.Resource; -import org.springframework.validation.annotation.Validated; -import org.springframework.security.access.prepost.PreAuthorize; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.Operation; - -import jakarta.validation.constraints.*; -import jakarta.validation.*; -import jakarta.servlet.http.*; -import java.util.*; -import java.io.IOException; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; - -import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; -import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*; - -import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.*; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.IotAlertConfigPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.IotAlertConfigRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.IotAlertConfigSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; import cn.iocoder.yudao.module.iot.service.alert.IotAlertConfigService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap; @Tag(name = "管理后台 - IoT 告警配置") @RestController @@ -38,6 +35,9 @@ public class IotAlertConfigController { @Resource private IotAlertConfigService alertConfigService; + @Resource + private AdminUserApi adminUserApi; + @PostMapping("/create") @Operation(summary = "创建告警配置") @PreAuthorize("@ss.hasPermission('iot:alert-config:create')") @@ -76,7 +76,12 @@ public class IotAlertConfigController { @PreAuthorize("@ss.hasPermission('iot:alert-config:query')") public CommonResult> getAlertConfigPage(@Valid IotAlertConfigPageReqVO pageReqVO) { PageResult pageResult = alertConfigService.getAlertConfigPage(pageReqVO); - return success(BeanUtils.toBean(pageResult, IotAlertConfigRespVO.class)); + // 转换返回 + Map userMap = adminUserApi.getUserMap( + convertSetByFlatMap(pageResult.getList(), config -> config.getReceiveUserIds().stream())); + return success(BeanUtils.toBean(pageResult, IotAlertConfigRespVO.class, vo -> + vo.setReceiveUserNames(vo.getReceiveUserIds().stream().map(userMap::get) + .filter(Objects::nonNull).map(AdminUserRespDTO::getNickname).collect(Collectors.toList())))); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigRespVO.java index d15ec4b2ab..d1e13b74a6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigRespVO.java @@ -31,6 +31,9 @@ public class IotAlertConfigRespVO { @Schema(description = "接收的用户编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "100,200") private List receiveUserIds; + @Schema(description = "接收的用户名称数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三,李四") + private List receiveUserNames; + @Schema(description = "接收的类型数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3") private List receiveTypes; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java index 4168daf0b0..31a95a22f7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.rule; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -18,7 +19,10 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import java.util.List; + import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; @Tag(name = "管理后台 - IoT 场景联动") @RestController @@ -70,6 +74,14 @@ public class IotRuleSceneController { return success(BeanUtils.toBean(pageResult, IotRuleSceneRespVO.class)); } + @GetMapping("/simple-list") + @Operation(summary = "获取场景联动的精简信息列表", description = "主要用于前端的下拉选项") + public CommonResult> getRuleSceneSimpleList() { + List list = ruleSceneService.getRuleSceneListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(convertList(list, scene -> // 只返回 id、name 字段 + new IotRuleSceneRespVO().setId(scene.getId()).setName(scene.getName()))); + } + @GetMapping("/test") @PermitAll public void test() { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertConfigDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertConfigDO.java index b7e5fd781c..2a647f781e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertConfigDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertConfigDO.java @@ -6,7 +6,7 @@ import cn.iocoder.yudao.framework.mybatis.core.type.IntegerListTypeHandler; import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; import cn.iocoder.yudao.module.iot.enums.DictTypeConstants; -import cn.iocoder.yudao.module.iot.enums.alert.IotAlertConfigReceiveTypeEnum; +import cn.iocoder.yudao.module.iot.enums.alert.IotAlertReceiveTypeEnum; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; @@ -24,7 +24,7 @@ import java.util.List; * * @author 芋道源码 */ -@TableName("iot_alert_config") +@TableName(value = "iot_alert_config", autoResultMap = true) @KeySequence("iot_alert_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Builder @@ -76,7 +76,7 @@ public class IotAlertConfigDO extends BaseDO { /** * 接收的类型数组 * - * 枚举 {@link IotAlertConfigReceiveTypeEnum} + * 枚举 {@link IotAlertReceiveTypeEnum} */ @TableField(typeHandler = IntegerListTypeHandler.class) private List receiveTypes; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotRuleSceneMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotRuleSceneMapper.java index c5bf13b2f3..741985a507 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotRuleSceneMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotRuleSceneMapper.java @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleScenePa import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + /** * IoT 场景联动 Mapper * @@ -24,4 +26,8 @@ public interface IotRuleSceneMapper extends BaseMapperX { .orderByDesc(IotRuleSceneDO::getId)); } + default List selectListByStatus(Integer status) { + return selectList(IotRuleSceneDO::getStatus, status); + } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/alert/IotAlertConfigReceiveTypeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/alert/IotAlertReceiveTypeEnum.java similarity index 65% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/alert/IotAlertConfigReceiveTypeEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/alert/IotAlertReceiveTypeEnum.java index 0f3315ba21..d70aea5c6a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/alert/IotAlertConfigReceiveTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/alert/IotAlertReceiveTypeEnum.java @@ -7,21 +7,22 @@ import lombok.RequiredArgsConstructor; import java.util.Arrays; /** - * IoT 告警配置的接收方式枚举 + * IoT 告警的接收方式枚举 * * @author 芋道源码 */ @RequiredArgsConstructor @Getter -public enum IotAlertConfigReceiveTypeEnum implements ArrayValuable { +public enum IotAlertReceiveTypeEnum implements ArrayValuable { SMS(1), // 短信 MAIL(2), // 邮箱 - NOTIFY(3); // 通知 + NOTIFY(3); // 站内信 + // TODO 待实现(欢迎 pull request):webhook 4 private final Integer type; - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotAlertConfigReceiveTypeEnum::getType).toArray(Integer[]::new); + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotAlertReceiveTypeEnum::getType).toArray(Integer[]::new); @Override public Integer[] array() { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java index ead8559dd7..24eaf3a133 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java @@ -6,6 +6,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.IotAlertConfigPageR import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.IotAlertConfigSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; import cn.iocoder.yudao.module.iot.dal.mysql.alert.IotAlertConfigMapper; +import cn.iocoder.yudao.module.iot.service.rule.scene.IotRuleSceneService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -25,8 +27,18 @@ public class IotAlertConfigServiceImpl implements IotAlertConfigService { @Resource private IotAlertConfigMapper alertConfigMapper; + @Resource + private IotRuleSceneService ruleSceneService; + + @Resource + private AdminUserApi adminUserApi; + @Override public Long createAlertConfig(IotAlertConfigSaveReqVO createReqVO) { + // 校验关联数据是否存在 + ruleSceneService.validateRuleSceneList(createReqVO.getSceneRuleIds()); + adminUserApi.validateUserList(createReqVO.getReceiveUserIds()); + IotAlertConfigDO alertConfig = BeanUtils.toBean(createReqVO, IotAlertConfigDO.class); alertConfigMapper.insert(alertConfig); return alertConfig.getId(); @@ -36,6 +48,10 @@ public class IotAlertConfigServiceImpl implements IotAlertConfigService { public void updateAlertConfig(IotAlertConfigSaveReqVO updateReqVO) { // 校验存在 validateAlertConfigExists(updateReqVO.getId()); + // 校验关联数据是否存在 + ruleSceneService.validateRuleSceneList(updateReqVO.getSceneRuleIds()); + adminUserApi.validateUserList(updateReqVO.getReceiveUserIds()); + // 更新 IotAlertConfigDO updateObj = BeanUtils.toBean(updateReqVO, IotAlertConfigDO.class); alertConfigMapper.updateById(updateObj); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneService.java index 0bf43d33b5..d42b214fe8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneService.java @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; import jakarta.validation.Valid; +import java.util.Collection; import java.util.List; /** @@ -55,6 +56,22 @@ public interface IotRuleSceneService { */ PageResult getRuleScenePage(IotRuleScenePageReqVO pageReqVO); + /** + * 校验规则场景编号们是否存在。如下情况,视为无效: + * 1. 规则场景编号不存在 + * + * @param ids 规则场景编号数组 + */ + void validateRuleSceneList(Collection ids); + + /** + * 获得指定状态的场景联动列表 + * + * @param status 状态 + * @return 场景联动列表 + */ + List getRuleSceneListByStatus(Integer status); + /** * 【缓存】获得指定设备的场景列表 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java index fc77180fde..94a38c3bb3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java @@ -42,9 +42,12 @@ import org.springframework.validation.annotation.Validated; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Collection; +import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.RULE_SCENE_NOT_EXISTS; @@ -109,6 +112,22 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { return ruleSceneMapper.selectPage(pageReqVO); } + @Override + public void validateRuleSceneList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return; + } + // 批量查询存在的规则场景 + List existingScenes = ruleSceneMapper.selectByIds(ids); + if (existingScenes.size() != ids.size()) { + throw exception(RULE_SCENE_NOT_EXISTS); + } + } + + @Override + public List getRuleSceneListByStatus(Integer status) { + return ruleSceneMapper.selectListByStatus(status); + } // TODO 芋艿,缓存待实现 @Override From 779cde24ecbd3a8f23ed9f46953e028c175a5867 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 28 Jun 2025 10:28:57 +0800 Subject: [PATCH 12/33] =?UTF-8?q?reactor=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E8=B0=83=E6=95=B4=E4=B8=8B=20IotSce?= =?UTF-8?q?neRuleAction=20=E7=AD=89=E7=B1=BB=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/alert/IotAlertConfigController.java | 6 +++--- .../vo/{ => config}/IotAlertConfigPageReqVO.java | 2 +- .../vo/{ => config}/IotAlertConfigRespVO.java | 2 +- .../vo/{ => config}/IotAlertConfigSaveReqVO.java | 2 +- .../iot/dal/dataobject/alert/IotAlertRecordDO.java | 14 +++++--------- .../iot/dal/mysql/alert/IotAlertConfigMapper.java | 2 +- .../iot/enums/rule/IotRuleSceneActionTypeEnum.java | 8 +++----- .../iot/service/alert/IotAlertConfigService.java | 4 ++-- .../service/alert/IotAlertConfigServiceImpl.java | 4 ++-- .../rule/scene/IotRuleSceneServiceImpl.java | 10 ++++------ ...on.java => IotAlertTriggerRuleSceneAction.java} | 8 ++++---- ...n.java => IotDeviceControlRuleSceneAction.java} | 4 ++-- ...uleSceneAction.java => IotSceneRuleAction.java} | 8 +++----- 13 files changed, 32 insertions(+), 42 deletions(-) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/{ => config}/IotAlertConfigPageReqVO.java (91%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/{ => config}/IotAlertConfigRespVO.java (95%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/{ => config}/IotAlertConfigSaveReqVO.java (96%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/{IotRuleSceneAlertAction.java => IotAlertTriggerRuleSceneAction.java} (73%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/{IotRuleSceneDeviceControlAction.java => IotDeviceControlRuleSceneAction.java} (94%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/{IotRuleSceneAction.java => IotSceneRuleAction.java} (77%) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertConfigController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertConfigController.java index d650fa9d7d..c7980b943c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertConfigController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertConfigController.java @@ -3,9 +3,9 @@ package cn.iocoder.yudao.module.iot.controller.admin.alert; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.IotAlertConfigPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.IotAlertConfigRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.IotAlertConfigSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConfigPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConfigRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConfigSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; import cn.iocoder.yudao.module.iot.service.alert.IotAlertConfigService; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigPageReqVO.java similarity index 91% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigPageReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigPageReqVO.java index 2a6ecdf7c6..0f9a1e9ce1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigPageReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.alert.vo; +package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config; import cn.iocoder.yudao.framework.common.pojo.PageParam; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigRespVO.java similarity index 95% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigRespVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigRespVO.java index d1e13b74a6..e68a7b7851 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigRespVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.alert.vo; +package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigSaveReqVO.java similarity index 96% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigSaveReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigSaveReqVO.java index 231bd4717a..694e8bfdf7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/IotAlertConfigSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/config/IotAlertConfigSaveReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.alert.vo; +package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.validation.InEnum; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertRecordDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertRecordDO.java index 7b5202d244..b5865b3b51 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertRecordDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertRecordDO.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import lombok.AllArgsConstructor; @@ -29,12 +30,12 @@ public class IotAlertRecordDO extends BaseDO { /** * 记录编号 */ - @TableField + @TableId private Long id; /** * 告警名称 * - * 冗余 {@link IotAlertConfigDO#getName()} + * 冗余 {@link IotAlertConfigDO#getId()} */ private Long configId; /** @@ -42,7 +43,7 @@ public class IotAlertRecordDO extends BaseDO { * * 冗余 {@link IotAlertConfigDO#getName()} */ - private String name; + private String configName; /** * 产品编号 @@ -56,8 +57,6 @@ public class IotAlertRecordDO extends BaseDO { * 关联 {@link IotDeviceDO#getId()} */ private String deviceId; - - // TODO @芋艿:有没更好的方式 /** * 触发的设备消息 */ @@ -65,10 +64,7 @@ public class IotAlertRecordDO extends BaseDO { private IotDeviceMessage deviceMessage; /** - * 处理状态 - * - * true - 已处理 - * false - 未处理 + * 是否处理 */ private Boolean processStatus; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertConfigMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertConfigMapper.java index 6871763211..d7dbac7560 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertConfigMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertConfigMapper.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.dal.mysql.alert; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.IotAlertConfigPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConfigPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; import org.apache.ibatis.annotations.Mapper; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java index 5251852312..323592b26b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.enums.rule; import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -15,17 +16,16 @@ import java.util.Arrays; @Getter public enum IotRuleSceneActionTypeEnum implements ArrayValuable { - // TODO @芋艿:后续“对应”部分,要 @下,等包结构梳理完; /** * 设备属性设置 * - * 对应 IotDeviceMessageMethodEnum.DEVICE_PROPERTY_SET + * 对应 {@link IotDeviceMessageMethodEnum#PROPERTY_SET} */ DEVICE_PROPERTY_SET(1), /** * 设备服务调用 * - * 对应 IotDeviceMessageMethodEnum.DEVICE_SERVICE_INVOKE + * 对应 {@link IotDeviceMessageMethodEnum#SERVICE_INVOKE} */ DEVICE_SERVICE_INVOKE(2), @@ -38,8 +38,6 @@ public enum IotRuleSceneActionTypeEnum implements ArrayValuable { */ ALERT_RECOVER(101), - @Deprecated - ALERT(2), // 告警执行 ; private final Integer type; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigService.java index cf539f6a88..222bf57bb2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigService.java @@ -1,8 +1,8 @@ package cn.iocoder.yudao.module.iot.service.alert; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.IotAlertConfigPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.IotAlertConfigSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConfigPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConfigSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; import jakarta.validation.Valid; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java index 24eaf3a133..0792ba539d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java @@ -2,8 +2,8 @@ package cn.iocoder.yudao.module.iot.service.alert; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.IotAlertConfigPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.IotAlertConfigSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConfigPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConfigSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; import cn.iocoder.yudao.module.iot.dal.mysql.alert.IotAlertConfigMapper; import cn.iocoder.yudao.module.iot.service.rule.scene.IotRuleSceneService; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java index 94a38c3bb3..2d6d8530d3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java @@ -27,7 +27,7 @@ import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionOperatorEnum; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager; import cn.iocoder.yudao.module.iot.job.rule.IotRuleSceneJob; -import cn.iocoder.yudao.module.iot.service.rule.scene.action.IotRuleSceneAction; +import cn.iocoder.yudao.module.iot.service.rule.scene.action.IotSceneRuleAction; import jakarta.annotation.Resource; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -39,15 +39,13 @@ import org.quartz.impl.StdSchedulerFactory; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Collection; -import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.RULE_SCENE_NOT_EXISTS; @@ -65,7 +63,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { private IotRuleSceneMapper ruleSceneMapper; @Resource - private List ruleSceneActions; + private List ruleSceneActions; @Resource(name = "iotSchedulerManager") private IotSchedulerManager schedulerManager; @@ -437,7 +435,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { // 2. 遍历规则场景的动作 ruleScene.getActions().forEach(actionConfig -> { // 3.1 获取对应的动作 Action 数组 - List actions = filterList(ruleSceneActions, + List actions = filterList(ruleSceneActions, action -> action.getType().getType().equals(actionConfig.getType())); if (CollUtil.isEmpty(actions)) { return; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotRuleSceneAlertAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerRuleSceneAction.java similarity index 73% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotRuleSceneAlertAction.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerRuleSceneAction.java index fd55cb8dd7..e2dbd1aa28 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotRuleSceneAlertAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerRuleSceneAction.java @@ -8,21 +8,21 @@ import org.springframework.stereotype.Component; import javax.annotation.Nullable; /** - * IoT 告警的 {@link IotRuleSceneAction} 实现类 + * IoT 告警触发的 {@link IotSceneRuleAction} 实现类 * * @author 芋道源码 */ @Component -public class IotRuleSceneAlertAction implements IotRuleSceneAction { +public class IotAlertTriggerRuleSceneAction implements IotSceneRuleAction { @Override public void execute(@Nullable IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) { - // TODO @芋艿:待实现 + // TODO @AI: } @Override public IotRuleSceneActionTypeEnum getType() { - return IotRuleSceneActionTypeEnum.ALERT; + return IotRuleSceneActionTypeEnum.ALERT_TRIGGER; } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotRuleSceneDeviceControlAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlRuleSceneAction.java similarity index 94% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotRuleSceneDeviceControlAction.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlRuleSceneAction.java index e7977e7d36..4e3138fe78 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotRuleSceneDeviceControlAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlRuleSceneAction.java @@ -12,13 +12,13 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; /** - * IoT 设备控制的 {@link IotRuleSceneAction} 实现类 + * IoT 设备控制的 {@link IotSceneRuleAction} 实现类 * * @author 芋道源码 */ @Component @Slf4j -public class IotRuleSceneDeviceControlAction implements IotRuleSceneAction { +public class IotDeviceControlRuleSceneAction implements IotSceneRuleAction { @Resource private IotDeviceService deviceService; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotRuleSceneAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotSceneRuleAction.java similarity index 77% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotRuleSceneAction.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotSceneRuleAction.java index 3d24384f66..855d9ecedd 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotRuleSceneAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotSceneRuleAction.java @@ -7,16 +7,14 @@ import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; import javax.annotation.Nullable; /** - * IoT 规则场景的场景执行器接口 + * IoT 场景联动的执行器接口 * * @author 芋道源码 */ -public interface IotRuleSceneAction { - - // TODO @芋艿:groovy 或者 javascript 实现数据的转换;可以考虑基于 hutool 的 ScriptUtil 做 +public interface IotSceneRuleAction { /** - * 执行场景 + * 执行场景联动 * * @param message 消息,允许空 * 1. 空的情况:定时触发 From db03c6d7a84ee9535a802ad087498442fac4c951 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 28 Jun 2025 16:46:39 +0800 Subject: [PATCH 13/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E6=96=B0=E5=A2=9E=E5=91=8A=E8=AD=A6?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD=EF=BC=8C?= =?UTF-8?q?=E5=8C=85=E6=8B=AC=E5=91=8A=E8=AD=A6=E8=AE=B0=E5=BD=95=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=92=8C=E5=89=8D=E7=AB=AF=E5=B1=95=E7=A4=BA=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/YudaoMybatisAutoConfiguration.java | 11 +++ .../admin/alert/IotAlertConfigController.java | 26 +++++- .../admin/alert/IotAlertRecordController.java | 56 +++++++++++++ .../vo/recrod/IotAlertRecordPageReqVO.java | 35 ++++++++ .../vo/recrod/IotAlertRecordProcessReqVO.java | 18 +++++ .../alert/vo/recrod/IotAlertRecordRespVO.java | 43 ++++++++++ .../dataobject/alert/IotAlertRecordDO.java | 11 ++- .../dal/dataobject/rule/IotRuleSceneDO.java | 8 -- .../dal/mysql/alert/IotAlertConfigMapper.java | 13 +++ .../dal/mysql/alert/IotAlertRecordMapper.java | 29 +++++++ .../module/iot/enums/ErrorCodeConstants.java | 3 + .../rule/IotDataRuleMessageHandler.java | 2 - .../service/alert/IotAlertConfigService.java | 18 +++++ .../alert/IotAlertConfigServiceImpl.java | 15 ++++ .../service/alert/IotAlertRecordService.java | 49 ++++++++++++ .../alert/IotAlertRecordServiceImpl.java | 80 +++++++++++++++++++ .../rule/scene/IotRuleSceneService.java | 10 +-- .../rule/scene/IotRuleSceneServiceImpl.java | 2 +- .../IotAlertTriggerRuleSceneAction.java | 28 ------- .../IotAlertTriggerSceneRuleAction.java | 49 ++++++++++++ .../IotDeviceControlRuleSceneAction.java | 11 +-- .../rule/scene/action/IotSceneRuleAction.java | 7 +- 22 files changed, 467 insertions(+), 57 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertRecordController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordPageReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordProcessReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertRecordMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordServiceImpl.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerRuleSceneAction.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java index ab2992184f..34829b8f72 100644 --- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/config/YudaoMybatisAutoConfiguration.java @@ -1,16 +1,19 @@ package cn.iocoder.yudao.framework.mybatis.config; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.mybatis.core.handler.DefaultDBFieldHandler; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import com.baomidou.mybatisplus.extension.incrementer.*; import com.baomidou.mybatisplus.extension.parser.JsqlParserGlobal; import com.baomidou.mybatisplus.extension.parser.cache.JdkSerialCaffeineJsqlParseCache; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.ibatis.annotations.Mapper; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.autoconfigure.AutoConfiguration; @@ -18,6 +21,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.core.env.ConfigurableEnvironment; +import java.util.List; import java.util.concurrent.TimeUnit; /** @@ -73,4 +77,11 @@ public class YudaoMybatisAutoConfiguration { throw new IllegalArgumentException(StrUtil.format("DbType{} 找不到合适的 IKeyGenerator 实现类", dbType)); } + @Bean + public JacksonTypeHandler jacksonTypeHandler(List objectMappers) { + // 特殊:设置 JacksonTypeHandler 的 ObjectMapper! + JacksonTypeHandler.setObjectMapper(CollUtil.getFirst(objectMappers)); + return new JacksonTypeHandler(Object.class); + } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertConfigController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertConfigController.java index c7980b943c..b6d225f6df 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertConfigController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertConfigController.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.alert; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -15,15 +16,18 @@ import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; + import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap; @Tag(name = "管理后台 - IoT 告警配置") @@ -34,7 +38,7 @@ public class IotAlertConfigController { @Resource private IotAlertConfigService alertConfigService; - + @Resource private AdminUserApi adminUserApi; @@ -76,12 +80,26 @@ public class IotAlertConfigController { @PreAuthorize("@ss.hasPermission('iot:alert-config:query')") public CommonResult> getAlertConfigPage(@Valid IotAlertConfigPageReqVO pageReqVO) { PageResult pageResult = alertConfigService.getAlertConfigPage(pageReqVO); + // 转换返回 Map userMap = adminUserApi.getUserMap( convertSetByFlatMap(pageResult.getList(), config -> config.getReceiveUserIds().stream())); - return success(BeanUtils.toBean(pageResult, IotAlertConfigRespVO.class, vo -> - vo.setReceiveUserNames(vo.getReceiveUserIds().stream().map(userMap::get) - .filter(Objects::nonNull).map(AdminUserRespDTO::getNickname).collect(Collectors.toList())))); + return success(BeanUtils.toBean(pageResult, IotAlertConfigRespVO.class, vo -> { + vo.setReceiveUserNames(vo.getReceiveUserIds().stream() + .map(userMap::get) + .filter(Objects::nonNull) + .map(AdminUserRespDTO::getNickname) + .collect(Collectors.toList())); + })); + } + + @GetMapping("/simple-list") + @Operation(summary = "获得告警配置简单列表", description = "只包含被开启的告警配置,主要用于前端的下拉选项") + @PreAuthorize("@ss.hasPermission('iot:alert-config:query')") + public CommonResult> getAlertConfigSimpleList() { + List list = alertConfigService.getAlertConfigListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(convertList(list, config -> // 只返回 id、name 字段 + new IotAlertConfigRespVO().setId(config.getId()).setName(config.getName()))); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertRecordController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertRecordController.java new file mode 100644 index 0000000000..d75f42e3f4 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertRecordController.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.iot.controller.admin.alert; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordProcessReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordRespVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO; +import cn.iocoder.yudao.module.iot.service.alert.IotAlertRecordService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - IoT 告警记录") +@RestController +@RequestMapping("/iot/alert-record") +@Validated +public class IotAlertRecordController { + + @Resource + private IotAlertRecordService alertRecordService; + + @GetMapping("/get") + @Operation(summary = "获得告警记录") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:alert-record:query')") + public CommonResult getAlertRecord(@RequestParam("id") Long id) { + IotAlertRecordDO alertRecord = alertRecordService.getAlertRecord(id); + return success(BeanUtils.toBean(alertRecord, IotAlertRecordRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得告警记录分页") + @PreAuthorize("@ss.hasPermission('iot:alert-record:query')") + public CommonResult> getAlertRecordPage(@Valid IotAlertRecordPageReqVO pageReqVO) { + PageResult pageResult = alertRecordService.getAlertRecordPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotAlertRecordRespVO.class)); + } + + @PutMapping("/process") + @Operation(summary = "处理告警记录") + @PreAuthorize("@ss.hasPermission('iot:alert-record:process')") + public CommonResult processAlertRecord(@Valid @RequestBody IotAlertRecordProcessReqVO processReqVO) { + alertRecordService.processAlertRecord(processReqVO); + return success(true); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordPageReqVO.java new file mode 100644 index 0000000000..109f240917 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordPageReqVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - IoT 告警记录分页 Request VO") +@Data +public class IotAlertRecordPageReqVO extends PageParam { + + @Schema(description = "告警配置编号", example = "29320") + private Long configId; + + @Schema(description = "告警级别", example = "1") + private Integer level; + + @Schema(description = "产品编号", example = "2050") + private Long productId; + + @Schema(description = "设备编号", example = "21727") + private String deviceId; + + @Schema(description = "是否处理", example = "true") + private Boolean processStatus; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordProcessReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordProcessReqVO.java new file mode 100644 index 0000000000..b64f66c5b9 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordProcessReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(description = "管理后台 - IoT 告警记录处理 Request VO") +@Data +public class IotAlertRecordProcessReqVO { + + @Schema(description = "记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "记录编号不能为空") + private Long id; + + @Schema(description = "处理结果(备注)", requiredMode = Schema.RequiredMode.REQUIRED, example = "已处理告警,问题已解决") + private String processRemark; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordRespVO.java new file mode 100644 index 0000000000..97ccf6cca4 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/vo/recrod/IotAlertRecordRespVO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod; + +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - IoT 告警记录 Response VO") +@Data +public class IotAlertRecordRespVO { + + @Schema(description = "记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "19904") + private Long id; + + @Schema(description = "告警配置编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "29320") + private Long configId; + + @Schema(description = "告警名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") + private String configName; + + @Schema(description = "告警级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer configLevel; + + @Schema(description = "产品编号", example = "2050") + private Long productId; + + @Schema(description = "设备编号", example = "21727") + private Long deviceId; + + @Schema(description = "触发的设备消息") + private IotDeviceMessage deviceMessage; + + @Schema(description = "是否处理", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Boolean processStatus; + + @Schema(description = "处理结果(备注)", example = "你说的对") + private String processRemark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertRecordDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertRecordDO.java index b5865b3b51..c057f85ccf 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertRecordDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertRecordDO.java @@ -19,7 +19,7 @@ import lombok.NoArgsConstructor; * * @author 芋道源码 */ -@TableName("iot_alert_record") +@TableName(value = "iot_alert_record", autoResultMap = true) @KeySequence("iot_alert_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Builder @@ -44,6 +44,13 @@ public class IotAlertRecordDO extends BaseDO { * 冗余 {@link IotAlertConfigDO#getName()} */ private String configName; + /** + * 告警级别 + * + * 冗余 {@link IotAlertConfigDO#getLevel()} + * 字典 {@link cn.iocoder.yudao.module.iot.enums.DictTypeConstants#ALERT_LEVEL} + */ + private Integer configLevel; /** * 产品编号 @@ -56,7 +63,7 @@ public class IotAlertRecordDO extends BaseDO { * * 关联 {@link IotDeviceDO#getId()} */ - private String deviceId; + private Long deviceId; /** * 触发的设备消息 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java index 9d25d66c7b..695705c389 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotRuleSceneDO.java @@ -198,14 +198,6 @@ public class IotRuleSceneDO extends TenantBaseDO { */ private ActionDeviceControl deviceControl; - /** - * 数据桥接编号 - * - * 必填:当 {@link #type} 为 {@link IotRuleSceneActionTypeEnum#DATA_BRIDGE} 时 - * 关联:{@link IotDataSinkDO#getId()} - */ - private Long dataBridgeId; - } /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertConfigMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertConfigMapper.java index d7dbac7560..c5d7154ff6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertConfigMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertConfigMapper.java @@ -3,10 +3,13 @@ package cn.iocoder.yudao.module.iot.dal.mysql.alert; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConfigPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + /** * IoT 告警配置 Mapper * @@ -23,4 +26,14 @@ public interface IotAlertConfigMapper extends BaseMapperX { .orderByDesc(IotAlertConfigDO::getId)); } + default List selectListByStatus(Integer status) { + return selectList(IotAlertConfigDO::getStatus, status); + } + + default List selectListBySceneRuleIdAndStatus(Long sceneRuleId, Integer status) { + return selectList(new LambdaQueryWrapperX() + .eq(IotAlertConfigDO::getStatus, status) + .apply(MyBatisUtils.findInSet("scene_rule_id", sceneRuleId))); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertRecordMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertRecordMapper.java new file mode 100644 index 0000000000..3d29c5ff81 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertRecordMapper.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.alert; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * IoT 告警记录 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface IotAlertRecordMapper extends BaseMapperX { + + default PageResult selectPage(IotAlertRecordPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(IotAlertRecordDO::getConfigId, reqVO.getConfigId()) + .eqIfPresent(IotAlertRecordDO::getConfigLevel, reqVO.getLevel()) + .eqIfPresent(IotAlertRecordDO::getProductId, reqVO.getProductId()) + .eqIfPresent(IotAlertRecordDO::getDeviceId, reqVO.getDeviceId()) + .eqIfPresent(IotAlertRecordDO::getProcessStatus, reqVO.getProcessStatus()) + .betweenIfPresent(IotAlertRecordDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(IotAlertRecordDO::getId)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index d186cd2f86..47694cfeeb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -67,4 +67,7 @@ public interface ErrorCodeConstants { // ========== IoT 告警配置 1-050-013-000 ========== ErrorCode ALERT_CONFIG_NOT_EXISTS = new ErrorCode(1_050_013_000, "IoT 告警配置不存在"); + // ========== IoT 告警记录 1-050-014-000 ========== + ErrorCode ALERT_RECORD_NOT_EXISTS = new ErrorCode(1_050_014_000, "IoT 告警记录不存在"); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotDataRuleMessageHandler.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotDataRuleMessageHandler.java index c2b82262c7..843592a272 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotDataRuleMessageHandler.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotDataRuleMessageHandler.java @@ -10,8 +10,6 @@ import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; -// TODO @puhui999:后面重构哈 - /** * 针对 {@link IotDeviceMessage} 的消费者,处理数据流转 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigService.java index 222bf57bb2..d58d42789c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigService.java @@ -6,6 +6,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConf import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; import jakarta.validation.Valid; +import java.util.List; + /** * IoT 告警配置 Service 接口 * @@ -51,4 +53,20 @@ public interface IotAlertConfigService { */ PageResult getAlertConfigPage(IotAlertConfigPageReqVO pageReqVO); + /** + * 获得告警配置列表 + * + * @param status 状态 + * @return 告警配置列表 + */ + List getAlertConfigListByStatus(Integer status); + + /** + * 获得告警配置列表 + * + * @param sceneRuleId 场景流动规则编号 + * @return 告警配置列表 + */ + List getAlertConfigListBySceneRuleIdAndStatus(Long sceneRuleId, Integer status); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java index 0792ba539d..e03af2fbb8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java @@ -9,9 +9,12 @@ import cn.iocoder.yudao.module.iot.dal.mysql.alert.IotAlertConfigMapper; import cn.iocoder.yudao.module.iot.service.rule.scene.IotRuleSceneService; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import jakarta.annotation.Resource; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.List; + import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.ALERT_CONFIG_NOT_EXISTS; @@ -28,6 +31,7 @@ public class IotAlertConfigServiceImpl implements IotAlertConfigService { private IotAlertConfigMapper alertConfigMapper; @Resource + @Lazy // 延迟,避免循环依赖报错 private IotRuleSceneService ruleSceneService; @Resource @@ -39,6 +43,7 @@ public class IotAlertConfigServiceImpl implements IotAlertConfigService { ruleSceneService.validateRuleSceneList(createReqVO.getSceneRuleIds()); adminUserApi.validateUserList(createReqVO.getReceiveUserIds()); + // 插入 IotAlertConfigDO alertConfig = BeanUtils.toBean(createReqVO, IotAlertConfigDO.class); alertConfigMapper.insert(alertConfig); return alertConfig.getId(); @@ -81,4 +86,14 @@ public class IotAlertConfigServiceImpl implements IotAlertConfigService { return alertConfigMapper.selectPage(pageReqVO); } + @Override + public List getAlertConfigListByStatus(Integer status) { + return alertConfigMapper.selectListByStatus(status); + } + + @Override + public List getAlertConfigListBySceneRuleIdAndStatus(Long sceneRuleId, Integer status) { + return alertConfigMapper.selectListBySceneRuleIdAndStatus(sceneRuleId, status); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordService.java new file mode 100644 index 0000000000..57ad9a3762 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordService.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.iot.service.alert; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordProcessReqVO; +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO; + +/** + * IoT 告警记录 Service 接口 + * + * @author 芋道源码 + */ +public interface IotAlertRecordService { + + /** + * 获得告警记录 + * + * @param id 编号 + * @return 告警记录 + */ + IotAlertRecordDO getAlertRecord(Long id); + + /** + * 获得告警记录分页 + * + * @param pageReqVO 分页查询 + * @return 告警记录分页 + */ + PageResult getAlertRecordPage(IotAlertRecordPageReqVO pageReqVO); + + /** + * 处理告警记录 + * + * @param processReqVO 处理请求 + */ + void processAlertRecord(IotAlertRecordProcessReqVO processReqVO); + + /** + * 创建告警记录 + * + * @param config 告警配置 + * @param deviceMessage 设备消息,可为空 + * @return 告警记录编号 + */ + Long createAlertRecord(IotAlertConfigDO config, IotDeviceMessage deviceMessage); + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordServiceImpl.java new file mode 100644 index 0000000000..72b13d2546 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordServiceImpl.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.iot.service.alert; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordProcessReqVO; +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.mysql.alert.IotAlertRecordMapper; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.ALERT_RECORD_NOT_EXISTS; + +/** + * IoT 告警记录 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class IotAlertRecordServiceImpl implements IotAlertRecordService { + + @Resource + private IotAlertRecordMapper alertRecordMapper; + + @Resource + private IotDeviceService deviceService; + + @Override + public IotAlertRecordDO getAlertRecord(Long id) { + return alertRecordMapper.selectById(id); + } + + @Override + public PageResult getAlertRecordPage(IotAlertRecordPageReqVO pageReqVO) { + return alertRecordMapper.selectPage(pageReqVO); + } + + @Override + public void processAlertRecord(IotAlertRecordProcessReqVO processReqVO) { + // 校验告警记录是否存在 + IotAlertRecordDO alertRecord = alertRecordMapper.selectById(processReqVO.getId()); + if (alertRecord == null) { + throw exception(ALERT_RECORD_NOT_EXISTS); + } + + // 更新处理状态和备注 + alertRecordMapper.updateById(IotAlertRecordDO.builder() + .id(processReqVO.getId()) + .processStatus(true) + .processRemark(processReqVO.getProcessRemark()) + .build()); + } + + @Override + public Long createAlertRecord(IotAlertConfigDO config, IotDeviceMessage message) { + // 构建告警记录 + IotAlertRecordDO.IotAlertRecordDOBuilder builder = IotAlertRecordDO.builder() + .configId(config.getId()).configName(config.getName()).configLevel(config.getLevel()) + .processStatus(false); + if (message != null) { + builder.deviceMessage(message); + // 填充设备信息 + IotDeviceDO device = deviceService.getDeviceFromCache(message.getDeviceId()); + if (device!= null) { + builder.productId(device.getProductId()).deviceId(device.getId()); + } + } + // 插入记录 + IotAlertRecordDO record = builder.build(); + alertRecordMapper.insert(record); + return record.getId(); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneService.java index d42b214fe8..86a2663edc 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneService.java @@ -12,7 +12,7 @@ import java.util.Collection; import java.util.List; /** - * IoT 规则场景 Service 接口 + * IoT 规则场景规则 Service 接口 * * @author 芋道源码 */ @@ -57,10 +57,10 @@ public interface IotRuleSceneService { PageResult getRuleScenePage(IotRuleScenePageReqVO pageReqVO); /** - * 校验规则场景编号们是否存在。如下情况,视为无效: - * 1. 规则场景编号不存在 + * 校验规则场景联动规则编号们是否存在。如下情况,视为无效: + * 1. 规则场景联动规则编号不存在 * - * @param ids 规则场景编号数组 + * @param ids 场景联动规则编号数组 */ void validateRuleSceneList(Collection ids); @@ -91,7 +91,7 @@ public interface IotRuleSceneService { /** * 基于 {@link IotRuleSceneTriggerTypeEnum#TIMER} 场景,执行规则场景 * - * @param id 场景编号 + * @param id 场景联动规则编号 */ void executeRuleSceneByTimer(Long id); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java index 2d6d8530d3..9bfa929b25 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java @@ -443,7 +443,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { // 3.2 执行动作 actions.forEach(action -> { try { - action.execute(message, actionConfig); + action.execute(message, ruleScene, actionConfig); log.info("[executeRuleSceneAction][消息({}) 规则场景编号({}) 的执行动作({}) 成功]", message, ruleScene.getId(), actionConfig); } catch (Exception e) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerRuleSceneAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerRuleSceneAction.java deleted file mode 100644 index e2dbd1aa28..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerRuleSceneAction.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.rule.scene.action; - -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; -import org.springframework.stereotype.Component; - -import javax.annotation.Nullable; - -/** - * IoT 告警触发的 {@link IotSceneRuleAction} 实现类 - * - * @author 芋道源码 - */ -@Component -public class IotAlertTriggerRuleSceneAction implements IotSceneRuleAction { - - @Override - public void execute(@Nullable IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) { - // TODO @AI: - } - - @Override - public IotRuleSceneActionTypeEnum getType() { - return IotRuleSceneActionTypeEnum.ALERT_TRIGGER; - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java new file mode 100644 index 0000000000..8ac33fcefc --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.iot.service.rule.scene.action; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; +import cn.iocoder.yudao.module.iot.service.alert.IotAlertConfigService; +import cn.iocoder.yudao.module.iot.service.alert.IotAlertRecordService; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Component; + +import javax.annotation.Nullable; +import java.util.List; + +// TODO @puhui999、@芋艿:未测试;需要场景联动开发完 +/** + * IoT 告警触发的 {@link IotSceneRuleAction} 实现类 + * + * @author 芋道源码 + */ +@Component +public class IotAlertTriggerSceneRuleAction implements IotSceneRuleAction { + + @Resource + private IotAlertConfigService alertConfigService; + + @Resource + private IotAlertRecordService alertRecordService; + + @Override + public void execute(@Nullable IotDeviceMessage message, + IotRuleSceneDO rule, IotRuleSceneDO.ActionConfig actionConfig) throws Exception { + List alertConfigs = alertConfigService.getAlertConfigListBySceneRuleIdAndStatus( + rule.getId(), CommonStatusEnum.ENABLE.getStatus()); + if (CollUtil.isEmpty(alertConfigs)) { + return; + } + alertConfigs.forEach(alertConfig -> + alertRecordService.createAlertRecord(alertConfig, message)); + } + + @Override + public IotRuleSceneActionTypeEnum getType() { + return IotRuleSceneActionTypeEnum.ALERT_TRIGGER; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlRuleSceneAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlRuleSceneAction.java index 4e3138fe78..c812b4ed57 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlRuleSceneAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlRuleSceneAction.java @@ -26,23 +26,24 @@ public class IotDeviceControlRuleSceneAction implements IotSceneRuleAction { private IotDeviceMessageService deviceMessageService; @Override - public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) { - IotRuleSceneDO.ActionDeviceControl control = config.getDeviceControl(); + public void execute(IotDeviceMessage message, + IotRuleSceneDO rule, IotRuleSceneDO.ActionConfig actionConfig) { + IotRuleSceneDO.ActionDeviceControl control = actionConfig.getDeviceControl(); Assert.notNull(control, "设备控制配置不能为空"); // 遍历每个设备,下发消息 control.getDeviceNames().forEach(deviceName -> { IotDeviceDO device = deviceService.getDeviceFromCache(control.getProductKey(), deviceName); if (device == null) { - log.error("[execute][message({}) config({}) 对应的设备不存在]", message, config); + log.error("[execute][message({}) actionConfig({}) 对应的设备不存在]", message, actionConfig); return; } try { // TODO @芋艿:@puhui999:这块可能要改,从 type => method IotDeviceMessage downstreamMessage = deviceMessageService.sendDeviceMessage(IotDeviceMessage.requestOf( control.getType() + control.getIdentifier(), control.getData()).setDeviceId(device.getId())); - log.info("[execute][message({}) config({}) 下发消息({})成功]", message, config, downstreamMessage); + log.info("[execute][message({}) actionConfig({}) 下发消息({})成功]", message, actionConfig, downstreamMessage); } catch (Exception e) { - log.error("[execute][message({}) config({}) 下发消息失败]", message, config, e); + log.error("[execute][message({}) actionConfig({}) 下发消息失败]", message, actionConfig, e); } }); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotSceneRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotSceneRuleAction.java index 855d9ecedd..b52d5c71e3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotSceneRuleAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotSceneRuleAction.java @@ -19,9 +19,12 @@ public interface IotSceneRuleAction { * @param message 消息,允许空 * 1. 空的情况:定时触发 * 2. 非空的情况:设备触发 - * @param config 配置 + * @param rule 规则 + * @param actionConfig 执行配置(实际对应规则里的哪条执行配置) */ - void execute(@Nullable IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) throws Exception; + void execute(@Nullable IotDeviceMessage message, + IotRuleSceneDO rule, + IotRuleSceneDO.ActionConfig actionConfig) throws Exception; /** * 获得类型 From 53c7ce2220848a5b34f9803f3377eb86ef1fa8b1 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 28 Jun 2025 19:37:00 +0800 Subject: [PATCH 14/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E6=96=B0=E5=A2=9E=E5=91=8A=E8=AD=A6?= =?UTF-8?q?=E6=81=A2=E5=A4=8D=E5=9C=BA=E6=99=AF=E8=A7=84=E5=88=99=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E7=B1=BB=20IotAlertRecoverSceneRuleAction?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IotAlertRecoverSceneRuleAction.java | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertRecoverSceneRuleAction.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertRecoverSceneRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertRecoverSceneRuleAction.java new file mode 100644 index 0000000000..f4bb853244 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertRecoverSceneRuleAction.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.iot.service.rule.scene.action; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; +import cn.iocoder.yudao.module.iot.service.alert.IotAlertConfigService; +import cn.iocoder.yudao.module.iot.service.alert.IotAlertRecordService; +import cn.iocoder.yudao.module.system.api.mail.MailSendApi; +import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; +import cn.iocoder.yudao.module.system.api.sms.SmsSendApi; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Component; + +import javax.annotation.Nullable; +import java.util.List; + +// TODO @puhui999、@芋艿:未测试;需要场景联动开发完 +/** + * IoT 告警触发的 {@link IotSceneRuleAction} 实现类 + * + * @author 芋道源码 + */ +@Component +public class IotAlertTriggerSceneRuleAction implements IotSceneRuleAction { + + @Resource + private IotAlertConfigService alertConfigService; + @Resource + private IotAlertRecordService alertRecordService; + + @Resource + private SmsSendApi smsSendApi; + @Resource + private MailSendApi mailSendApi; + @Resource + private NotifyMessageSendApi notifyMessageSendApi; + + @Override + public void execute(@Nullable IotDeviceMessage message, + IotRuleSceneDO rule, IotRuleSceneDO.ActionConfig actionConfig) throws Exception { + List alertConfigs = alertConfigService.getAlertConfigListBySceneRuleIdAndStatus( + rule.getId(), CommonStatusEnum.ENABLE.getStatus()); + if (CollUtil.isEmpty(alertConfigs)) { + return; + } + alertConfigs.forEach(alertConfig -> { + // 记录告警记录 + alertRecordService.createAlertRecord(alertConfig, message); + // 发送告警消息 + sendAlertMessage(alertConfig, message); + }); + } + + private void sendAlertMessage(IotAlertConfigDO config, IotDeviceMessage deviceMessage) { + // TODO @芋艿:等场景联动开发完,再实现 + // TODO @芋艿:短信 + // TODO @芋艿:邮箱 + // TODO @芋艿:站内信 + } + + @Override + public IotRuleSceneActionTypeEnum getType() { + return IotRuleSceneActionTypeEnum.ALERT_TRIGGER; + } + +} From 97260b8efeedc2a8e51c534f3517463e92403e1a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 28 Jun 2025 19:37:28 +0800 Subject: [PATCH 15/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E6=96=B0=E5=A2=9E=E5=91=8A=E8=AD=A6?= =?UTF-8?q?=E6=81=A2=E5=A4=8D=E5=9C=BA=E6=99=AF=E8=A7=84=E5=88=99=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E7=B1=BB=20IotAlertRecoverSceneRuleAction?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/alert/IotAlertRecordController.java | 3 +- .../dataobject/alert/IotAlertRecordDO.java | 7 ++++ .../dal/mysql/alert/IotAlertRecordMapper.java | 17 +++++++++ .../service/alert/IotAlertRecordService.java | 28 +++++++++++--- .../alert/IotAlertRecordServiceImpl.java | 38 +++++++++---------- .../IotAlertTriggerSceneRuleAction.java | 26 +++++++++++-- 6 files changed, 90 insertions(+), 29 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertRecordController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertRecordController.java index d75f42e3f4..91f15b989c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertRecordController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/alert/IotAlertRecordController.java @@ -18,6 +18,7 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static java.util.Collections.singleton; @Tag(name = "管理后台 - IoT 告警记录") @RestController @@ -49,7 +50,7 @@ public class IotAlertRecordController { @Operation(summary = "处理告警记录") @PreAuthorize("@ss.hasPermission('iot:alert-record:process')") public CommonResult processAlertRecord(@Valid @RequestBody IotAlertRecordProcessReqVO processReqVO) { - alertRecordService.processAlertRecord(processReqVO); + alertRecordService.processAlertRecordList(singleton(processReqVO.getId()), processReqVO.getProcessRemark()); return success(true); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertRecordDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertRecordDO.java index c057f85ccf..588b27068e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertRecordDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertRecordDO.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; @@ -51,6 +52,12 @@ public class IotAlertRecordDO extends BaseDO { * 字典 {@link cn.iocoder.yudao.module.iot.enums.DictTypeConstants#ALERT_LEVEL} */ private Integer configLevel; + /** + * 场景规则编号 + * + * 关联 {@link IotRuleSceneDO#getId()} + */ + private Long sceneRuleId; /** * 产品编号 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertRecordMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertRecordMapper.java index 3d29c5ff81..f23fe60f74 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertRecordMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/alert/IotAlertRecordMapper.java @@ -5,8 +5,12 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; +import java.util.Collection; +import java.util.List; + /** * IoT 告警记录 Mapper * @@ -26,4 +30,17 @@ public interface IotAlertRecordMapper extends BaseMapperX { .orderByDesc(IotAlertRecordDO::getId)); } + default List selectListBySceneRuleId(Long sceneRuleId, Long deviceId, Boolean processStatus) { + return selectList(new LambdaQueryWrapperX() + .eq(IotAlertRecordDO::getSceneRuleId, sceneRuleId) + .eqIfPresent(IotAlertRecordDO::getDeviceId, deviceId) + .eqIfPresent(IotAlertRecordDO::getProcessStatus, processStatus) + .orderByDesc(IotAlertRecordDO::getId)); + } + + default int updateList(Collection ids, IotAlertRecordDO updateObj) { + return update(updateObj, new LambdaUpdateWrapper() + .in(IotAlertRecordDO::getId, ids)); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordService.java index 57ad9a3762..68a2da97c9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordService.java @@ -2,10 +2,13 @@ package cn.iocoder.yudao.module.iot.service.alert; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordProcessReqVO; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO; +import jakarta.validation.constraints.NotNull; + +import java.util.Collection; +import java.util.List; /** * IoT 告警记录 Service 接口 @@ -31,19 +34,32 @@ public interface IotAlertRecordService { PageResult getAlertRecordPage(IotAlertRecordPageReqVO pageReqVO); /** - * 处理告警记录 + * 获得指定场景规则的告警记录列表 * - * @param processReqVO 处理请求 + * @param sceneRuleId 场景规则编号 + * @param deviceId 设备编号 + * @param processStatus 处理状态,允许空 + * @return 告警记录列表 */ - void processAlertRecord(IotAlertRecordProcessReqVO processReqVO); + List getAlertRecordListBySceneRuleId(@NotNull(message = "场景规则编号不能为空") Long sceneRuleId, + Long deviceId, Boolean processStatus); /** - * 创建告警记录 + * 处理告警记录 + * + * @param ids 告警记录编号 + * @param remark 处理结果(备注) + */ + void processAlertRecordList(Collection ids, String remark); + + /** + * 创建告警记录(包含场景规则编号) * * @param config 告警配置 + * @param sceneRuleId 场景规则编号 * @param deviceMessage 设备消息,可为空 * @return 告警记录编号 */ - Long createAlertRecord(IotAlertConfigDO config, IotDeviceMessage deviceMessage); + Long createAlertRecord(IotAlertConfigDO config, Long sceneRuleId, IotDeviceMessage deviceMessage); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordServiceImpl.java index 72b13d2546..34a673a4b5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertRecordServiceImpl.java @@ -1,8 +1,8 @@ package cn.iocoder.yudao.module.iot.service.alert; +import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.recrod.IotAlertRecordProcessReqVO; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO; @@ -13,8 +13,8 @@ import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.ALERT_RECORD_NOT_EXISTS; +import java.util.Collection; +import java.util.List; /** * IoT 告警记录 Service 实现类 @@ -42,35 +42,35 @@ public class IotAlertRecordServiceImpl implements IotAlertRecordService { } @Override - public void processAlertRecord(IotAlertRecordProcessReqVO processReqVO) { - // 校验告警记录是否存在 - IotAlertRecordDO alertRecord = alertRecordMapper.selectById(processReqVO.getId()); - if (alertRecord == null) { - throw exception(ALERT_RECORD_NOT_EXISTS); - } - - // 更新处理状态和备注 - alertRecordMapper.updateById(IotAlertRecordDO.builder() - .id(processReqVO.getId()) - .processStatus(true) - .processRemark(processReqVO.getProcessRemark()) - .build()); + public List getAlertRecordListBySceneRuleId(Long sceneRuleId, Long deviceId, Boolean processStatus) { + return alertRecordMapper.selectListBySceneRuleId(sceneRuleId, deviceId, processStatus); } @Override - public Long createAlertRecord(IotAlertConfigDO config, IotDeviceMessage message) { + public void processAlertRecordList(Collection ids, String processRemark) { + if (CollUtil.isEmpty(ids)) { + return; + } + // 批量更新告警记录的处理状态 + alertRecordMapper.updateList(ids, IotAlertRecordDO.builder() + .processStatus(true).processRemark(processRemark).build()); + } + + @Override + public Long createAlertRecord(IotAlertConfigDO config, Long sceneRuleId, IotDeviceMessage message) { // 构建告警记录 IotAlertRecordDO.IotAlertRecordDOBuilder builder = IotAlertRecordDO.builder() .configId(config.getId()).configName(config.getName()).configLevel(config.getLevel()) - .processStatus(false); + .sceneRuleId(sceneRuleId).processStatus(false); if (message != null) { builder.deviceMessage(message); // 填充设备信息 IotDeviceDO device = deviceService.getDeviceFromCache(message.getDeviceId()); - if (device!= null) { + if (device != null) { builder.productId(device.getProductId()).deviceId(device.getId()); } } + // 插入记录 IotAlertRecordDO record = builder.build(); alertRecordMapper.insert(record); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java index 8ac33fcefc..df34eea16f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java @@ -8,6 +8,9 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; import cn.iocoder.yudao.module.iot.service.alert.IotAlertConfigService; import cn.iocoder.yudao.module.iot.service.alert.IotAlertRecordService; +import cn.iocoder.yudao.module.system.api.mail.MailSendApi; +import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; +import cn.iocoder.yudao.module.system.api.sms.SmsSendApi; import jakarta.annotation.Resource; import org.springframework.stereotype.Component; @@ -25,10 +28,16 @@ public class IotAlertTriggerSceneRuleAction implements IotSceneRuleAction { @Resource private IotAlertConfigService alertConfigService; - @Resource private IotAlertRecordService alertRecordService; + @Resource + private SmsSendApi smsSendApi; + @Resource + private MailSendApi mailSendApi; + @Resource + private NotifyMessageSendApi notifyMessageSendApi; + @Override public void execute(@Nullable IotDeviceMessage message, IotRuleSceneDO rule, IotRuleSceneDO.ActionConfig actionConfig) throws Exception { @@ -37,8 +46,19 @@ public class IotAlertTriggerSceneRuleAction implements IotSceneRuleAction { if (CollUtil.isEmpty(alertConfigs)) { return; } - alertConfigs.forEach(alertConfig -> - alertRecordService.createAlertRecord(alertConfig, message)); + alertConfigs.forEach(alertConfig -> { + // 记录告警记录,传递场景规则ID + alertRecordService.createAlertRecord(alertConfig, rule.getId(), message); + // 发送告警消息 + sendAlertMessage(alertConfig, message); + }); + } + + private void sendAlertMessage(IotAlertConfigDO config, IotDeviceMessage deviceMessage) { + // TODO @芋艿:等场景联动开发完,再实现 + // TODO @芋艿:短信 + // TODO @芋艿:邮箱 + // TODO @芋艿:站内信 } @Override From a3f58be5714b0c5c24e998ed4f322db427f45629 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 28 Jun 2025 19:39:29 +0800 Subject: [PATCH 16/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E6=96=B0=E5=A2=9E=E5=91=8A=E8=AD=A6?= =?UTF-8?q?=E6=81=A2=E5=A4=8D=E5=9C=BA=E6=99=AF=E8=A7=84=E5=88=99=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E7=B1=BB=20IotAlertRecoverSceneRuleAction?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IotAlertRecoverSceneRuleAction.java | 52 ++++++------------- 1 file changed, 16 insertions(+), 36 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertRecoverSceneRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertRecoverSceneRuleAction.java index f4bb853244..6cc9fa5786 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertRecoverSceneRuleAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertRecoverSceneRuleAction.java @@ -1,69 +1,49 @@ package cn.iocoder.yudao.module.iot.service.rule.scene.action; import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; -import cn.iocoder.yudao.module.iot.service.alert.IotAlertConfigService; import cn.iocoder.yudao.module.iot.service.alert.IotAlertRecordService; -import cn.iocoder.yudao.module.system.api.mail.MailSendApi; -import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; -import cn.iocoder.yudao.module.system.api.sms.SmsSendApi; import jakarta.annotation.Resource; import org.springframework.stereotype.Component; -import javax.annotation.Nullable; import java.util.List; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + // TODO @puhui999、@芋艿:未测试;需要场景联动开发完 /** - * IoT 告警触发的 {@link IotSceneRuleAction} 实现类 + * IoT 告警恢复的 {@link IotSceneRuleAction} 实现类 * * @author 芋道源码 */ @Component -public class IotAlertTriggerSceneRuleAction implements IotSceneRuleAction { +public class IotAlertRecoverSceneRuleAction implements IotSceneRuleAction { + + private static final String PROCESS_REMARK = "告警自动回复,基于【{}】场景联动规则"; - @Resource - private IotAlertConfigService alertConfigService; @Resource private IotAlertRecordService alertRecordService; - @Resource - private SmsSendApi smsSendApi; - @Resource - private MailSendApi mailSendApi; - @Resource - private NotifyMessageSendApi notifyMessageSendApi; - @Override - public void execute(@Nullable IotDeviceMessage message, + public void execute(IotDeviceMessage message, IotRuleSceneDO rule, IotRuleSceneDO.ActionConfig actionConfig) throws Exception { - List alertConfigs = alertConfigService.getAlertConfigListBySceneRuleIdAndStatus( - rule.getId(), CommonStatusEnum.ENABLE.getStatus()); - if (CollUtil.isEmpty(alertConfigs)) { + Long deviceId = message != null ? message.getDeviceId() : null; + List alertRecords = alertRecordService.getAlertRecordListBySceneRuleId( + rule.getId(), deviceId, false); + if (CollUtil.isEmpty(alertRecords)) { return; } - alertConfigs.forEach(alertConfig -> { - // 记录告警记录 - alertRecordService.createAlertRecord(alertConfig, message); - // 发送告警消息 - sendAlertMessage(alertConfig, message); - }); - } - - private void sendAlertMessage(IotAlertConfigDO config, IotDeviceMessage deviceMessage) { - // TODO @芋艿:等场景联动开发完,再实现 - // TODO @芋艿:短信 - // TODO @芋艿:邮箱 - // TODO @芋艿:站内信 + alertRecordService.processAlertRecordList(convertList(alertRecords, IotAlertRecordDO::getId), + StrUtil.format(PROCESS_REMARK, rule.getName())); } @Override public IotRuleSceneActionTypeEnum getType() { - return IotRuleSceneActionTypeEnum.ALERT_TRIGGER; + return IotRuleSceneActionTypeEnum.ALERT_RECOVER; } } From 3535fda9e153f503e2d1951e710c0c21db7bb80e Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 28 Jun 2025 22:09:45 +0800 Subject: [PATCH 17/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E6=96=B0=E5=A2=9E=E5=85=A8=E5=B1=80?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=B1=BB=20YudaoIotProperties=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AE=BE=E5=A4=87=E7=A6=BB=E7=BA=BF=E6=A3=80?= =?UTF-8?q?=E6=B5=8B=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/config/YudaoIotProperties.java | 28 +++++++++++++++++++ .../iot/framework/iot/package-info.java | 4 +++ .../job/device/IotDeviceOfflineCheckJob.java | 18 ++++++------ .../enums/IotDeviceMessageMethodEnum.java | 2 ++ .../gateway/codec/modbus/package-info.java | 1 - .../gateway/codec/simple/package-info.java | 4 +++ 6 files changed, 48 insertions(+), 9 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/iot/config/YudaoIotProperties.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/iot/package-info.java delete mode 100644 yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/modbus/package-info.java create mode 100644 yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/simple/package-info.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/iot/config/YudaoIotProperties.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/iot/config/YudaoIotProperties.java new file mode 100644 index 0000000000..07473c0293 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/iot/config/YudaoIotProperties.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.iot.framework.iot.config; + +import lombok.Data; +import org.springframework.stereotype.Component; + +import java.time.Duration; + +/** + * 芋道 IoT 全局配置类 + * + * @author 芋道源码 + */ +@Component +@Data +public class YudaoIotProperties { + + /** + * 设备连接超时时间 + */ + private Duration keepAliveTime = Duration.ofMinutes(10); + /** + * 设备连接超时时间的因子 + * + * 因为设备可能会有网络抖动,所以需要乘以一个因子,避免误判 + */ + private double keepAliveFactor = 1.5D; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/iot/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/iot/package-info.java new file mode 100644 index 0000000000..0930a1409c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/iot/package-info.java @@ -0,0 +1,4 @@ +/** + * iot 模块的【全局】拓展封装 + */ +package cn.iocoder.yudao.module.iot.framework.iot; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/device/IotDeviceOfflineCheckJob.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/device/IotDeviceOfflineCheckJob.java index b14beafe23..6bd27a679a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/device/IotDeviceOfflineCheckJob.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/device/IotDeviceOfflineCheckJob.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.framework.iot.config.YudaoIotProperties; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceMessageService; import cn.iocoder.yudao.module.iot.service.device.property.IotDevicePropertyService; @@ -24,17 +25,14 @@ import java.util.Set; * * 检测逻辑:设备最后一条 {@link IotDeviceMessage} 消息超过一定时间,则认为设备离线 * + * @see 阿里云 IoT —— 设备离线分析 * @author 芋道源码 */ @Component public class IotDeviceOfflineCheckJob implements JobHandler { - /** - * 设备离线超时时间 - * - * TODO 芋艿:暂定 10 分钟,后续看看要不要基于设备或者全局有配置文件 - */ - public static final Duration OFFLINE_TIMEOUT = Duration.ofMinutes(10); + @Resource + private YudaoIotProperties iotProperties; @Resource private IotDeviceService deviceService; @@ -52,8 +50,7 @@ public class IotDeviceOfflineCheckJob implements JobHandler { return JsonUtils.toJsonString(Collections.emptyList()); } // 1.2 获取超时的设备集合 - Set timeoutDeviceIds = devicePropertyService.getDeviceIdListByReportTime( - LocalDateTime.now().minus(OFFLINE_TIMEOUT)); + Set timeoutDeviceIds = devicePropertyService.getDeviceIdListByReportTime(getTimeoutTime()); // 2. 下线设备 List offlineDevices = CollUtil.newArrayList(); @@ -68,4 +65,9 @@ public class IotDeviceOfflineCheckJob implements JobHandler { return JsonUtils.toJsonString(offlineDevices); } + private LocalDateTime getTimeoutTime() { + return LocalDateTime.now().minus(Duration.ofNanos( + (long) (iotProperties.getKeepAliveTime().toNanos() * iotProperties.getKeepAliveFactor()))); + } + } diff --git a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums/IotDeviceMessageMethodEnum.java b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums/IotDeviceMessageMethodEnum.java index cb343e33ec..fddf155a08 100644 --- a/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums/IotDeviceMessageMethodEnum.java +++ b/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums/IotDeviceMessageMethodEnum.java @@ -21,6 +21,8 @@ public enum IotDeviceMessageMethodEnum implements ArrayValuable { STATE_UPDATE("thing.state.update", "设备状态更新", true), + // TODO 芋艿:要不要加个 ping 消息; + // ========== 设备属性 ========== // 可参考:https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/modbus/package-info.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/modbus/package-info.java deleted file mode 100644 index 5e4835da78..0000000000 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/modbus/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.module.iot.gateway.codec.modbus; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/simple/package-info.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/simple/package-info.java new file mode 100644 index 0000000000..5bd676ad1a --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/simple/package-info.java @@ -0,0 +1,4 @@ +/** + * TODO @芋艿:实现一个 alink 的 xml 版本 + */ +package cn.iocoder.yudao.module.iot.gateway.codec.simple; \ No newline at end of file From 233afd7a59b6e62bde41d331a5d36d7fc24eab08 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 29 Jun 2025 10:45:09 +0800 Subject: [PATCH 18/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E5=95=86=E5=93=81=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=97=B6=EF=BC=8CproductKey=20=E4=B8=8D=E5=9C=A8=E8=B7=A8?= =?UTF-8?q?=E7=A7=9F=E6=88=B7=E6=A0=A1=E9=AA=8C=EF=BC=8C=E5=9B=A0=E4=B8=BA?= =?UTF-8?q?=E5=8F=AA=E9=9C=80=E8=A6=81=E4=BF=9D=E8=AF=81=20productKey=20+?= =?UTF-8?q?=20deviceName=20=E8=B7=A8=E7=A7=9F=E6=88=B7=E5=94=AF=E4=B8=80?= =?UTF-8?q?=E5=8D=B3=E5=8F=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/service/product/IotProductServiceImpl.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index fb198c8a3b..f29b4eaf9d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; -import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.product.IotProductSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; @@ -47,12 +46,9 @@ public class IotProductServiceImpl implements IotProductService { @Override public Long createProduct(IotProductSaveReqVO createReqVO) { // 1. 校验 ProductKey - TenantUtils.executeIgnore(() -> { - // 为什么忽略租户?避免多个租户之间,productKey 重复,导致 TDengine 设备属性表重复 - if (productMapper.selectByProductKey(createReqVO.getProductKey()) != null) { - throw exception(PRODUCT_KEY_EXISTS); - } - }); + if (productMapper.selectByProductKey(createReqVO.getProductKey()) != null) { + throw exception(PRODUCT_KEY_EXISTS); + } // 2. 插入 IotProductDO product = BeanUtils.toBean(createReqVO, IotProductDO.class) From fd00fb29546d35d737951bf93945281eaa545389 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 29 Jun 2025 10:50:40 +0800 Subject: [PATCH 19/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E6=96=B0=E5=A2=9E=E4=BA=A7=E5=93=81?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=A4=B1=E8=B4=A5=E9=94=99=E8=AF=AF=E7=A0=81?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96=E4=BA=A7=E5=93=81=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E4=BB=A5=E9=98=B2=E6=AD=A2=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E5=AD=98=E5=9C=A8=E8=AE=BE=E5=A4=87=E7=9A=84=E4=BA=A7=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 1 + .../iot/service/device/IotDeviceServiceImpl.java | 1 + .../property/IotDevicePropertyServiceImpl.java | 2 ++ .../service/product/IotProductServiceImpl.java | 15 +++++++++++---- .../thingmodel/IotThingModelServiceImpl.java | 2 ++ 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 47694cfeeb..1546f8a043 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -14,6 +14,7 @@ public interface ErrorCodeConstants { ErrorCode PRODUCT_KEY_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在"); ErrorCode PRODUCT_STATUS_NOT_DELETE = new ErrorCode(1_050_001_002, "产品状是发布状态,不允许删除"); ErrorCode PRODUCT_STATUS_NOT_ALLOW_THING_MODEL = new ErrorCode(1_050_001_003, "产品状是发布状态,不允许操作物模型"); + ErrorCode PRODUCT_DELETE_FAIL_HAS_DEVICE = new ErrorCode(1_050_001_004, "产品下存在设备,不允许删除"); // ========== 产品物模型 1-050-002-000 ============ ErrorCode THING_MODEL_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在"); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 604a8ae9b5..4bb090db41 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -56,6 +56,7 @@ public class IotDeviceServiceImpl implements IotDeviceService { private IotDeviceMapper deviceMapper; @Resource + @Lazy // 延迟加载,解决循环依赖 private IotProductService productService; @Resource @Lazy // 延迟加载,解决循环依赖 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java index 20e857ed80..b3fe9f4e95 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java @@ -23,6 +23,7 @@ import cn.iocoder.yudao.module.iot.service.product.IotProductService; import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @@ -58,6 +59,7 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { @Resource private IotThingModelService thingModelService; @Resource + @Lazy // 延迟加载,解决循环依赖 private IotProductService productService; @Resource diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index f29b4eaf9d..151590ab85 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -10,12 +10,12 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import cn.iocoder.yudao.module.iot.service.device.property.IotDevicePropertyService; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import jakarta.annotation.Resource; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; -import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -40,8 +40,9 @@ public class IotProductServiceImpl implements IotProductService { private IotProductMapper productMapper; @Resource - @Lazy // 延迟加载,解决循环依赖 private IotDevicePropertyService devicePropertyDataService; + @Resource + private IotDeviceService deviceService; @Override public Long createProduct(IotProductSaveReqVO createReqVO) { @@ -65,6 +66,7 @@ public class IotProductServiceImpl implements IotProductService { IotProductDO iotProductDO = validateProductExists(updateReqVO.getId()); // 1.2 发布状态不可更新 validateProductStatus(iotProductDO); + // 2. 更新 IotProductDO updateObj = BeanUtils.toBean(updateReqVO, IotProductDO.class); productMapper.updateById(updateObj); @@ -74,9 +76,14 @@ public class IotProductServiceImpl implements IotProductService { @CacheEvict(value = RedisKeyConstants.PRODUCT, key = "#id") public void deleteProduct(Long id) { // 1.1 校验存在 - IotProductDO iotProductDO = validateProductExists(id); + IotProductDO product = validateProductExists(id); // 1.2 发布状态不可删除 - validateProductStatus(iotProductDO); + validateProductStatus(product); + // 1.3 校验是否有设备 + if (deviceService.getDeviceCountByProductId(id) > 0) { + throw exception(PRODUCT_DELETE_FAIL_HAS_DEVICE); + } + // 2. 删除 productMapper.deleteById(id); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java index dc7c71c6ee..a72b6d4271 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java @@ -20,6 +20,7 @@ import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -47,6 +48,7 @@ public class IotThingModelServiceImpl implements IotThingModelService { private IotThingModelMapper thingModelMapper; @Resource + @Lazy // 延迟加载,解决循环依赖 private IotProductService productService; @Override From da60e649dfd068519ca2f040b9579fe23ff07b10 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 29 Jun 2025 17:09:20 +0800 Subject: [PATCH 20/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E7=89=A9=E6=A8=A1=E5=9E=8B=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E4=BD=BF=E7=94=A8=20NVARCHAR=20=E5=AD=98=E5=82=A8?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E5=85=BC=E5=AE=B9=20struct=E3=80=81array=20?= =?UTF-8?q?=E7=AD=89=E6=95=B0=E6=8D=AE=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../device/IotDevicePropertyController.java | 2 +- .../IotDevicePropertyDetailRespVO.java | 2 +- .../thingmodel/IotThingModelController.java | 35 +++++++++--------- .../thingmodel/vo/IotThingModelRespVO.java | 6 +-- .../thingmodel/vo/IotThingModelSaveReqVO.java | 6 +-- .../thingmodel/vo/IotThingModelTSLRespVO.java | 8 ++-- .../thingmodel/IotThingModelConvert.java | 6 +-- .../thingmodel/IotThingModelDO.java | 6 +-- .../thingmodel/model/ThingModelEvent.java | 2 +- .../thingmodel/model/ThingModelParam.java | 4 +- .../thingmodel/model/ThingModelProperty.java | 4 +- .../thingmodel/model/ThingModelService.java | 2 +- .../dataType/ThingModelArrayDataSpecs.java | 2 +- .../ThingModelBoolOrEnumDataSpecs.java | 4 +- .../model/dataType/ThingModelDataSpecs.java | 6 +-- .../ThingModelDateOrTextDataSpecs.java | 11 +++--- .../dataType/ThingModelNumericDataSpec.java | 18 ++++----- .../dataType/ThingModelStructDataSpecs.java | 2 +- .../tdengine/core/TDengineTableField.java | 6 +++ .../IotDevicePropertyServiceImpl.java | 37 +++++++++++++------ .../rule/data/IotDataRuleServiceImpl.java | 2 +- .../thingmodel/IotThingModelService.java | 2 +- .../thingmodel/IotThingModelServiceImpl.java | 29 ++++++--------- 23 files changed, 109 insertions(+), 93 deletions(-) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/{controller/admin => dal/dataobject}/thingmodel/model/ThingModelEvent.java (95%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/{controller/admin => dal/dataobject}/thingmodel/model/ThingModelParam.java (92%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/{controller/admin => dal/dataobject}/thingmodel/model/ThingModelProperty.java (91%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/{controller/admin => dal/dataobject}/thingmodel/model/ThingModelService.java (96%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/{controller/admin => dal/dataobject}/thingmodel/model/dataType/ThingModelArrayDataSpecs.java (93%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/{controller/admin => dal/dataobject}/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java (89%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/{controller/admin => dal/dataobject}/thingmodel/model/dataType/ThingModelDataSpecs.java (89%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/{controller/admin => dal/dataobject}/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java (67%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/{controller/admin => dal/dataobject}/thingmodel/model/dataType/ThingModelNumericDataSpec.java (82%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/{controller/admin => dal/dataobject}/thingmodel/model/dataType/ThingModelStructDataSpecs.java (95%) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDevicePropertyController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDevicePropertyController.java index b78793f8cf..4988efbeb3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDevicePropertyController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDevicePropertyController.java @@ -6,7 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.property.IotDevicePropertyDetailRespVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.property.IotDevicePropertyHistoryListReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.property.IotDevicePropertyRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.ThingModelProperty; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/property/IotDevicePropertyDetailRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/property/IotDevicePropertyDetailRespVO.java index 2fa27021ca..57712691f8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/property/IotDevicePropertyDetailRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/property/IotDevicePropertyDetailRespVO.java @@ -1,6 +1,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.device.vo.property; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDataSpecs; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType.ThingModelDataSpecs; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.java index 6b143a6bbe..d93c18d472 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.java @@ -1,14 +1,15 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; +import cn.iocoder.yudao.module.iot.service.product.IotProductService; import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService; +import com.google.common.base.Objects; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -32,6 +33,8 @@ public class IotThingModelController { @Resource private IotThingModelService thingModelService; + @Resource + private IotProductService productService; @PostMapping("/create") @Operation(summary = "创建产品物模型") @@ -71,23 +74,21 @@ public class IotThingModelController { @Parameter(name = "productId", description = "产品 ID", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('iot:thing-model:query')") public CommonResult getThingModelTsl(@RequestParam("productId") Long productId) { - IotThingModelTSLRespVO tslRespVO = new IotThingModelTSLRespVO(); - // TODO @puhui999:是不是要先查询产品哈?原因是,万一没配置物模型,但是产品已经有了! - // 1. 获得产品所有物模型定义 - List thingModels = thingModelService.getThingModelListByProductId(productId); - if (CollUtil.isEmpty(thingModels)) { - return success(tslRespVO); + // 1. 获得产品 + IotProductDO product = productService.getProduct(productId); + if (product == null) { + return success(null); } - - // 2. 设置公共部分参数 - IotThingModelDO thingModel = thingModels.get(0); - tslRespVO.setProductId(thingModel.getProductId()).setProductKey(thingModel.getProductKey()); + IotThingModelTSLRespVO tslRespVO = new IotThingModelTSLRespVO() + .setProductId(product.getId()).setProductKey(product.getProductKey()); + // 2. 获得物模型定义 + List thingModels = thingModelService.getThingModelListByProductId(productId); tslRespVO.setProperties(convertList(filterList(thingModels, item -> - ObjUtil.equal(IotThingModelTypeEnum.PROPERTY.getType(), item.getType())), IotThingModelDO::getProperty)); - tslRespVO.setServices(convertList(filterList(thingModels, item -> - ObjUtil.equal(IotThingModelTypeEnum.SERVICE.getType(), item.getType())), IotThingModelDO::getService)); - tslRespVO.setEvents(convertList(filterList(thingModels, item -> - ObjUtil.equal(IotThingModelTypeEnum.EVENT.getType(), item.getType())), IotThingModelDO::getEvent)); + Objects.equal(IotThingModelTypeEnum.PROPERTY.getType(), item.getType())), IotThingModelDO::getProperty)) + .setServices(convertList(filterList(thingModels, item -> + Objects.equal(IotThingModelTypeEnum.SERVICE.getType(), item.getType())), IotThingModelDO::getService)) + .setEvents(convertList(filterList(thingModels, item -> + Objects.equal(IotThingModelTypeEnum.EVENT.getType(), item.getType())), IotThingModelDO::getEvent)); return success(tslRespVO); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java index 2b7f17ac72..a7a17dde8c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java @@ -1,8 +1,8 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.ThingModelEvent; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.ThingModelProperty; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.ThingModelService; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelSaveReqVO.java index 1e8564df47..97404983d2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelSaveReqVO.java @@ -1,9 +1,9 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo; import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.ThingModelEvent; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.ThingModelProperty; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.ThingModelService; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.Valid; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelTSLRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelTSLRespVO.java index a5b28fd4e3..d3809d8819 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelTSLRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelTSLRespVO.java @@ -1,8 +1,8 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.ThingModelEvent; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.ThingModelProperty; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.ThingModelService; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -12,7 +12,7 @@ import java.util.List; @Data public class IotThingModelTSLRespVO { - @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Long productId; @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature_sensor") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/IotThingModelConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/IotThingModelConvert.java index 9577b18f7b..6abbe97b7b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/IotThingModelConvert.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/IotThingModelConvert.java @@ -1,8 +1,8 @@ package cn.iocoder.yudao.module.iot.convert.thingmodel; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.ThingModelEvent; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.ThingModelProperty; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.ThingModelService; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/IotThingModelDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/IotThingModelDO.java index e3b4a6d9ae..d70d2e1d01 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/IotThingModelDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/IotThingModelDO.java @@ -1,9 +1,9 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.ThingModelEvent; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.ThingModelProperty; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.ThingModelService; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelEvent.java similarity index 95% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelEvent.java index bf6e20b8a2..4d85370011 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelEvent.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; +package cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model; import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelServiceEventTypeEnum; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelParam.java similarity index 92% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelParam.java index 2afad898b0..3919542d5a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelParam.java @@ -1,7 +1,7 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; +package cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model; import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDataSpecs; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType.ThingModelDataSpecs; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelParamDirectionEnum; import jakarta.validation.constraints.NotEmpty; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelProperty.java similarity index 91% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelProperty.java index 4b9a05a0e2..2fe103a4b0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelProperty.java @@ -1,7 +1,7 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; +package cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model; import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDataSpecs; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType.ThingModelDataSpecs; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelAccessModeEnum; import jakarta.validation.constraints.NotEmpty; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelService.java similarity index 96% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelService.java index c98acd8243..10476956cb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelService.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; +package cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model; import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelServiceCallTypeEnum; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArrayDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelArrayDataSpecs.java similarity index 93% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArrayDataSpecs.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelArrayDataSpecs.java index 554bd2a83d..7107f99f56 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArrayDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelArrayDataSpecs.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; +package cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.validation.Valid; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java similarity index 89% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java index 80a4e0d970..8533fcc6f5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; +package cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.validation.constraints.NotEmpty; @@ -10,7 +10,7 @@ import lombok.EqualsAndHashCode; /** * IoT 物模型数据类型为布尔型或枚举型的 DataSpec 定义 * - * 数据类型,取值为 bool 或 enum。 + * 数据类型,取值为 bool 或 enum * * @author HUIHUI */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelDataSpecs.java similarity index 89% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDataSpecs.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelDataSpecs.java index d9fc12dd95..1643ab2c2c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelDataSpecs.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; +package cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; @@ -7,8 +7,8 @@ import lombok.Data; /** * IoT ThingModelDataSpecs 抽象类 * - * 用于表示物模型数据的通用类型,根据具体的 "dataType" 字段动态映射到对应的子类。 - * 提供多态支持,适用于不同类型的数据结构序列化和反序列化场景。 + * 用于表示物模型数据的通用类型,根据具体的 "dataType" 字段动态映射到对应的子类 + * 提供多态支持,适用于不同类型的数据结构序列化和反序列化场景 * * @author HUIHUI */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java similarity index 67% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java index 489833d4ba..18ca982c1a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; +package cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.validation.constraints.Max; @@ -8,7 +8,7 @@ import lombok.EqualsAndHashCode; /** * IoT 物模型数据类型为时间型或文本型的 DataSpec 定义 * - * 数据类型,取值为 date 或 text。 + * 数据类型,取值为 date 或 text * * @author HUIHUI */ @@ -18,13 +18,14 @@ import lombok.EqualsAndHashCode; public class ThingModelDateOrTextDataSpecs extends ThingModelDataSpecs { /** - * 数据长度,单位为字节。取值不能超过 2048。 - * 当 dataType 为 text 时,需传入该参数。 + * 数据长度,单位为字节。取值不能超过 2048 + * + * 当 dataType 为 text 时,需传入该参数 */ @Max(value = 2048, message = "数据长度不能超过 2048") private Integer length; /** - * 默认值,可选参数,用于存储默认值。 + * 默认值,可选参数,用于存储默认值 */ private String defaultValue; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelNumericDataSpec.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelNumericDataSpec.java similarity index 82% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelNumericDataSpec.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelNumericDataSpec.java index bd3457d7d5..4433a9b224 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelNumericDataSpec.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelNumericDataSpec.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; +package cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.validation.constraints.NotEmpty; @@ -9,7 +9,7 @@ import lombok.EqualsAndHashCode; /** * IoT 物模型数据类型为数值的 DataSpec 定义 * - * 数据类型,取值为 int、float 或 double。 + * 数据类型,取值为 int、float 或 double * * @author HUIHUI */ @@ -19,37 +19,37 @@ import lombok.EqualsAndHashCode; public class ThingModelNumericDataSpec extends ThingModelDataSpecs { /** - * 最大值,需转为字符串类型。值必须与 dataType 类型一致。 + * 最大值,需转为字符串类型。值必须与 dataType 类型一致 */ @NotEmpty(message = "最大值不能为空") @Pattern(regexp = "^-?\\d+(\\.\\d+)?$", message = "最大值必须为数值类型") private String max; /** - * 最小值,需转为字符串类型。值必须与 dataType 类型一致。 + * 最小值,需转为字符串类型。值必须与 dataType 类型一致 */ @NotEmpty(message = "最小值不能为空") @Pattern(regexp = "^-?\\d+(\\.\\d+)?$", message = "最小值必须为数值类型") private String min; /** - * 步长,需转为字符串类型。值必须与 dataType 类型一致。 + * 步长,需转为字符串类型。值必须与 dataType 类型一致 */ @NotEmpty(message = "步长不能为空") @Pattern(regexp = "^-?\\d+(\\.\\d+)?$", message = "步长必须为数值类型") private String step; /** - * 精度。当 dataType 为 float 或 double 时可选传入。 + * 精度。当 dataType 为 float 或 double 时可选传入 */ private String precise; /** - * 默认值,可传入用于存储的默认值。 + * 默认值,可传入用于存储的默认值 */ private String defaultValue; /** - * 单位的符号。 + * 单位的符号 */ private String unit; /** - * 单位的名称。 + * 单位的名称 */ private String unitName; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelStructDataSpecs.java similarity index 95% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelStructDataSpecs.java index 6ab7902e9f..a866a00107 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelStructDataSpecs.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; +package cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType; import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelAccessModeEnum; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableField.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableField.java index e3bbdd204f..48c3142eca 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableField.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableField.java @@ -23,8 +23,14 @@ public class TDengineTableField { public static final String TYPE_DOUBLE = "DOUBLE"; public static final String TYPE_BOOL = "BOOL"; public static final String TYPE_NCHAR = "NCHAR"; + public static final String TYPE_VARCHAR = "VARCHAR"; public static final String TYPE_TIMESTAMP = "TIMESTAMP"; + /** + * 字段长度 - VARCHAR 默认长度 + */ + public static final int LENGTH_VARCHAR = 1024; + /** * 注释 - TAG 字段 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java index b3fe9f4e95..8031c2a11a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java @@ -4,14 +4,16 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.property.IotDevicePropertyHistoryListReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.property.IotDevicePropertyRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs; import cn.iocoder.yudao.module.iot.dal.redis.device.DevicePropertyRedisDAO; import cn.iocoder.yudao.module.iot.dal.redis.device.DeviceReportTimeRedisDAO; import cn.iocoder.yudao.module.iot.dal.redis.device.DeviceServerIdRedisDAO; @@ -43,17 +45,19 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { /** * 物模型的数据类型,与 TDengine 数据类型的映射关系 + * + * @see TDEngine 数据类型 */ private static final Map TYPE_MAPPING = MapUtil.builder() .put(IotDataSpecsDataTypeEnum.INT.getDataType(), TDengineTableField.TYPE_INT) .put(IotDataSpecsDataTypeEnum.FLOAT.getDataType(), TDengineTableField.TYPE_FLOAT) .put(IotDataSpecsDataTypeEnum.DOUBLE.getDataType(), TDengineTableField.TYPE_DOUBLE) - .put(IotDataSpecsDataTypeEnum.ENUM.getDataType(), TDengineTableField.TYPE_TINYINT) // TODO 芋艿:为什么要映射为 TINYINT 的说明? - .put(IotDataSpecsDataTypeEnum.BOOL.getDataType(), TDengineTableField.TYPE_TINYINT) // TODO 芋艿:为什么要映射为 TINYINT 的说明? - .put(IotDataSpecsDataTypeEnum.TEXT.getDataType(), TDengineTableField.TYPE_NCHAR) + .put(IotDataSpecsDataTypeEnum.ENUM.getDataType(), TDengineTableField.TYPE_TINYINT) + .put(IotDataSpecsDataTypeEnum.BOOL.getDataType(), TDengineTableField.TYPE_TINYINT) + .put(IotDataSpecsDataTypeEnum.TEXT.getDataType(), TDengineTableField.TYPE_VARCHAR) .put(IotDataSpecsDataTypeEnum.DATE.getDataType(), TDengineTableField.TYPE_TIMESTAMP) - .put(IotDataSpecsDataTypeEnum.STRUCT.getDataType(), TDengineTableField.TYPE_NCHAR) // TODO 芋艿:怎么映射!!!! - .put(IotDataSpecsDataTypeEnum.ARRAY.getDataType(), TDengineTableField.TYPE_NCHAR) // TODO 芋艿:怎么映射!!!! + .put(IotDataSpecsDataTypeEnum.STRUCT.getDataType(), TDengineTableField.TYPE_VARCHAR) + .put(IotDataSpecsDataTypeEnum.ARRAY.getDataType(), TDengineTableField.TYPE_VARCHAR) .build(); @Resource @@ -109,8 +113,12 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { TDengineTableField field = new TDengineTableField( StrUtil.toUnderlineCase(thingModel.getIdentifier()), // TDengine 字段默认都是小写 TYPE_MAPPING.get(thingModel.getProperty().getDataType())); - if (thingModel.getProperty().getDataType().equals(IotDataSpecsDataTypeEnum.TEXT.getDataType())) { + String dataType = thingModel.getProperty().getDataType(); + if (Objects.equals(dataType, IotDataSpecsDataTypeEnum.TEXT.getDataType())) { field.setLength(((ThingModelDateOrTextDataSpecs) thingModel.getProperty().getDataSpecs()).getLength()); + } else if (ObjectUtils.equalsAny(dataType, IotDataSpecsDataTypeEnum.STRUCT.getDataType(), + IotDataSpecsDataTypeEnum.ARRAY.getDataType())) { + field.setLength(TDengineTableField.LENGTH_VARCHAR); } return field; }); @@ -118,7 +126,6 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { @Override public void saveDeviceProperty(IotDeviceDO device, IotDeviceMessage message) { - // TODO @芋艿:这里要改下协议! if (!(message.getParams() instanceof Map)) { log.error("[saveDeviceProperty][消息内容({}) 的 data 类型不正确]", message); return; @@ -129,11 +136,18 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { List thingModels = thingModelService.getThingModelListByProductIdFromCache(device.getProductId()); Map properties = new HashMap<>(); ((Map) message.getParams()).forEach((key, value) -> { - if (CollUtil.findOne(thingModels, thingModel -> thingModel.getIdentifier().equals(key)) == null) { + IotThingModelDO thingModel = CollUtil.findOne(thingModels, o -> o.getIdentifier().equals(key)); + if (thingModel == null || thingModel.getProperty() == null) { log.error("[saveDeviceProperty][消息({}) 的属性({}) 不存在]", message, key); return; } - properties.put((String) key, value); + if (ObjectUtils.equalsAny(thingModel.getProperty().getDataType(), + IotDataSpecsDataTypeEnum.STRUCT.getDataType(), IotDataSpecsDataTypeEnum.ARRAY.getDataType())) { + // 特殊:STRUCT 和 ARRAY 类型,在 TDengine 里,有没对应数据类型,只能通过 JSON 来存储 + properties.put((String) key, JsonUtils.toJsonString(value)); + } else { + properties.put((String) key, value); + } }); if (CollUtil.isEmpty(properties)) { log.error("[saveDeviceProperty][消息({}) 没有合法的属性]", message); @@ -141,8 +155,7 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { } // 2.1 保存设备属性【数据】 - devicePropertyMapper.insert(device, properties, - LocalDateTimeUtil.toEpochMilli(message.getReportTime())); + devicePropertyMapper.insert(device, properties, LocalDateTimeUtil.toEpochMilli(message.getReportTime())); // 2.2 保存设备属性【日志】 Map properties2 = convertMap(properties.entrySet(), Map.Entry::getKey, entry -> diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java index 81ce34dd60..3144a1362a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java @@ -143,7 +143,7 @@ public class IotDataRuleServiceImpl implements IotDataRuleService { productId -> new HashSet<>()).add(config.getIdentifier()); } for (Map.Entry> entry : productIdIdentifiers.entrySet()) { - thingModelService.validateThingModelsExist(entry.getKey(), entry.getValue()); + thingModelService.validateThingModelListExists(entry.getKey(), entry.getValue()); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java index b4af6f663d..b8c951b949 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java @@ -106,6 +106,6 @@ public interface IotThingModelService { * @param productId 产品编号 * @param identifiers 标识符集合 */ - void validateThingModelsExist(Long productId, Set identifiers); + void validateThingModelListExists(Long productId, Set identifiers); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java index a72b6d4271..ca04ecd5f3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java @@ -66,7 +66,7 @@ public class IotThingModelServiceImpl implements IotThingModelService { thingModelMapper.insert(thingModel); // 3. 删除缓存 - deleteThingModelListCache(createReqVO.getProductKey()); + deleteThingModelListCache(createReqVO.getProductId()); return thingModel.getId(); } @@ -85,7 +85,7 @@ public class IotThingModelServiceImpl implements IotThingModelService { thingModelMapper.updateById(thingModel); // 3. 删除缓存 - deleteThingModelListCache(updateReqVO.getProductKey()); + deleteThingModelListCache(updateReqVO.getProductId()); } @Override @@ -103,7 +103,7 @@ public class IotThingModelServiceImpl implements IotThingModelService { thingModelMapper.deleteById(id); // 3. 删除缓存 - deleteThingModelListCache(thingModel.getProductKey()); + deleteThingModelListCache(thingModel.getProductId()); } @Override @@ -128,7 +128,7 @@ public class IotThingModelServiceImpl implements IotThingModelService { @Override @Cacheable(value = RedisKeyConstants.THING_MODEL_LIST, key = "#productId") - @TenantIgnore // 忽略租户信息,跨租户 productKey 是唯一的 + @TenantIgnore // 忽略租户信息 public List getThingModelListByProductIdFromCache(Long productId) { return thingModelMapper.selectListByProductId(productId); } @@ -144,7 +144,7 @@ public class IotThingModelServiceImpl implements IotThingModelService { } @Override - public void validateThingModelsExist(Long productId, Set identifiers) { + public void validateThingModelListExists(Long productId, Set identifiers) { if (CollUtil.isEmpty(identifiers)) { return; } @@ -158,11 +158,6 @@ public class IotThingModelServiceImpl implements IotThingModelService { } } - /** - * 校验功能是否存在 - * - * @param id 功能编号 - */ private void validateProductThingModelMapperExists(Long id) { if (thingModelMapper.selectById(id) == null) { throw exception(THING_MODEL_NOT_EXISTS); @@ -170,13 +165,12 @@ public class IotThingModelServiceImpl implements IotThingModelService { } private void validateIdentifierUnique(Long id, Long productId, String identifier) { - // 1.0 情况一:创建时校验 + // 1. 情况一:创建时校验 if (id == null) { // 1.1 系统保留字段,不能用于标识符定义 if (StrUtil.equalsAny(identifier, "set", "get", "post", "property", "event", "time", "value")) { throw exception(THING_MODEL_IDENTIFIER_INVALID); } - // 1.2 校验唯一 IotThingModelDO thingModel = thingModelMapper.selectByProductIdAndIdentifier(productId, identifier); if (thingModel != null) { @@ -185,7 +179,7 @@ public class IotThingModelServiceImpl implements IotThingModelService { return; } - // 2.0 情况二:更新时校验 + // 2. 情况二:更新时校验 IotThingModelDO thingModel = thingModelMapper.selectByProductIdAndIdentifier(productId, identifier); if (thingModel != null && ObjectUtil.notEqual(thingModel.getId(), id)) { throw exception(THING_MODEL_IDENTIFIER_EXISTS); @@ -206,13 +200,14 @@ public class IotThingModelServiceImpl implements IotThingModelService { } } - private void deleteThingModelListCache(String productKey) { + private void deleteThingModelListCache(Long productId) { // 保证 Spring AOP 触发 - getSelf().deleteThingModelListCache0(productKey); + getSelf().deleteThingModelListCache0(productId); } - @CacheEvict(value = RedisKeyConstants.THING_MODEL_LIST, key = "#productKey") - public void deleteThingModelListCache0(String productKey) { + @CacheEvict(value = RedisKeyConstants.THING_MODEL_LIST, key = "#productId") + @TenantIgnore // 忽略租户信息 + public void deleteThingModelListCache0(Long productId) { } private IotThingModelServiceImpl getSelf() { From 801a6b970eeaf2ba31778d8cd6a37181a9809407 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 29 Jun 2025 18:59:55 +0800 Subject: [PATCH 21/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E4=BC=98=E5=8C=96=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E6=95=B0=E9=87=8F=E7=BB=9F=E8=AE=A1=E9=80=BB=E8=BE=91=EF=BC=8C?= =?UTF-8?q?=E7=AE=80=E5=8C=96=E6=9F=A5=E8=AF=A2=E6=96=B9=E6=B3=95=E5=B9=B6?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E6=9B=B4=E7=9B=B4=E8=A7=82=E7=9A=84=E7=BB=93?= =?UTF-8?q?=E6=9E=9C=E6=98=A0=E5=B0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/dal/mysql/device/IotDeviceMapper.java | 30 ++++++++++++++----- .../service/device/IotDeviceServiceImpl.java | 16 ++-------- .../IotProductCategoryServiceImpl.java | 26 ++++++++-------- .../mapper/device/IotDeviceMapper.xml | 25 ---------------- 4 files changed, 38 insertions(+), 59 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index 32477221ac..7cc7d5de81 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import jakarta.annotation.Nullable; import org.apache.ibatis.annotations.Mapper; @@ -13,6 +14,7 @@ import java.time.LocalDateTime; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; /** * IoT 设备 Mapper @@ -80,19 +82,33 @@ public interface IotDeviceMapper extends BaseMapperX { } /** - * 查询指定产品下各状态的设备数量 + * 查询指定产品下的设备数量 * - * @return 设备数量统计列表 + * @return 产品编号 -> 设备数量的映射 */ - // TODO @super:通过 mybatis-plus 来写哈,然后返回 Map 貌似就行了?! - List> selectDeviceCountMapByProductId(); + default Map selectDeviceCountMapByProductId() { + List> result = selectMaps(new QueryWrapper() + .select("product_id AS productId", "COUNT(1) AS deviceCount") + .groupBy("product_id")); + return result.stream().collect(Collectors.toMap( + map -> Long.valueOf(map.get("productId").toString()), + map -> Integer.valueOf(map.get("deviceCount").toString()) + )); + } - // TODO @super:通过 mybatis-plus 来写哈,然后返回 Map 貌似就行了?! /** * 查询各个状态下的设备数量 * - * @return 设备数量统计列表 + * @return 设备状态 -> 设备数量的映射 */ - List> selectDeviceCountGroupByState(); + default Map selectDeviceCountGroupByState() { + List> result = selectMaps(new QueryWrapper() + .select("state", "COUNT(1) AS deviceCount") + .groupBy("state")); + return result.stream().collect(Collectors.toMap( + map -> Integer.valueOf(map.get("state").toString()), + map -> Long.valueOf(map.get("deviceCount").toString()) + )); + } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 4bb090db41..ccbd652d6e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -36,7 +36,6 @@ import org.springframework.validation.annotation.Validated; import javax.annotation.Nullable; import java.time.LocalDateTime; import java.util.*; -import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; @@ -430,25 +429,14 @@ public class IotDeviceServiceImpl implements IotDeviceService { return deviceMapper.selectCountByCreateTime(createTime); } - // TODO @super:简化 @Override public Map getDeviceCountMapByProductId() { - // 查询结果转换成Map - List> list = deviceMapper.selectDeviceCountMapByProductId(); - return list.stream().collect(Collectors.toMap( - map -> Long.valueOf(map.get("key").toString()), - map -> Integer.valueOf(map.get("value").toString()) - )); + return deviceMapper.selectDeviceCountMapByProductId(); } @Override public Map getDeviceCountMapByState() { - // 查询结果转换成Map - List> list = deviceMapper.selectDeviceCountGroupByState(); - return list.stream().collect(Collectors.toMap( - map -> Integer.valueOf(map.get("key").toString()), - map -> Long.valueOf(map.get("value").toString()) - )); + return deviceMapper.selectDeviceCountGroupByState(); } @Override diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java index 9eb401c634..3c64caedb7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java @@ -17,6 +17,8 @@ import java.time.LocalDateTime; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_CATEGORY_NOT_EXISTS; /** @@ -99,23 +101,21 @@ public class IotProductCategoryServiceImpl implements IotProductCategoryService @Override public Map getProductCategoryDeviceCountMap() { // 1. 获取所有数据 - List categoryList = iotProductCategoryMapper.selectList(); - List productList = productService.getProductList(); - // TODO @super:不要 list 查询,返回内存,而是查询一个 Map + List categories = iotProductCategoryMapper.selectList(); + List products = productService.getProductList(); Map deviceCountMapByProductId = deviceService.getDeviceCountMapByProductId(); // 2. 统计每个分类下的设备数量 Map categoryDeviceCountMap = new HashMap<>(); - for (IotProductCategoryDO category : categoryList) { - categoryDeviceCountMap.put(category.getName(), 0); - // TODO @super:CollectionUtils.getSumValue(),看看能不能简化下 - // 2.2 找到该分类下的所有产品,累加设备数量 - for (IotProductDO product : productList) { - if (Objects.equals(product.getCategoryId(), category.getId())) { - Integer deviceCount = deviceCountMapByProductId.getOrDefault(product.getId(), 0); - categoryDeviceCountMap.merge(category.getName(), deviceCount, Integer::sum); - } - } + for (IotProductCategoryDO category : categories) { + // 2.1 找到该分类下的所有产品 + List categoryProducts = filterList(products, + product -> Objects.equals(product.getCategoryId(), category.getId())); + // 2.2 累加设备数量 + Integer totalDeviceCount = getSumValue(categoryProducts, + product -> deviceCountMapByProductId.getOrDefault(product.getId(), 0), + Integer::sum, 0); + categoryDeviceCountMap.put(category.getName(), totalDeviceCount); } return categoryDeviceCountMap; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml deleted file mode 100644 index 8404729cce..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - \ No newline at end of file From 18c27196f1638f48d29f999e58c27c4e1313623d Mon Sep 17 00:00:00 2001 From: haohao <1036606149@qq.com> Date: Sun, 29 Jun 2025 19:45:47 +0800 Subject: [PATCH 22/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E4=B8=BA=20EMQX=20=E5=8D=8F?= =?UTF-8?q?=E8=AE=AE=E6=B7=BB=E5=8A=A0=20=E5=85=B1=E4=BA=AB=20=E7=9A=84=20?= =?UTF-8?q?Vertx?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/IotGatewayConfiguration.java | 18 +++++--- .../emqx/IotEmqxAuthEventProtocol.java | 19 ++------ .../emqx/IotEmqxUpstreamProtocol.java | 37 +++++++--------- .../emqx/router/IotEmqxDownstreamHandler.java | 43 +++++++++++++++++-- .../iot/gateway/util/IotMqttTopicUtils.java | 35 +++++++++++++++ 5 files changed, 107 insertions(+), 45 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java index e9b0001e13..11cbfca270 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.iot.gateway.protocol.emqx.IotEmqxDownstreamSubscr import cn.iocoder.yudao.module.iot.gateway.protocol.emqx.IotEmqxUpstreamProtocol; import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpDownstreamSubscriber; import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpUpstreamProtocol; +import io.vertx.core.Vertx; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -45,14 +46,21 @@ public class IotGatewayConfiguration { @Slf4j public static class MqttProtocolConfiguration { - @Bean - public IotEmqxAuthEventProtocol iotEmqxAuthEventProtocol(IotGatewayProperties gatewayProperties) { - return new IotEmqxAuthEventProtocol(gatewayProperties.getProtocol().getEmqx()); + @Bean(destroyMethod = "close") + public Vertx emqxVertx() { + return Vertx.vertx(); } @Bean - public IotEmqxUpstreamProtocol iotEmqxUpstreamProtocol(IotGatewayProperties gatewayProperties) { - return new IotEmqxUpstreamProtocol(gatewayProperties.getProtocol().getEmqx()); + public IotEmqxAuthEventProtocol iotEmqxAuthEventProtocol(IotGatewayProperties gatewayProperties, + Vertx emqxVertx) { + return new IotEmqxAuthEventProtocol(gatewayProperties.getProtocol().getEmqx(), emqxVertx); + } + + @Bean + public IotEmqxUpstreamProtocol iotEmqxUpstreamProtocol(IotGatewayProperties gatewayProperties, + Vertx emqxVertx) { + return new IotEmqxUpstreamProtocol(gatewayProperties.getProtocol().getEmqx(), emqxVertx); } @Bean diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/IotEmqxAuthEventProtocol.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/IotEmqxAuthEventProtocol.java index 2ba902c5c5..059479b89d 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/IotEmqxAuthEventProtocol.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/IotEmqxAuthEventProtocol.java @@ -28,20 +28,20 @@ public class IotEmqxAuthEventProtocol { private final String serverId; - private Vertx vertx; + private final Vertx vertx; private HttpServer httpServer; - public IotEmqxAuthEventProtocol(IotGatewayProperties.EmqxProperties emqxProperties) { + public IotEmqxAuthEventProtocol(IotGatewayProperties.EmqxProperties emqxProperties, + Vertx vertx) { this.emqxProperties = emqxProperties; + this.vertx = vertx; this.serverId = IotDeviceMessageUtils.generateServerId(emqxProperties.getMqttPort()); } @PostConstruct public void start() { try { - // 创建 Vertx 实例 - this.vertx = Vertx.vertx(); startHttpServer(); log.info("[start][IoT 网关 EMQX 认证事件协议服务启动成功, 端口: {}]", emqxProperties.getHttpPort()); } catch (Exception e) { @@ -53,17 +53,6 @@ public class IotEmqxAuthEventProtocol { @PreDestroy public void stop() { stopHttpServer(); - - // 关闭 Vertx 实例 - if (vertx != null) { - try { - vertx.close(); - log.debug("[stop][Vertx 实例已关闭]"); - } catch (Exception e) { - log.warn("[stop][关闭 Vertx 实例失败]", e); - } - } - log.info("[stop][IoT 网关 EMQX 认证事件协议服务已停止]"); } diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/IotEmqxUpstreamProtocol.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/IotEmqxUpstreamProtocol.java index a02aa17da0..fef3ce1723 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/IotEmqxUpstreamProtocol.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/IotEmqxUpstreamProtocol.java @@ -10,7 +10,6 @@ import io.vertx.mqtt.MqttClient; import io.vertx.mqtt.MqttClientOptions; import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; -import jodd.util.ThreadUtil; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -41,9 +40,11 @@ public class IotEmqxUpstreamProtocol { private IotEmqxUpstreamHandler upstreamHandler; - public IotEmqxUpstreamProtocol(IotGatewayProperties.EmqxProperties emqxProperties) { + public IotEmqxUpstreamProtocol(IotGatewayProperties.EmqxProperties emqxProperties, + Vertx vertx) { this.emqxProperties = emqxProperties; this.serverId = IotDeviceMessageUtils.generateServerId(emqxProperties.getMqttPort()); + this.vertx = vertx; } @PostConstruct @@ -53,13 +54,10 @@ public class IotEmqxUpstreamProtocol { } try { - // 1. 初始化 Vertx 实例 - this.vertx = Vertx.vertx(); - - // 2. 启动 MQTT 客户端 + // 1. 启动 MQTT 客户端 startMqttClient(); - // 3. 标记服务为运行状态 + // 2. 标记服务为运行状态 isRunning = true; log.info("[start][IoT 网关 EMQX 协议启动成功]"); } catch (Exception e) { @@ -67,10 +65,16 @@ public class IotEmqxUpstreamProtocol { stop(); // 异步关闭应用 - // TODO haohao:是不是不用 sleep 也行哈? Thread shutdownThread = new Thread(() -> { - ThreadUtil.sleep(1000); - log.error("[start][由于 MQTT 连接失败,正在关闭应用]"); + try { + // 确保日志输出完成,使用更优雅的方式 + log.error("[start][由于 MQTT 连接失败,正在关闭应用]"); + // 等待日志输出完成 + Thread.sleep(1000); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + log.warn("[start][应用关闭被中断]"); + } System.exit(1); }); shutdownThread.setDaemon(true); @@ -90,16 +94,7 @@ public class IotEmqxUpstreamProtocol { // 1. 停止 MQTT 客户端 stopMqttClient(); - // 2. 关闭 Vertx 实例 - if (vertx != null) { - try { - vertx.close(); - } catch (Exception e) { - log.warn("[stop][关闭 Vertx 实例失败]", e); - } - } - - // 3. 标记服务为停止状态 + // 2. 标记服务为停止状态 isRunning = false; log.info("[stop][IoT 网关 MQTT 协议服务已停止]"); } @@ -147,7 +142,7 @@ public class IotEmqxUpstreamProtocol { // 2. 等待连接结果 try { - // TODO @haohao:想了下,timeout 可以不设置,全靠 mqttclient 的超时时间? + // 应用层超时控制:防止启动过程无限阻塞,与MQTT客户端的网络超时是不同层次的控制 boolean awaitResult = latch.await(10, java.util.concurrent.TimeUnit.SECONDS); if (!awaitResult) { log.error("[connectMqttSync][等待连接结果超时]"); diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java index b1ecfde58d..da500835d0 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java @@ -54,7 +54,8 @@ public class IotEmqxDownstreamHandler { return; } // 2.2 构建载荷 - byte[] payload = deviceMessageService.encodeDeviceMessage(message, deviceInfo.getProductKey(), deviceInfo.getDeviceName()); + byte[] payload = deviceMessageService.encodeDeviceMessage(message, deviceInfo.getProductKey(), + deviceInfo.getDeviceName()); // 2.3 发布消息 protocol.publishMessage(topic, payload); } @@ -78,20 +79,54 @@ public class IotEmqxDownstreamHandler { // 2. 根据消息方法和回复状态,构建 topic boolean isReply = IotDeviceMessageUtils.isReplyMessage(message); - // TODO @芋艿:需要添加对应的 Topic,所以需要先判断消息方法类型 - // TODO @haohao:基于 method,然后逆推对应的 topic,可以哇?约定好~ - // 根据消息方法和回复状态构建对应的主题 + // 3. 根据消息方法类型构建对应的主题 switch (methodEnum) { case PROPERTY_POST: + // 属性上报:只支持回复消息(下行) if (isReply) { return IotMqttTopicUtils.buildPropertyPostReplyTopic(productKey, deviceName); } break; + case PROPERTY_SET: + // 属性设置:只支持非回复消息(下行) if (!isReply) { return IotMqttTopicUtils.buildPropertySetTopic(productKey, deviceName); } break; + + case EVENT_POST: + // 事件上报:只支持回复消息(下行) + if (isReply) { + String identifier = IotDeviceMessageUtils.getIdentifier(message); + if (StrUtil.isNotBlank(identifier)) { + return IotMqttTopicUtils.buildEventPostReplyTopic(productKey, deviceName, identifier); + } + } + break; + + case SERVICE_INVOKE: + // 服务调用:支持请求和回复 + String serviceIdentifier = IotDeviceMessageUtils.getIdentifier(message); + if (StrUtil.isNotBlank(serviceIdentifier)) { + if (isReply) { + return IotMqttTopicUtils.buildServiceReplyTopic(productKey, deviceName, serviceIdentifier); + } else { + return IotMqttTopicUtils.buildServiceTopic(productKey, deviceName, serviceIdentifier); + } + } + break; + + case CONFIG_PUSH: + // 配置推送:平台向设备推送配置(下行请求),设备回复确认(上行回复) + if (!isReply) { + return IotMqttTopicUtils.buildConfigPushTopic(productKey, deviceName); + } + break; + + default: + log.warn("[buildTopicByMethod][未处理的消息方法: {}]", methodEnum); + break; } log.warn("[buildTopicByMethod][暂时不支持的下行消息: method={}, isReply={}]", diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java index 270e2717ab..1faf6aeeb8 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java @@ -91,4 +91,39 @@ public final class IotMqttTopicUtils { return buildDeviceTopicPrefix(productKey, deviceName) + SERVICE_TOPIC_PREFIX + serviceIdentifier; } + /** + * 构建设备服务调用回复主题 + * + * @param productKey 产品 Key + * @param deviceName 设备名称 + * @param serviceIdentifier 服务标识符 + * @return 完整的主题路径 + */ + public static String buildServiceReplyTopic(String productKey, String deviceName, String serviceIdentifier) { + return buildDeviceTopicPrefix(productKey, deviceName) + SERVICE_TOPIC_PREFIX + serviceIdentifier + "_reply"; + } + + /** + * 构建设备事件上报回复主题 + * + * @param productKey 产品 Key + * @param deviceName 设备名称 + * @param eventIdentifier 事件标识符 + * @return 完整的主题路径 + */ + public static String buildEventPostReplyTopic(String productKey, String deviceName, String eventIdentifier) { + return buildDeviceTopicPrefix(productKey, deviceName) + "/thing/event/" + eventIdentifier + "_reply"; + } + + /** + * 构建设备配置推送主题 + * + * @param productKey 产品 Key + * @param deviceName 设备名称 + * @return 完整的主题路径 + */ + public static String buildConfigPushTopic(String productKey, String deviceName) { + return buildDeviceTopicPrefix(productKey, deviceName) + "/thing/config/push"; + } + } \ No newline at end of file From d783890b7c21534e28ba3050adf633acaffd12df Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 29 Jun 2025 20:49:51 +0800 Subject: [PATCH 23/33] =?UTF-8?q?review=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E4=B8=BA=20EMQX=20=E5=8D=8F?= =?UTF-8?q?=E8=AE=AE=E6=B7=BB=E5=8A=A0=20=E5=85=B1=E4=BA=AB=20=E7=9A=84=20?= =?UTF-8?q?Vertx?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/gateway/protocol/emqx/IotEmqxUpstreamProtocol.java | 2 +- .../gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/IotEmqxUpstreamProtocol.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/IotEmqxUpstreamProtocol.java index fef3ce1723..9e6631af64 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/IotEmqxUpstreamProtocol.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/IotEmqxUpstreamProtocol.java @@ -31,7 +31,7 @@ public class IotEmqxUpstreamProtocol { private volatile boolean isRunning = false; - private Vertx vertx; + private final Vertx vertx; @Getter private final String serverId; diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java index da500835d0..14995c4384 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java @@ -79,6 +79,7 @@ public class IotEmqxDownstreamHandler { // 2. 根据消息方法和回复状态,构建 topic boolean isReply = IotDeviceMessageUtils.isReplyMessage(message); + // TODO @芋艿:看看基于 message 的 method 去反向推导; // 3. 根据消息方法类型构建对应的主题 switch (methodEnum) { case PROPERTY_POST: @@ -96,6 +97,7 @@ public class IotEmqxDownstreamHandler { break; case EVENT_POST: + // TODO @haohao:不用 eventIdentifier 拼接哈,直接 data 里面,有 identifier 字段 // 事件上报:只支持回复消息(下行) if (isReply) { String identifier = IotDeviceMessageUtils.getIdentifier(message); @@ -107,6 +109,7 @@ public class IotEmqxDownstreamHandler { case SERVICE_INVOKE: // 服务调用:支持请求和回复 + // TODO @haohao:不用 serviceIdentifier 拼接哈,直接 data 里面,有 identifier 字段 String serviceIdentifier = IotDeviceMessageUtils.getIdentifier(message); if (StrUtil.isNotBlank(serviceIdentifier)) { if (isReply) { From dd4027239e9f00917f4125509c38a17fe3aa9cd0 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 29 Jun 2025 20:50:56 +0800 Subject: [PATCH 24/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E6=96=B0=E5=A2=9E=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E5=BA=8F=E5=88=97=E5=8F=B7=E5=94=AF=E4=B8=80=E6=80=A7=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=EF=BC=8C=E6=B7=BB=E5=8A=A0=E5=BA=8F=E5=88=97=E5=8F=B7?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/dal/mysql/device/IotDeviceMapper.java | 4 ++ .../module/iot/enums/ErrorCodeConstants.java | 1 + .../iot/service/device/IotDeviceService.java | 15 +------ .../service/device/IotDeviceServiceImpl.java | 43 ++++++++++--------- 4 files changed, 28 insertions(+), 35 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index 7cc7d5de81..5f3dc56e04 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -81,6 +81,10 @@ public interface IotDeviceMapper extends BaseMapperX { .in(IotDeviceDO::getDeviceName, deviceNames)); } + default IotDeviceDO selectBySerialNumber(String serialNumber) { + return selectOne(IotDeviceDO::getSerialNumber, serialNumber); + } + /** * 查询指定产品下的设备数量 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 1546f8a043..8e445bf540 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -32,6 +32,7 @@ public interface ErrorCodeConstants { ErrorCode DEVICE_NOT_GATEWAY = new ErrorCode(1_050_003_005, "设备不是网关设备"); ErrorCode DEVICE_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_050_003_006, "导入设备数据不能为空!"); ErrorCode DEVICE_DOWNSTREAM_FAILED_SERVER_ID_NULL = new ErrorCode(1_050_003_007, "下行设备消息失败,原因:设备未连接网关"); + ErrorCode DEVICE_SERIAL_NUMBER_EXISTS = new ErrorCode(1_050_003_008, "设备序列号已存在,序列号必须全局唯一"); // ========== 产品分类 1-050-004-000 ========== ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_050_004_000, "产品分类不存在"); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index c3a6868945..7bfb9800d0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -3,10 +3,9 @@ package cn.iocoder.yudao.module.iot.service.device; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*; import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import jakarta.validation.Valid; -import jakarta.validation.constraints.NotEmpty; import javax.annotation.Nullable; import java.time.LocalDateTime; @@ -30,18 +29,6 @@ public interface IotDeviceService { */ Long createDevice(@Valid IotDeviceSaveReqVO createReqVO); - /** - * 【设备注册】创建设备 - * - * @param productKey 产品标识 - * @param deviceName 设备名称 - * @param gatewayId 网关设备 ID - * @return 设备 - */ - IotDeviceDO createDevice(@NotEmpty(message = "产品标识不能为空") String productKey, - @NotEmpty(message = "设备名称不能为空") String deviceName, - Long gatewayId); - /** * 更新设备 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index ccbd652d6e..be0762e725 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -73,6 +73,8 @@ public class IotDeviceServiceImpl implements IotDeviceService { createReqVO.getGatewayId(), product); // 1.3 校验分组存在 deviceGroupService.validateDeviceGroupExists(createReqVO.getGroupIds()); + // 1.4 校验设备序列号全局唯一 + validateSerialNumberUnique(createReqVO.getSerialNumber(), null); // 2. 插入到数据库 IotDeviceDO device = BeanUtils.toBean(createReqVO, IotDeviceDO.class); @@ -81,34 +83,14 @@ public class IotDeviceServiceImpl implements IotDeviceService { return device.getId(); } - @Override - public IotDeviceDO createDevice(String productKey, String deviceName, Long gatewayId) { - // 1.1 校验产品是否存在 - IotProductDO product = TenantUtils.executeIgnore(() -> productService.getProductByProductKey(productKey)); - if (product == null) { - throw exception(PRODUCT_NOT_EXISTS); - } - return TenantUtils.execute(product.getTenantId(), () -> { - // 1.2 校验设备名称在同一产品下是否唯一 - validateCreateDeviceParam(productKey, deviceName, gatewayId, product); - - // 2. 插入到数据库 - IotDeviceDO device = new IotDeviceDO().setDeviceName(deviceName).setGatewayId(gatewayId); - initDevice(device, product); - deviceMapper.insert(device); - return device; - }); - } - private void validateCreateDeviceParam(String productKey, String deviceName, Long gatewayId, IotProductDO product) { + // 校验设备名称在同一产品下是否唯一 TenantUtils.executeIgnore(() -> { - // 校验设备名称在同一产品下是否唯一 if (deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName) != null) { throw exception(DEVICE_NAME_EXISTS); } }); - // 校验父设备是否为合法网关 if (IotProductDeviceTypeEnum.isGatewaySub(product.getDeviceType()) && gatewayId != null) { @@ -116,6 +98,22 @@ public class IotDeviceServiceImpl implements IotDeviceService { } } + /** + * 校验设备序列号全局唯一性 + * + * @param serialNumber 设备序列号 + * @param excludeId 排除的设备ID(用于更新时排除自身) + */ + private void validateSerialNumberUnique(String serialNumber, Long excludeId) { + if (StrUtil.isBlank(serialNumber)) { + return; + } + IotDeviceDO existDevice = deviceMapper.selectBySerialNumber(serialNumber); + if (existDevice != null && ObjUtil.notEqual(existDevice.getId(), excludeId)) { + throw exception(DEVICE_SERIAL_NUMBER_EXISTS); + } + } + private void initDevice(IotDeviceDO device, IotProductDO product) { device.setProductId(product.getId()).setProductKey(product.getProductKey()) .setDeviceType(product.getDeviceType()); @@ -137,6 +135,8 @@ public class IotDeviceServiceImpl implements IotDeviceService { } // 1.3 校验分组存在 deviceGroupService.validateDeviceGroupExists(updateReqVO.getGroupIds()); + // 1.4 校验设备序列号全局唯一 + validateSerialNumberUnique(updateReqVO.getSerialNumber(), updateReqVO.getId()); // 2. 更新到数据库 IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class); @@ -417,6 +417,7 @@ public class IotDeviceServiceImpl implements IotDeviceService { devices.forEach(this::deleteDeviceCache); } + @SuppressWarnings("unused") @Caching(evict = { @CacheEvict(value = RedisKeyConstants.DEVICE, key = "#device.id"), @CacheEvict(value = RedisKeyConstants.DEVICE, key = "#device.productKey + '_' + #device.deviceName") From 0593dbc9a00fe2083c20756b448954a07d3b164c Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 29 Jun 2025 22:00:30 +0800 Subject: [PATCH 25/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E6=96=B0=E5=A2=9E=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E5=BA=8F=E5=88=97=E5=8F=B7=E5=94=AF=E4=B8=80=E6=80=A7=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=EF=BC=8C=E6=B7=BB=E5=8A=A0=E5=BA=8F=E5=88=97=E5=8F=B7?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/iot/service/device/IotDeviceServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index be0762e725..30f7b26878 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -102,7 +102,7 @@ public class IotDeviceServiceImpl implements IotDeviceService { * 校验设备序列号全局唯一性 * * @param serialNumber 设备序列号 - * @param excludeId 排除的设备ID(用于更新时排除自身) + * @param excludeId 排除的设备编号(用于更新时排除自身) */ private void validateSerialNumberUnique(String serialNumber, Long excludeId) { if (StrUtil.isBlank(serialNumber)) { From a5a3aea522a13300973dd343aafa20a16c80ba0a Mon Sep 17 00:00:00 2001 From: haohao <1036606149@qq.com> Date: Sun, 29 Jun 2025 22:46:38 +0800 Subject: [PATCH 26/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E6=96=B0=E5=A2=9E=20TCP=20=E5=8D=8F?= =?UTF-8?q?=E8=AE=AE=E6=94=AF=E6=8C=81=EF=BC=8C=E6=B7=BB=E5=8A=A0=20TCP=20?= =?UTF-8?q?=E8=BF=9E=E6=8E=A5=E7=AE=A1=E7=90=86=E3=80=81=E4=B8=8A=E4=B8=8B?= =?UTF-8?q?=E8=A1=8C=E6=B6=88=E6=81=AF=E5=A4=84=E7=90=86=E5=8F=8A=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/IotGatewayConfiguration.java | 45 +++++- .../gateway/config/IotGatewayProperties.java | 24 +++ .../emqx/router/IotEmqxDownstreamHandler.java | 19 +-- .../protocol/tcp/IotTcpConnectionManager.java | 62 ++++++++ .../tcp/IotTcpDownstreamSubscriber.java | 64 ++++++++ .../protocol/tcp/IotTcpUpstreamProtocol.java | 71 +++++++++ .../tcp/router/IotTcpConnectionHandler.java | 142 ++++++++++++++++++ .../tcp/router/IotTcpDownstreamHandler.java | 49 ++++++ .../iot/gateway/util/IotMqttTopicUtils.java | 75 ++++----- .../src/main/resources/application-local.yaml | 10 +- .../src/main/resources/application.yaml | 5 + 11 files changed, 510 insertions(+), 56 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpConnectionManager.java create mode 100644 yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpDownstreamSubscriber.java create mode 100644 yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpUpstreamProtocol.java create mode 100644 yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpConnectionHandler.java create mode 100644 yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpDownstreamHandler.java diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java index 11cbfca270..273a55f91f 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java @@ -1,11 +1,18 @@ package cn.iocoder.yudao.module.iot.gateway.config; +import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi; import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; import cn.iocoder.yudao.module.iot.gateway.protocol.emqx.IotEmqxAuthEventProtocol; import cn.iocoder.yudao.module.iot.gateway.protocol.emqx.IotEmqxDownstreamSubscriber; import cn.iocoder.yudao.module.iot.gateway.protocol.emqx.IotEmqxUpstreamProtocol; import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpDownstreamSubscriber; import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpUpstreamProtocol; +import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.IotTcpConnectionManager; +import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.router.IotTcpDownstreamHandler; +import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.IotTcpDownstreamSubscriber; +import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.IotTcpUpstreamProtocol; +import cn.iocoder.yudao.module.iot.gateway.service.device.IotDeviceService; +import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService; import io.vertx.core.Vertx; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -33,7 +40,7 @@ public class IotGatewayConfiguration { @Bean public IotHttpDownstreamSubscriber iotHttpDownstreamSubscriber(IotHttpUpstreamProtocol httpUpstreamProtocol, - IotMessageBus messageBus) { + IotMessageBus messageBus) { return new IotHttpDownstreamSubscriber(httpUpstreamProtocol, messageBus); } } @@ -53,21 +60,51 @@ public class IotGatewayConfiguration { @Bean public IotEmqxAuthEventProtocol iotEmqxAuthEventProtocol(IotGatewayProperties gatewayProperties, - Vertx emqxVertx) { + Vertx emqxVertx) { return new IotEmqxAuthEventProtocol(gatewayProperties.getProtocol().getEmqx(), emqxVertx); } @Bean public IotEmqxUpstreamProtocol iotEmqxUpstreamProtocol(IotGatewayProperties gatewayProperties, - Vertx emqxVertx) { + Vertx emqxVertx) { return new IotEmqxUpstreamProtocol(gatewayProperties.getProtocol().getEmqx(), emqxVertx); } @Bean public IotEmqxDownstreamSubscriber iotEmqxDownstreamSubscriber(IotEmqxUpstreamProtocol mqttUpstreamProtocol, - IotMessageBus messageBus) { + IotMessageBus messageBus) { return new IotEmqxDownstreamSubscriber(mqttUpstreamProtocol, messageBus); } } + /** + * IoT 网关 TCP 协议配置类 + */ + @Configuration + @ConditionalOnProperty(prefix = "yudao.iot.gateway.protocol.tcp", name = "enabled", havingValue = "true") + @Slf4j + public static class TcpProtocolConfiguration { + + @Bean + public Vertx tcpVertx() { + return Vertx.vertx(); + } + + @Bean + public IotTcpUpstreamProtocol iotTcpUpstreamProtocol(Vertx tcpVertx, IotGatewayProperties gatewayProperties, + IotTcpConnectionManager connectionManager, IotDeviceMessageService messageService, + IotDeviceService deviceService, IotDeviceCommonApi deviceApi) { + return new IotTcpUpstreamProtocol(tcpVertx, gatewayProperties, connectionManager, + messageService, deviceService, deviceApi); + } + + @Bean + public IotTcpDownstreamSubscriber iotTcpDownstreamSubscriber(IotTcpUpstreamProtocol tcpUpstreamProtocol, + IotMessageBus messageBus, + IotTcpDownstreamHandler downstreamHandler) { + return new IotTcpDownstreamSubscriber(tcpUpstreamProtocol, messageBus, downstreamHandler); + } + + } + } diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayProperties.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayProperties.java index 852b2e67b4..4d1d67afe1 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayProperties.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayProperties.java @@ -78,6 +78,11 @@ public class IotGatewayProperties { */ private EmqxProperties emqx; + /** + * TCP 组件配置 + */ + private TcpProperties tcp; + } @Data @@ -95,6 +100,25 @@ public class IotGatewayProperties { } + @Data + public static class TcpProperties { + + /** + * 是否开启 + */ + @NotNull(message = "是否开启不能为空") + private Boolean enabled; + /** + * 服务端口 + */ + private Integer serverPort; + /** + * 服务主机 + */ + private String serverHost; + + } + @Data public static class EmqxProperties { diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java index 14995c4384..c5d77d2f46 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java @@ -97,28 +97,19 @@ public class IotEmqxDownstreamHandler { break; case EVENT_POST: - // TODO @haohao:不用 eventIdentifier 拼接哈,直接 data 里面,有 identifier 字段 // 事件上报:只支持回复消息(下行) if (isReply) { - String identifier = IotDeviceMessageUtils.getIdentifier(message); - if (StrUtil.isNotBlank(identifier)) { - return IotMqttTopicUtils.buildEventPostReplyTopic(productKey, deviceName, identifier); - } + return IotMqttTopicUtils.buildEventPostReplyTopicGeneric(productKey, deviceName); } break; case SERVICE_INVOKE: // 服务调用:支持请求和回复 - // TODO @haohao:不用 serviceIdentifier 拼接哈,直接 data 里面,有 identifier 字段 - String serviceIdentifier = IotDeviceMessageUtils.getIdentifier(message); - if (StrUtil.isNotBlank(serviceIdentifier)) { - if (isReply) { - return IotMqttTopicUtils.buildServiceReplyTopic(productKey, deviceName, serviceIdentifier); - } else { - return IotMqttTopicUtils.buildServiceTopic(productKey, deviceName, serviceIdentifier); - } + if (isReply) { + return IotMqttTopicUtils.buildServiceReplyTopicGeneric(productKey, deviceName); + } else { + return IotMqttTopicUtils.buildServiceTopicGeneric(productKey, deviceName); } - break; case CONFIG_PUSH: // 配置推送:平台向设备推送配置(下行请求),设备回复确认(上行回复) diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpConnectionManager.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpConnectionManager.java new file mode 100644 index 0000000000..97d1e43b3d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpConnectionManager.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.iot.gateway.protocol.tcp; + +import io.vertx.core.net.NetSocket; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * IoT TCP 连接管理器 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class IotTcpConnectionManager { + + /** + * 连接集合 + * + * key:设备唯一标识 + */ + private final ConcurrentMap connectionMap = new ConcurrentHashMap<>(); + + /** + * 添加一个新连接 + * + * @param deviceId 设备唯一标识 + * @param socket Netty Channel + */ + public void addConnection(String deviceId, NetSocket socket) { + log.info("[addConnection][设备({}) 连接({})]", deviceId, socket.remoteAddress()); + connectionMap.put(deviceId, socket); + } + + /** + * 根据设备 ID 获取连接 + * + * @param deviceId 设备 ID + * @return 连接 + */ + public NetSocket getConnection(String deviceId) { + return connectionMap.get(deviceId); + } + + /** + * 移除指定连接 + * + * @param socket Netty Channel + */ + public void removeConnection(NetSocket socket) { + connectionMap.entrySet().stream() + .filter(entry -> entry.getValue().equals(socket)) + .findFirst() + .ifPresent(entry -> { + log.info("[removeConnection][设备({}) 断开连接({})]", entry.getKey(), socket.remoteAddress()); + connectionMap.remove(entry.getKey()); + }); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpDownstreamSubscriber.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpDownstreamSubscriber.java new file mode 100644 index 0000000000..f324d45438 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpDownstreamSubscriber.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.iot.gateway.protocol.tcp; + +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber; +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; +import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.router.IotTcpDownstreamHandler; +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * IoT 网关 TCP 订阅者:接收下行给设备的消息 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Slf4j +public class IotTcpDownstreamSubscriber implements IotMessageSubscriber { + + private final IotTcpUpstreamProtocol protocol; + + private final IotMessageBus messageBus; + + private final IotTcpDownstreamHandler downstreamHandler; + + @PostConstruct + public void init() { + messageBus.register(this); + } + + @Override + public String getTopic() { + return IotDeviceMessageUtils.buildMessageBusGatewayDeviceMessageTopic(protocol.getServerId()); + } + + @Override + public String getGroup() { + // 保证点对点消费,需要保证独立的 Group,所以使用 Topic 作为 Group + return getTopic(); + } + + @Override + public void onMessage(IotDeviceMessage message) { + log.debug("[onMessage][接收到下行消息, messageId: {}, method: {}, deviceId: {}]", + message.getId(), message.getMethod(), message.getDeviceId()); + try { + // 1. 校验 + String method = message.getMethod(); + if (method == null) { + log.warn("[onMessage][消息方法为空, messageId: {}, deviceId: {}]", + message.getId(), message.getDeviceId()); + return; + } + + // 2. 处理下行消息 + downstreamHandler.handle(message); + } catch (Exception e) { + log.error("[onMessage][处理下行消息失败, messageId: {}, method: {}, deviceId: {}]", + message.getId(), message.getMethod(), message.getDeviceId(), e); + } + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpUpstreamProtocol.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpUpstreamProtocol.java new file mode 100644 index 0000000000..f6bee94b5a --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpUpstreamProtocol.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.iot.gateway.protocol.tcp; + +import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi; +import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; +import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties; +import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.router.IotTcpConnectionHandler; +import cn.iocoder.yudao.module.iot.gateway.service.device.IotDeviceService; +import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService; +import io.vertx.core.Vertx; +import io.vertx.core.net.NetServer; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * IoT 网关 TCP 协议:接收设备上行消息 + * + * @author 芋道源码 + */ +@Slf4j +@RequiredArgsConstructor +public class IotTcpUpstreamProtocol { + + private final Vertx vertx; + + private final IotGatewayProperties gatewayProperties; + + private final IotTcpConnectionManager connectionManager; + + private final IotDeviceMessageService messageService; + + private final IotDeviceService deviceService; + + private final IotDeviceCommonApi deviceApi; + + @Getter + private String serverId; + + private NetServer netServer; + + @PostConstruct + public void start() { + // 1. 初始化参数 + IotGatewayProperties.TcpProperties tcpProperties = gatewayProperties.getProtocol().getTcp(); + this.serverId = IotDeviceMessageUtils.generateServerId(tcpProperties.getServerPort()); + + // 2. 创建 TCP 服务器 + netServer = vertx.createNetServer(); + netServer.connectHandler(socket -> { + new IotTcpConnectionHandler(socket, connectionManager, + messageService, deviceService, deviceApi, serverId).start(); + }); + + // 3. 启动 TCP 服务器 + netServer.listen(tcpProperties.getServerPort(), tcpProperties.getServerHost()) + .onSuccess(server -> log.info("[start][IoT 网关 TCP 服务启动成功,端口:{}]", server.actualPort())) + .onFailure(e -> log.error("[start][IoT 网关 TCP 服务启动失败]", e)); + } + + @PreDestroy + public void stop() { + if (netServer != null) { + netServer.close() + .onSuccess(v -> log.info("[stop][IoT 网关 TCP 服务已停止]")) + .onFailure(e -> log.error("[stop][IoT 网关 TCP 服务停止失败]", e)); + } + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpConnectionHandler.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpConnectionHandler.java new file mode 100644 index 0000000000..c1d9c9e301 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpConnectionHandler.java @@ -0,0 +1,142 @@ +package cn.iocoder.yudao.module.iot.gateway.protocol.tcp.router; + +import cn.hutool.core.util.BooleanUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi; +import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO; +import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceRespDTO; +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.IotTcpConnectionManager; +import cn.iocoder.yudao.module.iot.gateway.service.device.IotDeviceService; +import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService; +import io.vertx.core.Handler; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.net.NetSocket; +import io.vertx.core.parsetools.RecordParser; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * IoT TCP 连接处理器 + *

+ * 核心负责: + * 1. 【认证】创建连接后,设备需要发送认证消息,认证通过后,才能进行后续的通信 + * 2. 【消息处理】接收设备发送的消息,解码后,发送到消息队列 + * 3. 【断开】设备断开连接后,清理资源 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Slf4j +public class IotTcpConnectionHandler implements Handler { + + private final NetSocket socket; + /** + * 是否已认证 + */ + private boolean authenticated = false; + /** + * 设备信息 + */ + private IotDeviceRespDTO device; + + private final IotTcpConnectionManager connectionManager; + + private final IotDeviceMessageService messageService; + + private final IotDeviceService deviceService; + + private final IotDeviceCommonApi deviceApi; + + private final String serverId; + + public void start() { + // 1. 设置解析器 + final RecordParser parser = RecordParser.newDelimited("\n", this); + socket.handler(parser); + + // 2. 设置处理器 + socket.closeHandler(v -> handleConnectionClose()); + socket.exceptionHandler(this::handleException); + } + + @Override + public void handle(Buffer buffer) { + log.info("[handle][接收到数据: {}]", buffer); + try { + // 1. 处理认证 + if (!authenticated) { + handleAuthentication(buffer); + return; + } + // 2. 处理消息 + handleMessage(buffer); + } catch (Exception e) { + log.error("[handle][处理异常]", e); + socket.close(); + } + } + + private void handleAuthentication(Buffer buffer) { + // 1. 解析认证信息 + // TODO @芋艿:这里的认证协议,需要和设备端约定。默认为 productKey,deviceName,password + String[] parts = buffer.toString().split(","); + if (parts.length != 3) { + log.error("[handleAuthentication][认证信息({})格式不正确]", buffer); + socket.close(); + return; + } + String productKey = parts[0]; + String deviceName = parts[1]; + String password = parts[2]; + + // 2. 执行认证 + CommonResult authResult = deviceApi.authDevice(new IotDeviceAuthReqDTO() + .setClientId(socket.remoteAddress().toString()).setUsername(productKey + "/" + deviceName) + .setPassword(password)); + if (authResult.isError() || !BooleanUtil.isTrue(authResult.getData())) { + log.error("[handleAuthentication][认证失败,productKey({}) deviceName({}) password({})]", productKey, deviceName, + password); + socket.close(); + return; + } + + // 3. 认证成功 + this.authenticated = true; + this.device = deviceService.getDeviceFromCache(productKey, deviceName); + connectionManager.addConnection(String.valueOf(device.getId()), socket); + + // 4. 发送上线消息 + IotDeviceMessage message = IotDeviceMessage.buildStateUpdateOnline(); + messageService.sendDeviceMessage(message, productKey, deviceName, serverId); + log.info("[handleAuthentication][认证成功]"); + } + + private void handleMessage(Buffer buffer) { + // 1. 解码消息 + IotDeviceMessage message = messageService.decodeDeviceMessage(buffer.getBytes(), + device.getProductKey(), device.getDeviceName()); + if (message == null) { + log.warn("[handleMessage][解码消息失败]"); + return; + } + // 2. 发送消息到队列 + messageService.sendDeviceMessage(message, device.getProductKey(), device.getDeviceName(), serverId); + } + + private void handleConnectionClose() { + // 1. 移除连接 + connectionManager.removeConnection(socket); + // 2. 发送离线消息 + if (device != null) { + IotDeviceMessage message = IotDeviceMessage.buildStateOffline(); + messageService.sendDeviceMessage(message, device.getProductKey(), device.getDeviceName(), serverId); + } + } + + private void handleException(Throwable e) { + log.error("[handleException][连接({}) 发生异常]", socket.remoteAddress(), e); + socket.close(); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpDownstreamHandler.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpDownstreamHandler.java new file mode 100644 index 0000000000..cb7e7c0665 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpDownstreamHandler.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.iot.gateway.protocol.tcp.router; + +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.IotTcpConnectionManager; +import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.net.NetSocket; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * IoT 网关 TCP 下行消息处理器 + *

+ * 从消息总线接收到下行消息,然后发布到 TCP 连接,从而被设备所接收 + * + * @author 芋道源码 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class IotTcpDownstreamHandler { + + private final IotTcpConnectionManager connectionManager; + private final IotDeviceMessageService messageService; + + /** + * 处理下行消息 + * + * @param message 设备消息 + */ + public void handle(IotDeviceMessage message) { + // 1. 获取设备对应的连接 + NetSocket socket = connectionManager.getConnection(String.valueOf(message.getDeviceId())); + if (socket == null) { + log.error("[handle][设备({})的连接不存在]", message.getDeviceId()); + return; + } + + // 2. 编码消息 + byte[] bytes = messageService.encodeDeviceMessage(message, null, null); + + // 3. 发送消息 + socket.write(Buffer.buffer(bytes)); + // TODO @芋艿:这里的换行符,需要和设备端约定 + socket.write("\n"); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java index 1faf6aeeb8..d1f1621264 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java @@ -79,42 +79,6 @@ public final class IotMqttTopicUtils { return buildDeviceTopicPrefix(productKey, deviceName) + "/thing/property/post_reply"; } - /** - * 构建设备服务调用主题 - * - * @param productKey 产品 Key - * @param deviceName 设备名称 - * @param serviceIdentifier 服务标识符 - * @return 完整的主题路径 - */ - public static String buildServiceTopic(String productKey, String deviceName, String serviceIdentifier) { - return buildDeviceTopicPrefix(productKey, deviceName) + SERVICE_TOPIC_PREFIX + serviceIdentifier; - } - - /** - * 构建设备服务调用回复主题 - * - * @param productKey 产品 Key - * @param deviceName 设备名称 - * @param serviceIdentifier 服务标识符 - * @return 完整的主题路径 - */ - public static String buildServiceReplyTopic(String productKey, String deviceName, String serviceIdentifier) { - return buildDeviceTopicPrefix(productKey, deviceName) + SERVICE_TOPIC_PREFIX + serviceIdentifier + "_reply"; - } - - /** - * 构建设备事件上报回复主题 - * - * @param productKey 产品 Key - * @param deviceName 设备名称 - * @param eventIdentifier 事件标识符 - * @return 完整的主题路径 - */ - public static String buildEventPostReplyTopic(String productKey, String deviceName, String eventIdentifier) { - return buildDeviceTopicPrefix(productKey, deviceName) + "/thing/event/" + eventIdentifier + "_reply"; - } - /** * 构建设备配置推送主题 * @@ -126,4 +90,43 @@ public final class IotMqttTopicUtils { return buildDeviceTopicPrefix(productKey, deviceName) + "/thing/config/push"; } + /** + * 构建设备事件上报通用回复主题 + *

+ * 不包含具体的事件标识符,事件标识符通过消息 data 中的 identifier 字段传递 + * + * @param productKey 产品 Key + * @param deviceName 设备名称 + * @return 完整的主题路径 + */ + public static String buildEventPostReplyTopicGeneric(String productKey, String deviceName) { + return buildDeviceTopicPrefix(productKey, deviceName) + "/thing/event/post_reply"; + } + + /** + * 构建设备服务调用通用主题 + *

+ * 不包含具体的服务标识符,服务标识符通过消息 data 中的 identifier 字段传递 + * + * @param productKey 产品 Key + * @param deviceName 设备名称 + * @return 完整的主题路径 + */ + public static String buildServiceTopicGeneric(String productKey, String deviceName) { + return buildDeviceTopicPrefix(productKey, deviceName) + "/thing/service/invoke"; + } + + /** + * 构建设备服务调用通用回复主题 + *

+ * 不包含具体的服务标识符,服务标识符通过消息 data 中的 identifier 字段传递 + * + * @param productKey 产品 Key + * @param deviceName 设备名称 + * @return 完整的主题路径 + */ + public static String buildServiceReplyTopicGeneric(String productKey, String deviceName) { + return buildDeviceTopicPrefix(productKey, deviceName) + "/thing/service/invoke_reply"; + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application-local.yaml b/yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application-local.yaml index ab3eda8155..1ad0e6f9e2 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application-local.yaml +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application-local.yaml @@ -1,5 +1,4 @@ # ==================== IoT 网关本地开发环境配置 ==================== - --- #################### 消息队列相关 #################### # rocketmq 配置项,对应 RocketMQProperties 配置类 @@ -41,6 +40,13 @@ yudao: mqtt-ssl: false # 是否开启 SSL mqtt-topics: - "/sys/#" # 系统主题 + # ==================================== + # 针对引入的 TCP 组件的配置 + # ==================================== + tcp: + enabled: true + server-port: 8093 + server-host: 0.0.0.0 # 消息总线配置 message-bus: @@ -52,7 +58,7 @@ yudao: logging: level: # 开发环境详细日志 - cn.iocoder.yudao.module.iot.gateway.protocol.mqtt: DEBUG + cn.iocoder.yudao.module.iot.gateway.protocol.emqx: DEBUG cn.iocoder.yudao.module.iot.gateway.protocol.http: DEBUG # MQTT 客户端日志 # io.vertx.mqtt: DEBUG \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml b/yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml index b12b2f73d7..e028d5ce7c 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml @@ -41,6 +41,11 @@ yudao: mqtt-ssl: false mqtt-topics: - "/sys/#" # 系统主题 + # ==================================== + # 针对引入的 TCP 组件的配置 + # ==================================== + tcp: + enabled: false # 消息总线配置 message-bus: From bf41d47fa843e29a7bbce04aa418bc539f6f2f52 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 30 Jun 2025 00:04:58 +0800 Subject: [PATCH 27/33] =?UTF-8?q?review=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E7=BD=91=E5=85=B3=20TCP=20=E7=9A=84?= =?UTF-8?q?=E6=8E=A5=E5=85=A5=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/gateway/config/IotGatewayConfiguration.java | 10 ++++++---- .../iot/gateway/config/IotGatewayProperties.java | 2 ++ .../protocol/emqx/router/IotEmqxDownstreamHandler.java | 7 +------ .../gateway/protocol/tcp/IotTcpConnectionManager.java | 2 ++ .../protocol/tcp/router/IotTcpConnectionHandler.java | 6 ++++++ .../protocol/tcp/router/IotTcpDownstreamHandler.java | 2 ++ .../module/iot/gateway/util/IotMqttTopicUtils.java | 2 ++ 7 files changed, 21 insertions(+), 10 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java index 273a55f91f..3481faead8 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java @@ -85,6 +85,7 @@ public class IotGatewayConfiguration { @Slf4j public static class TcpProtocolConfiguration { + // TODO @haohao:close @Bean public Vertx tcpVertx() { return Vertx.vertx(); @@ -92,16 +93,17 @@ public class IotGatewayConfiguration { @Bean public IotTcpUpstreamProtocol iotTcpUpstreamProtocol(Vertx tcpVertx, IotGatewayProperties gatewayProperties, - IotTcpConnectionManager connectionManager, IotDeviceMessageService messageService, - IotDeviceService deviceService, IotDeviceCommonApi deviceApi) { + IotTcpConnectionManager connectionManager, + IotDeviceMessageService messageService, + IotDeviceService deviceService, IotDeviceCommonApi deviceApi) { return new IotTcpUpstreamProtocol(tcpVertx, gatewayProperties, connectionManager, messageService, deviceService, deviceApi); } @Bean public IotTcpDownstreamSubscriber iotTcpDownstreamSubscriber(IotTcpUpstreamProtocol tcpUpstreamProtocol, - IotMessageBus messageBus, - IotTcpDownstreamHandler downstreamHandler) { + IotMessageBus messageBus, + IotTcpDownstreamHandler downstreamHandler) { return new IotTcpDownstreamSubscriber(tcpUpstreamProtocol, messageBus, downstreamHandler); } diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayProperties.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayProperties.java index 4d1d67afe1..461698c46c 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayProperties.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayProperties.java @@ -108,10 +108,12 @@ public class IotGatewayProperties { */ @NotNull(message = "是否开启不能为空") private Boolean enabled; + // TODO @haohao:加个默认值? /** * 服务端口 */ private Integer serverPort; + // TODO @haohao:应该不用?一般都监听 0.0.0.0 哈; /** * 服务主机 */ diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java index c5d77d2f46..7be33571b4 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java @@ -79,7 +79,7 @@ public class IotEmqxDownstreamHandler { // 2. 根据消息方法和回复状态,构建 topic boolean isReply = IotDeviceMessageUtils.isReplyMessage(message); - // TODO @芋艿:看看基于 message 的 method 去反向推导; + // TODO @haohao:看看基于 message 的 method 去反向推导; // 3. 根据消息方法类型构建对应的主题 switch (methodEnum) { case PROPERTY_POST: @@ -88,21 +88,18 @@ public class IotEmqxDownstreamHandler { return IotMqttTopicUtils.buildPropertyPostReplyTopic(productKey, deviceName); } break; - case PROPERTY_SET: // 属性设置:只支持非回复消息(下行) if (!isReply) { return IotMqttTopicUtils.buildPropertySetTopic(productKey, deviceName); } break; - case EVENT_POST: // 事件上报:只支持回复消息(下行) if (isReply) { return IotMqttTopicUtils.buildEventPostReplyTopicGeneric(productKey, deviceName); } break; - case SERVICE_INVOKE: // 服务调用:支持请求和回复 if (isReply) { @@ -110,14 +107,12 @@ public class IotEmqxDownstreamHandler { } else { return IotMqttTopicUtils.buildServiceTopicGeneric(productKey, deviceName); } - case CONFIG_PUSH: // 配置推送:平台向设备推送配置(下行请求),设备回复确认(上行回复) if (!isReply) { return IotMqttTopicUtils.buildConfigPushTopic(productKey, deviceName); } break; - default: log.warn("[buildTopicByMethod][未处理的消息方法: {}]", methodEnum); break; diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpConnectionManager.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpConnectionManager.java index 97d1e43b3d..a208e74e5d 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpConnectionManager.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/IotTcpConnectionManager.java @@ -16,6 +16,7 @@ import java.util.concurrent.ConcurrentMap; @Slf4j public class IotTcpConnectionManager { + // TODO @haohao:要考虑,相同设备,多次连接的情况哇? /** * 连接集合 * @@ -50,6 +51,7 @@ public class IotTcpConnectionManager { * @param socket Netty Channel */ public void removeConnection(NetSocket socket) { + // TODO @haohao:vertx 的 socket,有没办法设置一些属性,类似 netty 的;目的是,避免遍历 connectionMap 去操作哈; connectionMap.entrySet().stream() .filter(entry -> entry.getValue().equals(socket)) .findFirst() diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpConnectionHandler.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpConnectionHandler.java index c1d9c9e301..ff64f453da 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpConnectionHandler.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpConnectionHandler.java @@ -64,6 +64,7 @@ public class IotTcpConnectionHandler implements Handler { public void handle(Buffer buffer) { log.info("[handle][接收到数据: {}]", buffer); try { + // TODO @haohao:可以调研下,做个对比表格哈; // 1. 处理认证 if (!authenticated) { handleAuthentication(buffer); @@ -80,6 +81,11 @@ public class IotTcpConnectionHandler implements Handler { private void handleAuthentication(Buffer buffer) { // 1. 解析认证信息 // TODO @芋艿:这里的认证协议,需要和设备端约定。默认为 productKey,deviceName,password + // TODO @haohao:这里,要不也 json 解析?类似 http 是 { + // "clientId": "4aymZgOTOOCrDKRT.small", + // "username": "small&4aymZgOTOOCrDKRT", + // "password": "509e2b08f7598eb139d276388c600435913ba4c94cd0d50aebc5c0d1855bcb75" + //} String[] parts = buffer.toString().split(","); if (parts.length != 3) { log.error("[handleAuthentication][认证信息({})格式不正确]", buffer); diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpDownstreamHandler.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpDownstreamHandler.java index cb7e7c0665..a4dce318b7 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpDownstreamHandler.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/tcp/router/IotTcpDownstreamHandler.java @@ -22,6 +22,7 @@ import org.springframework.stereotype.Component; public class IotTcpDownstreamHandler { private final IotTcpConnectionManager connectionManager; + private final IotDeviceMessageService messageService; /** @@ -43,6 +44,7 @@ public class IotTcpDownstreamHandler { // 3. 发送消息 socket.write(Buffer.buffer(bytes)); // TODO @芋艿:这里的换行符,需要和设备端约定 + // TODO @haohao:tcp 要不定长?很少 \n 哈。然后有个 magic number;可以参考 dubbo rpc; socket.write("\n"); } diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java index d1f1621264..f2861581f5 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java @@ -16,6 +16,7 @@ public final class IotMqttTopicUtils { */ private static final String SYS_TOPIC_PREFIX = "/sys/"; + // TODO @haohao:这个要删除哇? /** * 服务调用主题前缀 */ @@ -36,6 +37,7 @@ public final class IotMqttTopicUtils { */ public static final String MQTT_EVENT_PATH = "/mqtt/event"; + // TODO @haohao:这个要删除哇? /** * MQTT 授权接口路径(预留) * 对应 EMQX HTTP 授权插件的授权检查接口 From 3ca4cf265a0323bc06768a5be88955b1a9c1cdda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Mon, 30 Jun 2025 09:50:18 +0800 Subject: [PATCH 28/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E4=BC=98=E5=8C=96=E6=A0=B9=E6=8D=AE?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=96=B9=E6=B3=95=E5=92=8C=E5=9B=9E=E5=A4=8D?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=9E=84=E5=BB=BA=E4=B8=BB=E9=A2=98=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../emqx/router/IotEmqxDownstreamHandler.java | 54 +-------- .../iot/gateway/util/IotMqttTopicUtils.java | 104 +++--------------- 2 files changed, 20 insertions(+), 138 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java index 7be33571b4..6c451fd5c0 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.iot.gateway.protocol.emqx.router; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceRespDTO; -import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; import cn.iocoder.yudao.module.iot.gateway.protocol.emqx.IotEmqxUpstreamProtocol; @@ -69,58 +68,11 @@ public class IotEmqxDownstreamHandler { * @return 构建的主题,如果方法不支持返回 null */ private String buildTopicByMethod(IotDeviceMessage message, String productKey, String deviceName) { - // 1. 解析消息方法 - IotDeviceMessageMethodEnum methodEnum = IotDeviceMessageMethodEnum.of(message.getMethod()); - if (methodEnum == null) { - log.warn("[buildTopicByMethod][未知的消息方法: {}]", message.getMethod()); - return null; - } - - // 2. 根据消息方法和回复状态,构建 topic + // 1. 判断是否为回复消息 boolean isReply = IotDeviceMessageUtils.isReplyMessage(message); - // TODO @haohao:看看基于 message 的 method 去反向推导; - // 3. 根据消息方法类型构建对应的主题 - switch (methodEnum) { - case PROPERTY_POST: - // 属性上报:只支持回复消息(下行) - if (isReply) { - return IotMqttTopicUtils.buildPropertyPostReplyTopic(productKey, deviceName); - } - break; - case PROPERTY_SET: - // 属性设置:只支持非回复消息(下行) - if (!isReply) { - return IotMqttTopicUtils.buildPropertySetTopic(productKey, deviceName); - } - break; - case EVENT_POST: - // 事件上报:只支持回复消息(下行) - if (isReply) { - return IotMqttTopicUtils.buildEventPostReplyTopicGeneric(productKey, deviceName); - } - break; - case SERVICE_INVOKE: - // 服务调用:支持请求和回复 - if (isReply) { - return IotMqttTopicUtils.buildServiceReplyTopicGeneric(productKey, deviceName); - } else { - return IotMqttTopicUtils.buildServiceTopicGeneric(productKey, deviceName); - } - case CONFIG_PUSH: - // 配置推送:平台向设备推送配置(下行请求),设备回复确认(上行回复) - if (!isReply) { - return IotMqttTopicUtils.buildConfigPushTopic(productKey, deviceName); - } - break; - default: - log.warn("[buildTopicByMethod][未处理的消息方法: {}]", methodEnum); - break; - } - - log.warn("[buildTopicByMethod][暂时不支持的下行消息: method={}, isReply={}]", - message.getMethod(), isReply); - return null; + // 2. 根据消息方法类型构建对应的主题 + return IotMqttTopicUtils.buildTopicByMethod(message.getMethod(), productKey, deviceName, isReply); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java index f2861581f5..957b7003d8 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.iot.gateway.util; +import cn.hutool.core.util.StrUtil; + /** * IoT 网关 MQTT 主题工具类 *

@@ -16,12 +18,6 @@ public final class IotMqttTopicUtils { */ private static final String SYS_TOPIC_PREFIX = "/sys/"; - // TODO @haohao:这个要删除哇? - /** - * 服务调用主题前缀 - */ - private static final String SERVICE_TOPIC_PREFIX = "/thing/"; - // ========== MQTT HTTP 接口路径常量 ========== /** @@ -37,98 +33,32 @@ public final class IotMqttTopicUtils { */ public static final String MQTT_EVENT_PATH = "/mqtt/event"; - // TODO @haohao:这个要删除哇? - /** - * MQTT 授权接口路径(预留) - * 对应 EMQX HTTP 授权插件的授权检查接口 - */ - public static final String MQTT_AUTHZ_PATH = "/mqtt/authz"; - // ========== 工具方法 ========== /** - * 构建设备主题前缀 - * - * @param productKey 产品 Key - * @param deviceName 设备名称 - * @return 设备主题前缀:/sys/{productKey}/{deviceName} - */ - private static String buildDeviceTopicPrefix(String productKey, String deviceName) { - return SYS_TOPIC_PREFIX + productKey + "/" + deviceName; - } - - /** - * 构建设备属性设置主题 + * 根据消息方法构建对应的主题 * + * @param method 消息方法,例如 thing.property.post * @param productKey 产品 Key * @param deviceName 设备名称 + * @param isReply 是否为回复消息 * @return 完整的主题路径 */ - public static String buildPropertySetTopic(String productKey, String deviceName) { - return buildDeviceTopicPrefix(productKey, deviceName) + "/thing/property/set"; - } + public static String buildTopicByMethod(String method, String productKey, String deviceName, boolean isReply) { + if (StrUtil.isBlank(method)) { + return null; + } - /** - * 构建设备属性上报回复主题 - *

- * 当设备上报属性时,会收到该主题的回复 - * - * @param productKey 产品 Key - * @param deviceName 设备名称 - * @return 完整的主题路径 - */ - public static String buildPropertyPostReplyTopic(String productKey, String deviceName) { - return buildDeviceTopicPrefix(productKey, deviceName) + "/thing/property/post_reply"; - } + // 1. 将点分隔符转换为斜杠 + String topicSuffix = method.replace('.', '/'); - /** - * 构建设备配置推送主题 - * - * @param productKey 产品 Key - * @param deviceName 设备名称 - * @return 完整的主题路径 - */ - public static String buildConfigPushTopic(String productKey, String deviceName) { - return buildDeviceTopicPrefix(productKey, deviceName) + "/thing/config/push"; - } + // 2. 对于回复消息,添加 _reply 后缀 + if (isReply) { + topicSuffix += "_reply"; + } - /** - * 构建设备事件上报通用回复主题 - *

- * 不包含具体的事件标识符,事件标识符通过消息 data 中的 identifier 字段传递 - * - * @param productKey 产品 Key - * @param deviceName 设备名称 - * @return 完整的主题路径 - */ - public static String buildEventPostReplyTopicGeneric(String productKey, String deviceName) { - return buildDeviceTopicPrefix(productKey, deviceName) + "/thing/event/post_reply"; - } - - /** - * 构建设备服务调用通用主题 - *

- * 不包含具体的服务标识符,服务标识符通过消息 data 中的 identifier 字段传递 - * - * @param productKey 产品 Key - * @param deviceName 设备名称 - * @return 完整的主题路径 - */ - public static String buildServiceTopicGeneric(String productKey, String deviceName) { - return buildDeviceTopicPrefix(productKey, deviceName) + "/thing/service/invoke"; - } - - /** - * 构建设备服务调用通用回复主题 - *

- * 不包含具体的服务标识符,服务标识符通过消息 data 中的 identifier 字段传递 - * - * @param productKey 产品 Key - * @param deviceName 设备名称 - * @return 完整的主题路径 - */ - public static String buildServiceReplyTopicGeneric(String productKey, String deviceName) { - return buildDeviceTopicPrefix(productKey, deviceName) + "/thing/service/invoke_reply"; + // 3. 构建完整主题 + return SYS_TOPIC_PREFIX + productKey + "/" + deviceName + "/" + topicSuffix; } } \ No newline at end of file From f9d782c701def246dede38b5e0b0a240ff16f4c3 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 30 Jun 2025 19:08:29 +0800 Subject: [PATCH 29/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E4=BC=98=E5=8C=96=E5=9B=BA=E4=BB=B6?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E8=AF=B7=E6=B1=82=E5=92=8C=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E5=AF=B9=E8=B1=A1=EF=BC=8C=E6=B7=BB=E5=8A=A0=E6=96=87=E4=BB=B6?= =?UTF-8?q?=20URL=20=E6=A0=BC=E5=BC=8F=E6=A0=A1=E9=AA=8C=EF=BC=8C=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E5=9B=BA=E4=BB=B6=20ID=20=E7=B1=BB=E5=9E=8B=E4=B8=BA?= =?UTF-8?q?=20Long?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../firmware/IotOtaFirmwareCreateReqVO.java | 13 +-- .../vo/firmware/IotOtaFirmwarePageReqVO.java | 17 ++-- .../ota/vo/firmware/IotOtaFirmwareRespVO.java | 85 ++++++------------- .../firmware/IotOtaFirmwareUpdateReqVO.java | 5 +- .../dal/dataobject/ota/IotOtaFirmwareDO.java | 33 +++---- .../dal/mysql/ota/IotOtaFirmwareMapper.java | 10 +-- .../service/ota/IotOtaFirmwareService.java | 21 ++--- .../ota/IotOtaFirmwareServiceImpl.java | 64 ++++++++------ .../ota/IotOtaUpgradeRecordServiceImpl.java | 30 ++----- .../ota/IotOtaUpgradeTaskServiceImpl.java | 67 ++++----------- .../emqx/router/IotEmqxDownstreamHandler.java | 1 - .../iot/gateway/util/IotMqttTopicUtils.java | 10 ++- 12 files changed, 131 insertions(+), 225 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java index 3d8299cc69..544cce0814 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java @@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; +import org.hibernate.validator.constraints.URL; @Schema(description = "管理后台 - IoT OTA 固件创建 Request VO") @Data @@ -22,17 +23,11 @@ public class IotOtaFirmwareCreateReqVO { @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @NotNull(message = "产品编号不能为空") - private String productId; + private Long productId; - @Schema(description = "签名方式", example = "MD5") - // TODO @li:是不是必传哈 - private String signMethod; - - @Schema(description = "固件文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/yudao-firmware.zip") + @Schema(description = "固件文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.zip") @NotEmpty(message = "固件文件 URL 不能为空") + @URL(message = "固件文件 URL 格式错误") private String fileUrl; - @Schema(description = "自定义信息,建议使用 JSON 格式", example = "{\"key1\":\"value1\",\"key2\":\"value2\"}") - private String information; - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwarePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwarePageReqVO.java index baa7410298..589ed00d40 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwarePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwarePageReqVO.java @@ -3,21 +3,24 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware; import cn.iocoder.yudao.framework.common.pojo.PageParam; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; -@Data @Schema(description = "管理后台 - IoT OTA 固件分页 Request VO") +@Data public class IotOtaFirmwarePageReqVO extends PageParam { - /** - * 固件名称 - */ @Schema(description = "固件名称", example = "智能开关固件") private String name; - /** - * 产品标识 - */ @Schema(description = "产品标识", example = "1024") private String productId; + @Schema(description = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java index 1bcc359fdb..0ad8a82ee6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java @@ -1,83 +1,46 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware; -import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import com.fhs.core.trans.anno.Trans; -import com.fhs.core.trans.constant.TransType; import com.fhs.core.trans.vo.VO; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -@Data +import java.time.LocalDateTime; + @Schema(description = "管理后台 - IoT OTA 固件 Response VO") +@Data public class IotOtaFirmwareRespVO implements VO { - /** - * 固件编号 - */ @Schema(description = "固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Long id; - /** - * 固件名称 - */ - @Schema(description = "固件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "OTA固件") + + @Schema(description = "固件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "OTA 固件") private String name; - /** - * 固件描述 - */ + @Schema(description = "固件描述") private String description; - /** - * 版本号 - */ + @Schema(description = "版本号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0.0") private String version; - /** - * 产品编号 - *

- * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()} - */ @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - @Trans(type = TransType.SIMPLE, target = IotProductDO.class, fields = {"name"}, refs = {"productName"}) - private String productId; - /** - * 产品标识 - *

- * 冗余 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getProductKey()} - */ - @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "iot-product-key") - private String productKey; - /** - * 产品名称 - */ - @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "OTA产品") - private String productName; - /** - * 签名方式 - *

- * 例如说:MD5、SHA256 - */ - @Schema(description = "签名方式", example = "MD5") - private String signMethod; - /** - * 固件文件签名 - */ - @Schema(description = "固件文件签名", example = "1024") - private String fileSign; - /** - * 固件文件大小 - */ + private Long productId; + + @Schema(description = "固件文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/firmware.bin") + private String fileUrl; + @Schema(description = "固件文件大小", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Long fileSize; - /** - * 固件文件 URL - */ - @Schema(description = "固件文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn") - private String fileUrl; - /** - * 自定义信息,建议使用 JSON 格式 - */ - @Schema(description = "自定义信息,建议使用 JSON 格式") - private String information; + + @Schema(description = "固件文件签名算法", example = "MD5") + private String fileDigestAlgorithm; + + @Schema(description = "固件文件签名结果", example = "d41d8cd98f00b204e9800998ecf8427e") + private String fileDigestValue; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime updateTime; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java index 2a594b238e..57b53bbd31 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware; import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; @@ -13,9 +12,7 @@ public class IotOtaFirmwareUpdateReqVO { @NotNull(message = "固件编号不能为空") private Long id; - // TODO @li:name 是不是可以飞必传哈 - @Schema(description = "固件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "智能开关固件") - @NotEmpty(message = "固件名称不能为空") + @Schema(description = "固件名称", example = "智能开关固件") private String name; @Schema(description = "固件描述", example = "某品牌型号固件,测试用") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java index fd635c66f6..1e26727188 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.ota; +import cn.hutool.crypto.digest.DigestAlgorithm; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; @@ -34,7 +35,7 @@ public class IotOtaFirmwareDO extends BaseDO { */ private String name; /** - * 固件版本 + * 固件描述 */ private String description; /** @@ -47,37 +48,25 @@ public class IotOtaFirmwareDO extends BaseDO { * * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()} */ - // TODO @li:帮我改成 Long 哈,写错了 - private String productId; - /** - * 产品标识 - * - * 冗余 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getProductKey()} - */ - private String productKey; + private Long productId; /** - * 签名方式 - * - * 例如说:MD5、SHA256 + * 固件文件 URL */ - private String signMethod; - /** - * 固件文件签名 - */ - private String fileSign; + private String fileUrl; /** * 固件文件大小 */ private Long fileSize; /** - * 固件文件 URL + * 固件文件签名算法 + * + * 枚举 {@link DigestAlgorithm},目前只使用 MD5 */ - private String fileUrl; - + private String fileDigestAlgorithm; /** - * 自定义信息,建议使用 JSON 格式 + * 固件文件签名结果 */ - private String information; + private String fileDigestValue; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java index 7adf79349b..86288674c1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java @@ -9,7 +9,6 @@ import org.apache.ibatis.annotations.Mapper; import java.util.List; -// TODO @li:参考 IotOtaUpgradeRecordMapper 的写法 @Mapper public interface IotOtaFirmwareMapper extends BaseMapperX { @@ -20,21 +19,16 @@ public interface IotOtaFirmwareMapper extends BaseMapperX { * @param version 固件版本号,用于筛选固件信息。 * @return 返回符合条件的固件信息列表。 */ - default List selectByProductIdAndVersion(String productId, String version) { + default List selectByProductIdAndVersion(Long productId, String version) { return selectList(IotOtaFirmwareDO::getProductId, productId, IotOtaFirmwareDO::getVersion, version); } - /** - * 分页查询固件信息,支持根据名称和产品ID进行筛选,并按创建时间降序排列。 - * - * @param pageReqVO 分页查询请求对象,包含分页参数和筛选条件。 - * @return 返回分页查询结果,包含符合条件的固件信息列表。 - */ default PageResult selectPage(IotOtaFirmwarePageReqVO pageReqVO) { return selectPage(pageReqVO, new LambdaQueryWrapperX() .likeIfPresent(IotOtaFirmwareDO::getName, pageReqVO.getName()) .eqIfPresent(IotOtaFirmwareDO::getProductId, pageReqVO.getProductId()) + .betweenIfPresent(IotOtaFirmwareDO::getCreateTime, pageReqVO.getCreateTime()) .orderByDesc(IotOtaFirmwareDO::getCreateTime)); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java index 99e3b382a5..9b9ffaf796 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java @@ -7,7 +7,6 @@ import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwa import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; import jakarta.validation.Valid; -// TODO @li:注释写的有点冗余,可以看看别的模块哈。= = AI 生成的注释,有的时候太啰嗦了,需要处理下的哈 /** * OTA 固件管理 Service * @@ -18,41 +17,39 @@ public interface IotOtaFirmwareService { /** * 创建 OTA 固件 * - * @param saveReqVO OTA固件保存请求对象,包含固件的相关信息 - * @return 返回新创建的固件的ID + * @param saveReqVO 固件信息 + * @return 固件编号 */ Long createOtaFirmware(@Valid IotOtaFirmwareCreateReqVO saveReqVO); /** * 更新 OTA 固件信息 * - * @param updateReqVO OTA固件保存请求对象,包含需要更新的固件信息 + * @param updateReqVO 固件信息 */ void updateOtaFirmware(@Valid IotOtaFirmwareUpdateReqVO updateReqVO); /** * 根据 ID 获取 OTA 固件信息 * - * @param id OTA固件的唯一标识符 - * @return 返回OTA固件的详细信息对象 + * @param id OTA 固件编号 + * @return 固件信息 */ IotOtaFirmwareDO getOtaFirmware(Long id); /** * 分页查询 OTA 固件信息 * - * @param pageReqVO 包含分页查询条件的请求对象 - * @return 返回分页查询结果,包含固件信息列表和分页信息 + * @param pageReqVO 分页查询条件 + * @return 分页结果 */ PageResult getOtaFirmwarePage(@Valid IotOtaFirmwarePageReqVO pageReqVO); /** * 验证物联网 OTA 固件是否存在 * - * @param id 固件的唯一标识符 - * 该方法用于检查系统中是否存在与给定ID关联的物联网OTA固件信息 - * 主要目的是在进行固件更新操作前,确保目标固件已经存在并可以被访问 - * 如果固件不存在,该方法可能抛出异常或返回错误信息,具体行为未定义 + * @param id 物联网 OTA 固件编号 + * @return OTA 固件 */ IotOtaFirmwareDO validateFirmwareExists(Long id); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java index 7c0ddba7cf..f0d22ea22f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java @@ -1,14 +1,14 @@ package cn.iocoder.yudao.module.iot.service.ota; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.convert.Convert; +import cn.hutool.crypto.digest.DigestAlgorithm; +import cn.hutool.crypto.digest.DigestUtil; +import cn.hutool.http.HttpUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareCreateReqVO; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwarePageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareUpdateReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaFirmwareMapper; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import jakarta.annotation.Resource; @@ -17,8 +17,7 @@ import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import java.util.List; -import java.util.Objects; +import java.io.ByteArrayInputStream; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.OTA_FIRMWARE_NOT_EXISTS; @@ -37,16 +36,20 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService { @Override public Long createOtaFirmware(IotOtaFirmwareCreateReqVO saveReqVO) { - // 1. 校验固件产品 + 版本号不能重复 + // 1.1 校验固件产品 + 版本号不能重复 validateProductAndVersionDuplicate(saveReqVO.getProductId(), saveReqVO.getVersion()); + // 1.2 校验产品存在 + productService.validateProductExists(saveReqVO.getProductId()); - // 2.1.转化数据格式,准备存储到数据库中 + // 2. 构建对象 + 存储 IotOtaFirmwareDO firmware = BeanUtils.toBean(saveReqVO, IotOtaFirmwareDO.class); - // 2.2.查询ProductKey - // TODO @li:productService.getProduct(Convert.toLong(firmware.getProductId())) 放到 1. 后面,先做参考校验。逻辑两段:1)先参数校验;2)构建对象 + 存储 - IotProductDO product = productService.getProduct(Convert.toLong(firmware.getProductId())); - firmware.setProductKey(Objects.requireNonNull(product).getProductKey()); - // TODO @芋艿: 附件、附件签名等属性的计算 + // 2.1 计算文件签名等属性 + try { + calculateFileDigest(firmware); + } catch (Exception e) { + log.error("[createOtaFirmware][url({}) 计算文件签名失败]", firmware.getFileUrl(), e); + throw new RuntimeException("计算文件签名失败: " + e.getMessage()); + } otaFirmwareMapper.insert(firmware); return firmware.getId(); } @@ -80,25 +83,34 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService { return firmware; } - // TODO @li:注释有点冗余 /** * 验证产品和版本号是否重复 - *

- * 该方法用于确保在系统中不存在具有相同产品ID和版本号的固件条目 - * 它通过调用otaFirmwareMapper的selectByProductIdAndVersion方法来查询数据库中是否存在匹配的产品ID和版本号的固件信息 - * 如果查询结果非空且不为null,则抛出异常,提示固件信息已存在,从而避免数据重复 - * - * @param productId 产品ID,用于数据库查询 - * @param version 版本号,用于数据库查询 - * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,则抛出异常,提示固件信息已存在 */ - private void validateProductAndVersionDuplicate(String productId, String version) { - // 查询数据库中是否存在具有相同产品ID和版本号的固件信息 - List list = otaFirmwareMapper.selectByProductIdAndVersion(productId, version); - // 如果查询结果非空且不为null,则抛出异常,提示固件信息已存在 - if (CollUtil.isNotEmpty(list)) { + private void validateProductAndVersionDuplicate(Long productId, String version) { + // 只查询1条记录检查是否存在 + IotOtaFirmwareDO firmware = otaFirmwareMapper.selectOne(IotOtaFirmwareDO::getProductId, productId, + IotOtaFirmwareDO::getVersion, version); + if (firmware != null) { throw exception(OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE); } } + /** + * 计算文件签名 + * + * @param firmware 固件对象 + * @throws Exception 下载或计算签名失败时抛出异常 + */ + private void calculateFileDigest(IotOtaFirmwareDO firmware) throws Exception { + String fileUrl = firmware.getFileUrl(); + // 下载文件并计算签名 + byte[] fileBytes = HttpUtil.downloadBytes(fileUrl); + // 设置文件大小 + firmware.setFileSize((long) fileBytes.length); + // 计算 MD5 签名 + firmware.setFileDigestAlgorithm(DigestAlgorithm.MD5.getValue()); + String md5Hex = DigestUtil.digester(firmware.getFileDigestAlgorithm()).digestHex(new ByteArrayInputStream(fileBytes)); + firmware.setFileDigestValue(md5Hex); + } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java index 02ef39cdf1..32652a8314 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java @@ -34,24 +34,19 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic @Resource private IotOtaUpgradeRecordMapper upgradeRecordMapper; - // TODO @li:1)@Resource 写在 @Lazy 之前,先用关键注解;2)有必要的情况下,在写 @Lazy 注解。 - @Lazy @Resource private IotDeviceService deviceService; - @Lazy @Resource private IotOtaFirmwareService firmwareService; - @Lazy @Resource private IotOtaUpgradeTaskService upgradeTaskService; @Override public void createOtaUpgradeRecordBatch(List deviceIds, Long firmwareId, Long upgradeTaskId) { // 1. 校验升级记录信息是否存在,并且已经取消的任务可以重新开始 - // TODO @li:批量查询。。 deviceIds.forEach(deviceId -> validateUpgradeRecordDuplicate(firmwareId, upgradeTaskId, String.valueOf(deviceId))); - // 2.初始化OTA升级记录列表信息 + // 2. 初始化OTA升级记录列表信息 IotOtaUpgradeTaskDO upgradeTask = upgradeTaskService.getUpgradeTask(upgradeTaskId); IotOtaFirmwareDO firmware = firmwareService.getOtaFirmware(firmwareId); List deviceList = deviceService.getDeviceListByIdList(deviceIds); @@ -67,10 +62,9 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic upgradeRecord.setProgress(0); return upgradeRecord; }).toList(); - // 3.保存数据 + // 3. 保存数据 upgradeRecordMapper.insertBatch(upgradeRecordList); // TODO @芋艿:在这里需要处理推送升级任务的逻辑 - } // TODO @li:1)方法注释,简单写;2)父类写了注释,子类就不用写了。。。 @@ -116,9 +110,9 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic @Override public void retryUpgradeRecord(Long id) { - // 1.1.校验升级记录信息是否存在 + // 1.1 校验升级记录信息是否存在 IotOtaUpgradeRecordDO upgradeRecord = validateUpgradeRecordExists(id); - // 1.2.校验升级记录是否可以重新升级 + // 1.2 校验升级记录是否可以重新升级 validateUpgradeRecordCanRetry(upgradeRecord); // 2. 将一些数据重置,这样定时任务轮询就可以重启任务 @@ -191,16 +185,12 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic * @param deviceId 设备ID,用于标识特定的设备 */ private void validateUpgradeRecordDuplicate(Long firmwareId, Long taskId, String deviceId) { - // 根据条件查询升级记录 IotOtaUpgradeRecordDO upgradeRecord = upgradeRecordMapper.selectByConditions(firmwareId, taskId, deviceId); - // 如果查询到升级记录且状态不是已取消,则抛出异常 - // TODO @li:if return,减少括号层级; - // TODO @li:ObjUtil.notEquals,尽量不用 !取否逻辑; - if (upgradeRecord != null) { - if (!IotOtaUpgradeRecordStatusEnum.CANCELED.getStatus().equals(upgradeRecord.getStatus())) { - // TODO @li:提示的时候,需要把 deviceName 给提示出来,不然用户不知道哪个重复啦。 - throw exception(OTA_UPGRADE_RECORD_DUPLICATE); - } + if (upgradeRecord == null) { + return; + } + if (!Objects.equals(upgradeRecord.getStatus(), IotOtaUpgradeRecordStatusEnum.CANCELED.getStatus())) { + throw exception(OTA_UPGRADE_RECORD_DUPLICATE); } } @@ -216,12 +206,10 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic */ // TODO @li:这种一次性的方法(不复用的),其实一步一定要抽成小方法; private void validateUpgradeRecordCanRetry(IotOtaUpgradeRecordDO upgradeRecord) { - // 检查升级记录的状态是否为 PENDING、PUSHED 或 UPGRADING if (ObjectUtils.equalsAny(upgradeRecord.getStatus(), IotOtaUpgradeRecordStatusEnum.PENDING.getStatus(), IotOtaUpgradeRecordStatusEnum.PUSHED.getStatus(), IotOtaUpgradeRecordStatusEnum.UPGRADING.getStatus())) { - // 如果升级记录处于上述状态之一,则抛出异常,表示不允许重试 throw exception(OTA_UPGRADE_RECORD_CANNOT_RETRY); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java index cee3ba516b..b91fb89dab 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java @@ -27,10 +27,14 @@ import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; -// TODO @li:完善注释、注解顺序 -@Slf4j +/** + * IoT OTA升级任务 Service 实现类 + * + * @author Shelly Chan + */ @Service @Validated +@Slf4j public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { @Resource @@ -105,102 +109,65 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { upgradeTaskMapper.updateById(IotOtaUpgradeTaskDO.builder().id(id).status(status).build()); } - // TODO @li:注释有点冗余 /** * 校验固件升级任务是否重复 - *

- * 该方法用于检查给定固件ID和任务名称组合是否已存在于数据库中,如果存在则抛出异常, - * 表示任务名称对于该固件而言是重复的此检查确保用户不能创建具有相同名称的任务, - * 从而避免数据重复和混淆 - * - * @param firmwareId 固件的唯一标识符,用于区分不同的固件 - * @param taskName 升级任务的名称,用于与固件ID一起检查重复性 - * @throws cn.iocoder.yudao.framework.common.exception.ServerException 则抛出预定义的异常 */ private void validateFirmwareTaskDuplicate(Long firmwareId, String taskName) { - // 查询数据库中是否有相同固件ID和任务名称的升级任务存在 List upgradeTaskList = upgradeTaskMapper.selectByFirmwareIdAndName(firmwareId, taskName); - // 如果查询结果不为空,说明存在重复的任务名称,抛出异常 if (CollUtil.isNotEmpty(upgradeTaskList)) { throw exception(OTA_UPGRADE_TASK_NAME_DUPLICATE); } } - // TODO @li:注释有点冗余 /** * 验证升级任务的范围和设备列表的有效性。 - *

- * 根据升级任务的范围(scope),验证设备列表(deviceIds)或产品ID(productId)是否有效。 - * 如果范围是“选择设备”(SELECT),则必须提供设备列表;如果范围是“所有设备”(ALL),则必须根据产品ID获取设备列表,并确保列表不为空。 * * @param scope 升级任务的范围,参考 IotOtaUpgradeTaskScopeEnum 枚举值 - * @param deviceIds 设备ID列表,当范围为“选择设备”时,该列表不能为空 - * @param productId 产品ID,当范围为“所有设备”时,用于获取设备列表 + * @param deviceIds 设备ID列表,当范围为"选择设备"时,该列表不能为空 + * @param productId 产品ID,当范围为"所有设备"时,用于获取设备列表 * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,抛出相应的异常 */ - private void validateScopeAndDevice(Integer scope, List deviceIds, String productId) { - // TODO @li:if return - // 验证范围为“选择设备”时,设备列表不能为空 + private void validateScopeAndDevice(Integer scope, List deviceIds, Long productId) { if (Objects.equals(scope, IotOtaUpgradeTaskScopeEnum.SELECT.getScope())) { if (CollUtil.isEmpty(deviceIds)) { throw exception(OTA_UPGRADE_TASK_DEVICE_IDS_EMPTY); } - } else if (Objects.equals(scope, IotOtaUpgradeTaskScopeEnum.ALL.getScope())) { - // 验证范围为“所有设备”时,根据产品ID获取的设备列表不能为空 - List deviceList = deviceService.getDeviceListByProductId(Convert.toLong(productId)); + return; + } + + if (Objects.equals(scope, IotOtaUpgradeTaskScopeEnum.ALL.getScope())) { + List deviceList = deviceService.getDeviceListByProductId(productId); if (CollUtil.isEmpty(deviceList)) { throw exception(OTA_UPGRADE_TASK_DEVICE_LIST_EMPTY); } } } - // TODO @li:注释有点冗余 /** * 验证升级任务是否存在 - *

- * 通过查询数据库来验证给定ID的升级任务是否存在此方法主要用于确保后续操作所针对的升级任务是有效的 - * - * @param id 升级任务的唯一标识符如果为null或数据库中不存在对应的记录,则认为任务不存在 - * @throws cn.iocoder.yudao.framework.common.exception.ServiceException 如果升级任务不存在,则抛出异常提示任务不存在 */ private IotOtaUpgradeTaskDO validateUpgradeTaskExists(Long id) { - // 查询数据库中是否有相同固件ID和任务名称的升级任务存在 IotOtaUpgradeTaskDO upgradeTask = upgradeTaskMapper.selectById(id); - // 如果查询结果不为空,说明存在重复的任务名称,抛出异常 if (Objects.isNull(upgradeTask)) { throw exception(OTA_UPGRADE_TASK_NOT_EXISTS); } return upgradeTask; } - // TODO @li:注释有点冗余 /** * 初始化升级任务 - *

- * 根据请求参数创建升级任务对象,并根据选择的范围初始化设备数量 - * 如果选择特定设备进行升级,则设备数量为所选设备的总数 - * 如果选择全部设备进行升级,则设备数量为该固件对应产品下的所有设备总数 - * - * @param createReqVO 升级任务保存请求对象,包含创建升级任务所需的信息 - * @return 返回初始化后的升级任务对象 */ - // TODO @li:一次性的方法,不用特别抽小方法 - private IotOtaUpgradeTaskDO initOtaUpgradeTask(IotOtaUpgradeTaskSaveReqVO createReqVO, String productId) { - // 将请求参数转换为升级任务对象 + private IotOtaUpgradeTaskDO initOtaUpgradeTask(IotOtaUpgradeTaskSaveReqVO createReqVO, Long productId) { IotOtaUpgradeTaskDO upgradeTask = BeanUtils.toBean(createReqVO, IotOtaUpgradeTaskDO.class); - // 初始化的时候,设置设备数量和状态 upgradeTask.setDeviceCount(Convert.toLong(CollUtil.size(createReqVO.getDeviceIds()))) .setStatus(IotOtaUpgradeTaskStatusEnum.IN_PROGRESS.getStatus()); - // 如果选择全选,则需要查询设备数量 + if (Objects.equals(createReqVO.getScope(), IotOtaUpgradeTaskScopeEnum.ALL.getScope())) { - // 根据产品ID查询设备数量 - List deviceList = deviceService.getDeviceListByProductId(Convert.toLong(productId)); - // 设置升级任务的设备数量 + List deviceList = deviceService.getDeviceListByProductId(productId); upgradeTask.setDeviceCount((long) deviceList.size()); upgradeTask.setDeviceIds( deviceList.stream().map(IotDeviceDO::getId).collect(Collectors.toList())); } - // 返回初始化后的升级任务对象 return upgradeTask; } diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java index 6c451fd5c0..06632b3e8f 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java @@ -70,7 +70,6 @@ public class IotEmqxDownstreamHandler { private String buildTopicByMethod(IotDeviceMessage message, String productKey, String deviceName) { // 1. 判断是否为回复消息 boolean isReply = IotDeviceMessageUtils.isReplyMessage(message); - // 2. 根据消息方法类型构建对应的主题 return IotMqttTopicUtils.buildTopicByMethod(message.getMethod(), productKey, deviceName, isReply); } diff --git a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java index 957b7003d8..7f72937efb 100644 --- a/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java +++ b/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java @@ -18,6 +18,11 @@ public final class IotMqttTopicUtils { */ private static final String SYS_TOPIC_PREFIX = "/sys/"; + /** + * 回复主题后缀 + */ + private static final String REPLY_TOPIC_SUFFIX = "_reply"; + // ========== MQTT HTTP 接口路径常量 ========== /** @@ -48,15 +53,12 @@ public final class IotMqttTopicUtils { if (StrUtil.isBlank(method)) { return null; } - // 1. 将点分隔符转换为斜杠 String topicSuffix = method.replace('.', '/'); - // 2. 对于回复消息,添加 _reply 后缀 if (isReply) { - topicSuffix += "_reply"; + topicSuffix += REPLY_TOPIC_SUFFIX; } - // 3. 构建完整主题 return SYS_TOPIC_PREFIX + productKey + "/" + deviceName + "/" + topicSuffix; } From 5399e5bba0d4673c763b90dc50ab38ec29a5dbbe Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 1 Jul 2025 00:33:02 +0800 Subject: [PATCH 30/33] =?UTF-8?q?reactor=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E8=B0=83=E6=95=B4=20ota=20=E7=9A=84?= =?UTF-8?q?=20task=20=E5=AE=9E=E4=BD=93=E5=AE=9A=E4=B9=89=EF=BC=88?= =?UTF-8?q?=E6=9A=82=E6=97=B6=E6=9C=AA=E5=A4=84=E7=90=86=20controller?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/ota/IotOtaFirmwareController.java | 2 +- .../ota/IotOtaUpgradeRecordController.java | 15 +--- .../ota/IotOtaUpgradeTaskController.java | 6 +- .../record/IotOtaUpgradeRecordRespVO.java | 7 +- .../task/IotOtaUpgradeTaskPageReqVO.java | 14 +--- .../upgrade/task/IotOtaUpgradeTaskRespVO.java | 58 +++----------- .../task/IotOtaUpgradeTaskSaveReqVO.java | 38 ++------- ...taUpgradeTaskDO.java => IotOtaTaskDO.java} | 32 ++++---- ...eRecordDO.java => IotOtaTaskRecordDO.java} | 29 +++---- .../mysql/ota/IotOtaUpgradeRecordMapper.java | 78 ++++--------------- .../mysql/ota/IotOtaUpgradeTaskMapper.java | 24 +++--- ...um.java => IotOtaTaskDeviceScopeEnum.java} | 7 +- ...m.java => IotOtaTaskRecordStatusEnum.java} | 13 ++-- .../iot/enums/ota/IotOtaTaskStatusEnum.java | 35 +++++++++ .../ota/IotOtaUpgradeTaskStatusEnum.java | 35 --------- .../ota/IotOtaUpgradeRecordService.java | 42 +--------- .../ota/IotOtaUpgradeRecordServiceImpl.java | 76 +++++------------- .../service/ota/IotOtaUpgradeTaskService.java | 8 +- .../ota/IotOtaUpgradeTaskServiceImpl.java | 50 ++++++------ 19 files changed, 177 insertions(+), 392 deletions(-) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/{IotOtaUpgradeTaskDO.java => IotOtaTaskDO.java} (50%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/{IotOtaUpgradeRecordDO.java => IotOtaTaskRecordDO.java} (62%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/{IotOtaUpgradeTaskScopeEnum.java => IotOtaTaskDeviceScopeEnum.java} (74%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/{IotOtaUpgradeRecordStatusEnum.java => IotOtaTaskRecordStatusEnum.java} (68%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaTaskStatusEnum.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskStatusEnum.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java index 6cc3918e8f..a2a5a114e7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java @@ -21,7 +21,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @Tag(name = "管理后台 - IoT OTA 固件") @RestController -@RequestMapping("/iot/ota-firmware") +@RequestMapping("/iot/ota/firmware") @Validated public class IotOtaFirmwareController { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java index f6bc526ac2..855391b28a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java @@ -5,7 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordRespVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO; import cn.iocoder.yudao.module.iot.service.ota.IotOtaUpgradeRecordService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -50,7 +50,7 @@ public class IotOtaUpgradeRecordController { @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") public CommonResult> getUpgradeRecordPage( @Valid IotOtaUpgradeRecordPageReqVO pageReqVO) { - PageResult pageResult = upgradeRecordService.getUpgradeRecordPage(pageReqVO); + PageResult pageResult = upgradeRecordService.getUpgradeRecordPage(pageReqVO); return success(BeanUtils.toBean(pageResult, IotOtaUpgradeRecordRespVO.class)); } @@ -59,17 +59,8 @@ public class IotOtaUpgradeRecordController { @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") @Parameter(name = "id", description = "升级记录编号", required = true, example = "1024") public CommonResult getUpgradeRecord(@RequestParam("id") Long id) { - IotOtaUpgradeRecordDO upgradeRecord = upgradeRecordService.getUpgradeRecord(id); + IotOtaTaskRecordDO upgradeRecord = upgradeRecordService.getUpgradeRecord(id); return success(BeanUtils.toBean(upgradeRecord, IotOtaUpgradeRecordRespVO.class)); } - @PutMapping("/retry") - @Operation(summary = "重试升级记录") - @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:retry')") - @Parameter(name = "id", description = "升级记录编号", required = true, example = "1024") - public CommonResult retryUpgradeRecord(@RequestParam("id") Long id) { - upgradeRecordService.retryUpgradeRecord(id); - return success(true); - } - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java index e248e80274..834723700b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java @@ -6,7 +6,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskRespVO; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO; import cn.iocoder.yudao.module.iot.service.ota.IotOtaUpgradeTaskService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -48,7 +48,7 @@ public class IotOtaUpgradeTaskController { @Operation(summary = "获得升级任务分页") @PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:query')") public CommonResult> getUpgradeTaskPage(@Valid IotOtaUpgradeTaskPageReqVO pageReqVO) { - PageResult pageResult = upgradeTaskService.getUpgradeTaskPage(pageReqVO); + PageResult pageResult = upgradeTaskService.getUpgradeTaskPage(pageReqVO); return success(BeanUtils.toBean(pageResult, IotOtaUpgradeTaskRespVO.class)); } @@ -57,7 +57,7 @@ public class IotOtaUpgradeTaskController { @Parameter(name = "id", description = "升级任务编号", required = true, example = "1024") @PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:query')") public CommonResult getUpgradeTask(@RequestParam("id") Long id) { - IotOtaUpgradeTaskDO upgradeTask = upgradeTaskService.getUpgradeTask(id); + IotOtaTaskDO upgradeTask = upgradeTaskService.getUpgradeTask(id); return success(BeanUtils.toBean(upgradeTask, IotOtaUpgradeTaskRespVO.class)); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordRespVO.java index ba2a40aa81..0f7ddc75f6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordRespVO.java @@ -3,7 +3,8 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO; +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskRecordStatusEnum; import com.fhs.core.trans.anno.Trans; import com.fhs.core.trans.constant.TransType; import io.swagger.v3.oas.annotations.media.Schema; @@ -36,7 +37,7 @@ public class IotOtaUpgradeRecordRespVO { /** * 任务编号 *

- * 关联 {@link IotOtaUpgradeTaskDO#getId()} + * 关联 {@link IotOtaTaskDO#getId()} */ @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Long taskId; @@ -77,7 +78,7 @@ public class IotOtaUpgradeRecordRespVO { /** * 升级状态 *

- * 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum} + * 关联 {@link IotOtaTaskRecordStatusEnum} */ @Schema(description = "升级状态", requiredMode = Schema.RequiredMode.REQUIRED, allowableValues = {"0", "10", "20", "30", "40", "50"}) private Integer status; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskPageReqVO.java index 8abdd59370..9ce36b27e3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskPageReqVO.java @@ -9,17 +9,11 @@ import lombok.Data; @Schema(description = "管理后台 - IoT OTA 升级任务分页 Request VO") public class IotOtaUpgradeTaskPageReqVO extends PageParam { - /** - * 任务名称字段,用于描述任务的名称 - */ + @Schema(description = "固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "固件编号不能为空") + private Long firmwareId; + @Schema(description = "任务名称", example = "升级任务") private String name; - /** - * 固件编号字段,用于唯一标识固件,不能为空 - */ - @NotNull(message = "固件编号不能为空") - @Schema(description = "固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private Long firmwareId; - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskRespVO.java index 6a32522ac3..666e17cb39 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskRespVO.java @@ -1,7 +1,5 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; import com.fhs.core.trans.vo.VO; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -13,69 +11,33 @@ import java.util.List; @Schema(description = "管理后台 - IoT OTA 升级任务 Response VO") public class IotOtaUpgradeTaskRespVO implements VO { - /** - * 任务编号 - */ @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Long id; - /** - * 任务名称 - */ + @Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "升级任务") private String name; - /** - * 任务描述 - */ + @Schema(description = "任务描述", example = "升级任务") private String description; - /** - * 固件编号 - *

- * 关联 {@link IotOtaFirmwareDO#getId()} - */ + @Schema(description = "固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Long firmwareId; - /** - * 任务状态 - *

- * 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskStatusEnum} - */ - @Schema(description = "任务状态", requiredMode = Schema.RequiredMode.REQUIRED, allowableValues = {"10", "20", "21", "30"}) + + @Schema(description = "任务状态", requiredMode = Schema.RequiredMode.REQUIRED) private Integer status; - /** - * 任务状态名称 - */ - @Schema(description = "任务状态名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "进行中") - private String statusName; - /** - * 升级范围 - *

- * 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskScopeEnum} - */ + @Schema(description = "升级范围", requiredMode = Schema.RequiredMode.REQUIRED, allowableValues = {"1", "2"}) private Integer scope; - /** - * 设备数量 - */ + @Schema(description = "设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Long deviceCount; - /** - * 选中的设备编号数组 - *

- * 关联 {@link IotDeviceDO#getId()} - */ + @Schema(description = "选中的设备编号数组", example = "1024") private List deviceIds; - /** - * 选中的设备名字数组 - *

- * 关联 {@link IotDeviceDO#getDeviceName()} - */ + @Schema(description = "选中的设备名字数组", example = "1024") private List deviceNames; - /** - * 创建时间 - */ + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-07-08 07:30:00") private LocalDateTime createTime; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java index e8cdbefa46..ebf49cbe92 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java @@ -1,9 +1,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task; import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; -import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskScopeEnum; +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskDeviceScopeEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; @@ -11,51 +9,27 @@ import lombok.Data; import java.util.List; -@Data @Schema(description = "管理后台 - IoT OTA 升级任务创建/修改 Request VO") +@Data public class IotOtaUpgradeTaskSaveReqVO { - // TODO @li:已经有注解,不用重复注释 - // TODO @li: @Schema 写在参数校验前面。先有定义;其他的,也检查下; - - /** - * 任务名称 - */ @NotEmpty(message = "任务名称不能为空") @Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "升级任务") private String name; - /** - * 任务描述 - */ @Schema(description = "任务描述", example = "升级任务") private String description; - /** - * 固件编号 - *

- * 关联 {@link IotOtaFirmwareDO#getId()} - */ - @NotNull(message = "固件编号不能为空") @Schema(description = "固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "固件编号不能为空") private Long firmwareId; - /** - * 升级范围 - *

- * 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskScopeEnum} - */ - @NotNull(message = "升级范围不能为空") - @InEnum(value = IotOtaUpgradeTaskScopeEnum.class) @Schema(description = "升级范围", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "升级范围不能为空") + @InEnum(value = IotOtaTaskDeviceScopeEnum.class) private Integer scope; - /** - * 选中的设备编号数组 - *

- * 关联 {@link IotDeviceDO#getId()} - */ - @Schema(description = "选中的设备编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1,2,3,4]") + @Schema(description = "选中的设备编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3") private List deviceIds; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaTaskDO.java similarity index 50% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaTaskDO.java index 6f59f3f931..d2452950af 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeTaskDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaTaskDO.java @@ -1,31 +1,28 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.ota; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskDeviceScopeEnum; +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskStatusEnum; import com.baomidou.mybatisplus.annotation.KeySequence; -import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.List; - /** * IoT OTA 升级任务 DO * * @author 芋道源码 */ -@TableName(value = "iot_ota_upgrade_task", autoResultMap = true) -@KeySequence("iot_ota_upgrade_task_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@TableName(value = "iot_ota_task", autoResultMap = true) +@KeySequence("iot_ota_task_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Builder @NoArgsConstructor @AllArgsConstructor -public class IotOtaUpgradeTaskDO extends BaseDO { +public class IotOtaTaskDO extends BaseDO { /** * 任务编号 @@ -51,26 +48,23 @@ public class IotOtaUpgradeTaskDO extends BaseDO { /** * 任务状态 *

- * 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskStatusEnum} + * 关联 {@link IotOtaTaskStatusEnum} */ private Integer status; /** - * 升级范围 + * 设备升级范围 *

- * 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskScopeEnum} + * 关联 {@link IotOtaTaskDeviceScopeEnum} */ - private Integer scope; + private Integer deviceScope; /** - * 设备数量 + * 设备总数数量 */ - private Long deviceCount; + private Long deviceTotalCount; /** - * 选中的设备编号数组 - *

- * 关联 {@link IotDeviceDO#getId()} + * 设备成功数量 */ - @TableField(typeHandler = JacksonTypeHandler.class) - private List deviceIds; + private Integer deviceSuccessCount; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaTaskRecordDO.java similarity index 62% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaTaskRecordDO.java index 02c4a0157f..8cd0173396 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaUpgradeRecordDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaTaskRecordDO.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.ota; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO; +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskRecordStatusEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -11,17 +12,17 @@ import lombok.*; import java.time.LocalDateTime; /** - * IoT OTA 升级记录 DO + * IoT OTA 升级任务记录 DO * * @author 芋道源码 */ -@TableName(value = "iot_ota_upgrade_record", autoResultMap = true) -@KeySequence("iot_ota_upgrade_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@TableName(value = "iot_ota_task_record", autoResultMap = true) +@KeySequence("iot_ota_task_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Builder @NoArgsConstructor @AllArgsConstructor -public class IotOtaUpgradeRecordDO extends BaseDO { +public class IotOtaTaskRecordDO extends BaseDO { @TableId private Long id; @@ -35,28 +36,16 @@ public class IotOtaUpgradeRecordDO extends BaseDO { /** * 任务编号 * - * 关联 {@link IotOtaUpgradeTaskDO#getId()} + * 关联 {@link IotOtaTaskDO#getId()} */ private Long taskId; - /** - * 产品标识 - * - * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()} - */ - private String productKey; - /** - * 设备名称 - * - * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO#getId()} - */ - private String deviceName; /** * 设备编号 * - * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO#getId()} + * 关联 {@link IotDeviceDO#getId()} */ - private String deviceId; + private Long deviceId; /** * 来源的固件编号 * @@ -67,7 +56,7 @@ public class IotOtaUpgradeRecordDO extends BaseDO { /** * 升级状态 * - * 关联 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum} + * 关联 {@link IotOtaTaskRecordStatusEnum} */ private Integer status; /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java index 5e5d8200f4..81bb604c6d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordPageReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -14,7 +14,7 @@ import java.util.List; import java.util.Map; @Mapper -public interface IotOtaUpgradeRecordMapper extends BaseMapperX { +public interface IotOtaUpgradeRecordMapper extends BaseMapperX { // TODO @li:selectByFirmwareIdAndTaskIdAndDeviceId;让方法自解释 /** @@ -25,12 +25,12 @@ public interface IotOtaUpgradeRecordMapper extends BaseMapperX() - .eqIfPresent(IotOtaUpgradeRecordDO::getFirmwareId, firmwareId) - .eqIfPresent(IotOtaUpgradeRecordDO::getTaskId, taskId) - .eqIfPresent(IotOtaUpgradeRecordDO::getDeviceId, deviceId)); + return selectOne(new LambdaQueryWrapperX() + .eqIfPresent(IotOtaTaskRecordDO::getFirmwareId, firmwareId) + .eqIfPresent(IotOtaTaskRecordDO::getTaskId, taskId) + .eqIfPresent(IotOtaTaskRecordDO::getDeviceId, deviceId)); } // TODO @li:这个是不是 groupby status 就 ok 拉? @@ -80,12 +80,12 @@ public interface IotOtaUpgradeRecordMapper extends BaseMapperX selectUpgradeRecordPage(IotOtaUpgradeRecordPageReqVO pageReqVO) { + default PageResult selectUpgradeRecordPage(IotOtaUpgradeRecordPageReqVO pageReqVO) { // TODO @li:这里的注释,可以去掉哈;然后下面的“如果”。。。也没必要注释 // 使用LambdaQueryWrapperX构建查询条件,并根据请求参数动态添加查询条件 - return selectPage(pageReqVO, new LambdaQueryWrapperX() - .likeIfPresent(IotOtaUpgradeRecordDO::getDeviceName, pageReqVO.getDeviceName()) // 如果设备名称存在,则添加模糊查询条件 - .eqIfPresent(IotOtaUpgradeRecordDO::getTaskId, pageReqVO.getTaskId())); // 如果任务ID存在,则添加等值查询条件 + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .likeIfPresent(IotOtaTaskRecordDO::getDeviceName, pageReqVO.getDeviceName()) // 如果设备名称存在,则添加模糊查询条件 + .eqIfPresent(IotOtaTaskRecordDO::getTaskId, pageReqVO.getTaskId())); // 如果任务ID存在,则添加等值查询条件 } // TODO @li:这里的注释,可以去掉哈 @@ -101,59 +101,11 @@ public interface IotOtaUpgradeRecordMapper extends BaseMapperX() - .set(IotOtaUpgradeRecordDO::getStatus, setStatus) - .eq(IotOtaUpgradeRecordDO::getTaskId, taskId) - .eq(IotOtaUpgradeRecordDO::getStatus, whereStatus) + update(new LambdaUpdateWrapper() + .set(IotOtaTaskRecordDO::getStatus, setStatus) + .eq(IotOtaTaskRecordDO::getTaskId, taskId) + .eq(IotOtaTaskRecordDO::getStatus, whereStatus) ); } - // TODO @li:参考上面的建议,调整下这个方法 - /** - * 根据状态查询符合条件的升级记录列表 - *

- * 该函数使用LambdaQueryWrapperX构建查询条件,查询指定状态的升级记录。 - * - * @param state 升级记录的状态,用于筛选符合条件的记录 - * @return 返回符合指定状态的升级记录列表,类型为List - */ - default List selectUpgradeRecordListByState(Integer state) { - // 使用LambdaQueryWrapperX构建查询条件,根据状态查询符合条件的升级记录 - return selectList(new LambdaQueryWrapperX() - .eq(IotOtaUpgradeRecordDO::getStatus, state)); - } - - // TODO @li:参考上面的建议,调整下这个方法 - /** - * 更新升级记录状态 - *

- * 该函数用于批量更新指定ID列表中的升级记录状态。通过传入的ID列表和状态值,使用LambdaUpdateWrapper构建更新条件, - * 并执行更新操作。 - * - * @param ids 需要更新的升级记录ID列表,类型为List。传入的ID列表中的记录将被更新。 - * @param status 要更新的状态值,类型为Integer。该值将被设置到符合条件的升级记录中。 - */ - default void updateUpgradeRecordStatus(List ids, Integer status) { - // 使用LambdaUpdateWrapper构建更新条件,设置状态字段,并根据ID列表进行筛选 - update(new LambdaUpdateWrapper() - .set(IotOtaUpgradeRecordDO::getStatus, status) - .in(IotOtaUpgradeRecordDO::getId, ids) - ); - } - - // TODO @li:参考上面的建议,调整下这个方法 - /** - * 根据任务ID查询升级记录列表 - *

- * 该函数通过任务ID查询符合条件的升级记录,并返回查询结果列表。 - * - * @param taskId 任务ID,用于筛选升级记录 - * @return 返回符合条件的升级记录列表,若未找到则返回空列表 - */ - default List selectUpgradeRecordListByTaskId(Long taskId) { - // 使用LambdaQueryWrapperX构建查询条件,根据任务ID查询符合条件的升级记录 - return selectList(new LambdaQueryWrapperX() - .eq(IotOtaUpgradeRecordDO::getTaskId, taskId)); - } - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java index d955b13619..db778b2773 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskPageReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO; import org.apache.ibatis.annotations.Mapper; import java.util.List; @@ -15,7 +15,7 @@ import java.util.List; * @author Shelly */ @Mapper -public interface IotOtaUpgradeTaskMapper extends BaseMapperX { +public interface IotOtaUpgradeTaskMapper extends BaseMapperX { /** * 根据固件ID和任务名称查询升级任务列表。 @@ -24,10 +24,10 @@ public interface IotOtaUpgradeTaskMapper extends BaseMapperX selectByFirmwareIdAndName(Long firmwareId, String name) { - return selectList(new LambdaQueryWrapperX() - .eqIfPresent(IotOtaUpgradeTaskDO::getFirmwareId, firmwareId) - .eqIfPresent(IotOtaUpgradeTaskDO::getName, name)); + default List selectByFirmwareIdAndName(Long firmwareId, String name) { + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(IotOtaTaskDO::getFirmwareId, firmwareId) + .eqIfPresent(IotOtaTaskDO::getName, name)); } /** @@ -36,10 +36,10 @@ public interface IotOtaUpgradeTaskMapper extends BaseMapperX selectUpgradeTaskPage(IotOtaUpgradeTaskPageReqVO pageReqVO) { - return selectPage(pageReqVO, new LambdaQueryWrapperX() - .eqIfPresent(IotOtaUpgradeTaskDO::getFirmwareId, pageReqVO.getFirmwareId()) - .likeIfPresent(IotOtaUpgradeTaskDO::getName, pageReqVO.getName())); + default PageResult selectUpgradeTaskPage(IotOtaUpgradeTaskPageReqVO pageReqVO) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .eqIfPresent(IotOtaTaskDO::getFirmwareId, pageReqVO.getFirmwareId()) + .likeIfPresent(IotOtaTaskDO::getName, pageReqVO.getName())); } /** @@ -50,8 +50,8 @@ public interface IotOtaUpgradeTaskMapper extends BaseMapperX selectUpgradeTaskByState(Integer status) { - return selectList(IotOtaUpgradeTaskDO::getStatus, status); + default List selectUpgradeTaskByState(Integer status) { + return selectList(IotOtaTaskDO::getStatus, status); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskScopeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaTaskDeviceScopeEnum.java similarity index 74% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskScopeEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaTaskDeviceScopeEnum.java index 6dccbb041c..d9ec270ed5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskScopeEnum.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaTaskDeviceScopeEnum.java @@ -7,18 +7,19 @@ import lombok.RequiredArgsConstructor; import java.util.Arrays; /** - * IoT OTA 升级任务的范围枚举 + * IoT OTA 升级任务的设备范围枚举 * * @author haohao */ @RequiredArgsConstructor @Getter -public enum IotOtaUpgradeTaskScopeEnum implements ArrayValuable { +public enum IotOtaTaskDeviceScopeEnum implements ArrayValuable { ALL(1), // 全部设备:只包括当前产品下的设备,不包括未来创建的设备 SELECT(2); // 指定设备 - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotOtaUpgradeTaskScopeEnum::getScope).toArray(Integer[]::new); + public static final Integer[] ARRAYS = Arrays.stream(values()) + .map(IotOtaTaskDeviceScopeEnum::getScope).toArray(Integer[]::new); /** * 范围 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeRecordStatusEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaTaskRecordStatusEnum.java similarity index 68% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeRecordStatusEnum.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaTaskRecordStatusEnum.java index e809a7e5b2..c95b033d70 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeRecordStatusEnum.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaTaskRecordStatusEnum.java @@ -8,25 +8,26 @@ import lombok.RequiredArgsConstructor; import java.util.Arrays; /** - * IoT OTA 升级记录的范围枚举 + * IoT OTA 升级任务记录的状态枚举 * - * @author haohao + * @author 芋道源码 */ @RequiredArgsConstructor @Getter -public enum IotOtaUpgradeRecordStatusEnum implements ArrayValuable { +public enum IotOtaTaskRecordStatusEnum implements ArrayValuable { PENDING(0), // 待推送 PUSHED(10), // 已推送 UPGRADING(20), // 升级中 SUCCESS(30), // 升级成功 FAILURE(40), // 升级失败 - CANCELED(50),; // 已取消 + CANCELED(50),; // 升级取消 - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotOtaUpgradeRecordStatusEnum::getStatus).toArray(Integer[]::new); + public static final Integer[] ARRAYS = Arrays.stream(values()) + .map(IotOtaTaskRecordStatusEnum::getStatus).toArray(Integer[]::new); /** - * 范围 + * 状态 */ private final Integer status; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaTaskStatusEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaTaskStatusEnum.java new file mode 100644 index 0000000000..65147027e6 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaTaskStatusEnum.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.iot.enums.ota; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * IoT OTA 升级任务的状态 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Getter +public enum IotOtaTaskStatusEnum implements ArrayValuable { + + IN_PROGRESS(10), // 进行中(升级中) + COMPLETED(20), // 已完成(包括全部成功、部分成功) + CANCELED(30),; // 已取消(一般是主动取消任务) + + public static final Integer[] ARRAYS = Arrays.stream(values()) + .map(IotOtaTaskStatusEnum::getStatus).toArray(Integer[]::new); + + /** + * 状态 + */ + private final Integer status; + + @Override + public Integer[] array() { + return ARRAYS; + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskStatusEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskStatusEnum.java deleted file mode 100644 index 78af16cb20..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskStatusEnum.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.yudao.module.iot.enums.ota; - -import cn.iocoder.yudao.framework.common.core.ArrayValuable; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -import java.util.Arrays; - -/** - * IoT OTA 升级任务的范围枚举 - * - * @author haohao - */ -@RequiredArgsConstructor -@Getter -public enum IotOtaUpgradeTaskStatusEnum implements ArrayValuable { - - IN_PROGRESS(10), // 进行中:升级中 - COMPLETED(20), // 已完成:已结束,全部升级完成 - INCOMPLETE(21), // 未完成:已结束,部分升级完成 - CANCELED(30),; // 已取消:一般是主动取消任务 - - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotOtaUpgradeTaskStatusEnum::getStatus).toArray(Integer[]::new); - - /** - * 范围 - */ - private final Integer status; - - @Override - public Integer[] array() { - return ARRAYS; - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java index cbf900ac0a..c27380d0ab 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.service.ota; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordPageReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO; import jakarta.validation.Valid; import java.util.List; @@ -39,20 +39,13 @@ public interface IotOtaUpgradeRecordService { */ Map getOtaUpgradeRecordStatistics(Long firmwareId); - /** - * 重试指定的 OTA 升级记录 - * - * @param id 需要重试的升级记录的ID。 - */ - void retryUpgradeRecord(Long id); - /** * 获取指定 ID 的 OTA 升级记录的详细信息。 * * @param id 需要查询的升级记录的ID。 * @return 返回包含升级记录详细信息的响应对象。 */ - IotOtaUpgradeRecordDO getUpgradeRecord(Long id); + IotOtaTaskRecordDO getUpgradeRecord(Long id); /** * 分页查询 OTA 升级记录。 @@ -60,7 +53,7 @@ public interface IotOtaUpgradeRecordService { * @param pageReqVO 包含分页查询条件的请求对象,必须经过验证。 * @return 返回包含分页查询结果的响应对象。 */ - PageResult getUpgradeRecordPage(@Valid IotOtaUpgradeRecordPageReqVO pageReqVO); + PageResult getUpgradeRecordPage(@Valid IotOtaUpgradeRecordPageReqVO pageReqVO); /** * 根据任务 ID 取消升级记录 @@ -72,33 +65,4 @@ public interface IotOtaUpgradeRecordService { */ void cancelUpgradeRecordByTaskId(Long taskId); - // TODO @li:不要的方法,可以删除下哈。 - /** - * 根据升级状态获取升级记录列表 - * - * @param state 升级状态,用于筛选符合条件的升级记录 - * @return 返回符合指定状态的升级记录列表,列表中的元素为 {@link IotOtaUpgradeRecordDO} 对象 - */ - List getUpgradeRecordListByState(Integer state); - - /** - * 更新升级记录的状态。 - *

- * 该函数用于批量更新指定升级记录的状态。通过传入的ID列表和状态值,将对应的升级记录的状态更新为指定的值。 - * - * @param ids 需要更新状态的升级记录的ID列表。列表中的每个元素代表一个升级记录的ID。 - * @param status 要更新的状态值。该值应为有效的状态标识符,通常为整数类型。 - */ - void updateUpgradeRecordStatus(List ids, Integer status); - - /** - * 根据任务ID获取升级记录列表 - *

- * 该函数通过给定的任务ID,查询并返回与该任务相关的所有升级记录。 - * - * @param taskId 任务ID,用于指定需要查询的任务 - * @return 返回一个包含升级记录的列表,列表中的每个元素为IotOtaUpgradeRecordDO对象 - */ - List getUpgradeRecordListByTaskId(Long taskId); - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java index 32652a8314..0e6d431e27 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java @@ -6,14 +6,13 @@ import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO; import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaUpgradeRecordMapper; -import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum; +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskRecordStatusEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; -import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -47,18 +46,18 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic deviceIds.forEach(deviceId -> validateUpgradeRecordDuplicate(firmwareId, upgradeTaskId, String.valueOf(deviceId))); // 2. 初始化OTA升级记录列表信息 - IotOtaUpgradeTaskDO upgradeTask = upgradeTaskService.getUpgradeTask(upgradeTaskId); + IotOtaTaskDO upgradeTask = upgradeTaskService.getUpgradeTask(upgradeTaskId); IotOtaFirmwareDO firmware = firmwareService.getOtaFirmware(firmwareId); List deviceList = deviceService.getDeviceListByIdList(deviceIds); - List upgradeRecordList = deviceList.stream().map(device -> { - IotOtaUpgradeRecordDO upgradeRecord = new IotOtaUpgradeRecordDO(); + List upgradeRecordList = deviceList.stream().map(device -> { + IotOtaTaskRecordDO upgradeRecord = new IotOtaTaskRecordDO(); upgradeRecord.setFirmwareId(firmware.getId()); upgradeRecord.setTaskId(upgradeTask.getId()); upgradeRecord.setProductKey(device.getProductKey()); upgradeRecord.setDeviceName(device.getDeviceName()); upgradeRecord.setDeviceId(Convert.toStr(device.getId())); upgradeRecord.setFromFirmwareId(Convert.toLong(device.getFirmwareId())); - upgradeRecord.setStatus(IotOtaUpgradeRecordStatusEnum.PENDING.getStatus()); + upgradeRecord.setStatus(IotOtaTaskRecordStatusEnum.PENDING.getStatus()); upgradeRecord.setProgress(0); return upgradeRecord; }).toList(); @@ -88,14 +87,6 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic entry -> Convert.toLong(entry.getValue()))); } - // TODO @li:1)方法注释,简单写;2)父类写了注释,子类就不用写了。。。 - /** - * 获取指定固件ID的OTA升级记录统计信息。 - * 该方法通过查询数据库,统计不同状态的OTA升级记录数量,并返回一个包含各状态数量的映射。 - * - * @param firmwareId 固件ID,用于指定需要统计的固件升级记录。 - * @return 返回一个Map,其中键为升级记录状态(如PENDING、PUSHED等),值为对应状态的记录数量。 - */ @Override @Transactional public Map getOtaUpgradeRecordStatistics(Long firmwareId) { @@ -109,26 +100,12 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic } @Override - public void retryUpgradeRecord(Long id) { - // 1.1 校验升级记录信息是否存在 - IotOtaUpgradeRecordDO upgradeRecord = validateUpgradeRecordExists(id); - // 1.2 校验升级记录是否可以重新升级 - validateUpgradeRecordCanRetry(upgradeRecord); - - // 2. 将一些数据重置,这样定时任务轮询就可以重启任务 - // TODO @li:更新的时候,wherestatus; - upgradeRecordMapper.updateById(new IotOtaUpgradeRecordDO() - .setId(upgradeRecord.getId()).setProgress(0) - .setStatus(IotOtaUpgradeRecordStatusEnum.PENDING.getStatus())); - } - - @Override - public IotOtaUpgradeRecordDO getUpgradeRecord(Long id) { + public IotOtaTaskRecordDO getUpgradeRecord(Long id) { return upgradeRecordMapper.selectById(id); } @Override - public PageResult getUpgradeRecordPage(IotOtaUpgradeRecordPageReqVO pageReqVO) { + public PageResult getUpgradeRecordPage(IotOtaUpgradeRecordPageReqVO pageReqVO) { return upgradeRecordMapper.selectUpgradeRecordPage(pageReqVO); } @@ -136,23 +113,8 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic public void cancelUpgradeRecordByTaskId(Long taskId) { // 暂定只有待推送的升级记录可以取消 TODO @芋艿:可以看看阿里云,哪些可以取消 upgradeRecordMapper.updateUpgradeRecordStatusByTaskIdAndStatus( - IotOtaUpgradeRecordStatusEnum.CANCELED.getStatus(), taskId, - IotOtaUpgradeRecordStatusEnum.PENDING.getStatus()); - } - - @Override - public List getUpgradeRecordListByState(Integer state) { - return upgradeRecordMapper.selectUpgradeRecordListByState(state); - } - - @Override - public void updateUpgradeRecordStatus(List ids, Integer status) { - upgradeRecordMapper.updateUpgradeRecordStatus(ids, status); - } - - @Override - public List getUpgradeRecordListByTaskId(Long taskId) { - return upgradeRecordMapper.selectUpgradeRecordListByTaskId(taskId); + IotOtaTaskRecordStatusEnum.CANCELED.getStatus(), taskId, + IotOtaTaskRecordStatusEnum.PENDING.getStatus()); } /** @@ -163,9 +125,9 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic * @param id 升级记录的唯一标识符,类型为Long。 * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,则抛出异常,异常类型为OTA_UPGRADE_RECORD_NOT_EXISTS。 */ - private IotOtaUpgradeRecordDO validateUpgradeRecordExists(Long id) { + private IotOtaTaskRecordDO validateUpgradeRecordExists(Long id) { // 根据ID查询升级记录 - IotOtaUpgradeRecordDO upgradeRecord = upgradeRecordMapper.selectById(id); + IotOtaTaskRecordDO upgradeRecord = upgradeRecordMapper.selectById(id); // 如果查询结果为空,抛出异常 if (upgradeRecord == null) { throw exception(OTA_UPGRADE_RECORD_NOT_EXISTS); @@ -185,11 +147,11 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic * @param deviceId 设备ID,用于标识特定的设备 */ private void validateUpgradeRecordDuplicate(Long firmwareId, Long taskId, String deviceId) { - IotOtaUpgradeRecordDO upgradeRecord = upgradeRecordMapper.selectByConditions(firmwareId, taskId, deviceId); + IotOtaTaskRecordDO upgradeRecord = upgradeRecordMapper.selectByConditions(firmwareId, taskId, deviceId); if (upgradeRecord == null) { return; } - if (!Objects.equals(upgradeRecord.getStatus(), IotOtaUpgradeRecordStatusEnum.CANCELED.getStatus())) { + if (!Objects.equals(upgradeRecord.getStatus(), IotOtaTaskRecordStatusEnum.CANCELED.getStatus())) { throw exception(OTA_UPGRADE_RECORD_DUPLICATE); } } @@ -205,11 +167,11 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,则抛出 OTA_UPGRADE_RECORD_CANNOT_RETRY 异常 */ // TODO @li:这种一次性的方法(不复用的),其实一步一定要抽成小方法; - private void validateUpgradeRecordCanRetry(IotOtaUpgradeRecordDO upgradeRecord) { + private void validateUpgradeRecordCanRetry(IotOtaTaskRecordDO upgradeRecord) { if (ObjectUtils.equalsAny(upgradeRecord.getStatus(), - IotOtaUpgradeRecordStatusEnum.PENDING.getStatus(), - IotOtaUpgradeRecordStatusEnum.PUSHED.getStatus(), - IotOtaUpgradeRecordStatusEnum.UPGRADING.getStatus())) { + IotOtaTaskRecordStatusEnum.PENDING.getStatus(), + IotOtaTaskRecordStatusEnum.PUSHED.getStatus(), + IotOtaTaskRecordStatusEnum.UPGRADING.getStatus())) { throw exception(OTA_UPGRADE_RECORD_CANNOT_RETRY); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java index a2a810bf0c..9611d151f3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.service.ota; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO; import jakarta.validation.Valid; import java.util.List; @@ -36,7 +36,7 @@ public interface IotOtaUpgradeTaskService { * @param id OTA升级任务的ID * @return OTA升级任务的详细信息对象 */ - IotOtaUpgradeTaskDO getUpgradeTask(Long id); + IotOtaTaskDO getUpgradeTask(Long id); /** * 分页查询OTA升级任务 @@ -44,7 +44,7 @@ public interface IotOtaUpgradeTaskService { * @param pageReqVO OTA升级任务的分页查询请求对象,包含查询条件和分页信息 * @return 分页查询结果,包含OTA升级任务列表和总记录数 */ - PageResult getUpgradeTaskPage(@Valid IotOtaUpgradeTaskPageReqVO pageReqVO); + PageResult getUpgradeTaskPage(@Valid IotOtaUpgradeTaskPageReqVO pageReqVO); /** * 根据任务状态获取升级任务列表 @@ -52,7 +52,7 @@ public interface IotOtaUpgradeTaskService { * @param state 任务状态,用于筛选符合条件的升级任务 * @return 返回符合指定状态的升级任务列表,列表中的元素为 IotOtaUpgradeTaskDO 对象 */ - List getUpgradeTaskByState(Integer state); + List getUpgradeTaskByState(Integer state); /** * 更新升级任务的状态。 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java index b91fb89dab..a61181d49a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java @@ -8,10 +8,10 @@ import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUp import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO; import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaUpgradeTaskMapper; -import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskScopeEnum; -import cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeTaskStatusEnum; +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskDeviceScopeEnum; +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskStatusEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -61,7 +61,7 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { validateScopeAndDevice(createReqVO.getScope(), createReqVO.getDeviceIds(), firmware.getProductId()); // 2. 保存 OTA 升级任务信息到数据库 - IotOtaUpgradeTaskDO upgradeTask = initOtaUpgradeTask(createReqVO, firmware.getProductId()); + IotOtaTaskDO upgradeTask = initOtaUpgradeTask(createReqVO, firmware.getProductId()); upgradeTaskMapper.insert(upgradeTask); // 3. 生成设备升级记录信息并存储,等待定时任务轮询 @@ -73,16 +73,16 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { @Transactional(rollbackFor = Exception.class) public void cancelUpgradeTask(Long id) { // 1.1 校验升级任务是否存在 - IotOtaUpgradeTaskDO upgradeTask = validateUpgradeTaskExists(id); + IotOtaTaskDO upgradeTask = validateUpgradeTaskExists(id); // 1.2 校验升级任务是否可以取消 // TODO @li:ObjUtil notequals - if (!Objects.equals(upgradeTask.getStatus(), IotOtaUpgradeTaskStatusEnum.IN_PROGRESS.getStatus())) { + if (!Objects.equals(upgradeTask.getStatus(), IotOtaTaskStatusEnum.IN_PROGRESS.getStatus())) { throw exception(OTA_UPGRADE_TASK_CANNOT_CANCEL); } // 2. 更新 OTA 升级任务状态为已取消 - upgradeTaskMapper.updateById(IotOtaUpgradeTaskDO.builder() - .id(id).status(IotOtaUpgradeTaskStatusEnum.CANCELED.getStatus()) + upgradeTaskMapper.updateById(IotOtaTaskDO.builder() + .id(id).status(IotOtaTaskStatusEnum.CANCELED.getStatus()) .build()); // 3. 更新 OTA 升级记录状态为已取消 @@ -90,30 +90,30 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { } @Override - public IotOtaUpgradeTaskDO getUpgradeTask(Long id) { + public IotOtaTaskDO getUpgradeTask(Long id) { return upgradeTaskMapper.selectById(id); } @Override - public PageResult getUpgradeTaskPage(IotOtaUpgradeTaskPageReqVO pageReqVO) { + public PageResult getUpgradeTaskPage(IotOtaUpgradeTaskPageReqVO pageReqVO) { return upgradeTaskMapper.selectUpgradeTaskPage(pageReqVO); } @Override - public List getUpgradeTaskByState(Integer state) { + public List getUpgradeTaskByState(Integer state) { return upgradeTaskMapper.selectUpgradeTaskByState(state); } @Override public void updateUpgradeTaskStatus(Long id, Integer status) { - upgradeTaskMapper.updateById(IotOtaUpgradeTaskDO.builder().id(id).status(status).build()); + upgradeTaskMapper.updateById(IotOtaTaskDO.builder().id(id).status(status).build()); } /** * 校验固件升级任务是否重复 */ private void validateFirmwareTaskDuplicate(Long firmwareId, String taskName) { - List upgradeTaskList = upgradeTaskMapper.selectByFirmwareIdAndName(firmwareId, taskName); + List upgradeTaskList = upgradeTaskMapper.selectByFirmwareIdAndName(firmwareId, taskName); if (CollUtil.isNotEmpty(upgradeTaskList)) { throw exception(OTA_UPGRADE_TASK_NAME_DUPLICATE); } @@ -128,14 +128,14 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,抛出相应的异常 */ private void validateScopeAndDevice(Integer scope, List deviceIds, Long productId) { - if (Objects.equals(scope, IotOtaUpgradeTaskScopeEnum.SELECT.getScope())) { + if (Objects.equals(scope, IotOtaTaskDeviceScopeEnum.SELECT.getScope())) { if (CollUtil.isEmpty(deviceIds)) { throw exception(OTA_UPGRADE_TASK_DEVICE_IDS_EMPTY); } return; } - - if (Objects.equals(scope, IotOtaUpgradeTaskScopeEnum.ALL.getScope())) { + + if (Objects.equals(scope, IotOtaTaskDeviceScopeEnum.ALL.getScope())) { List deviceList = deviceService.getDeviceListByProductId(productId); if (CollUtil.isEmpty(deviceList)) { throw exception(OTA_UPGRADE_TASK_DEVICE_LIST_EMPTY); @@ -146,8 +146,8 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { /** * 验证升级任务是否存在 */ - private IotOtaUpgradeTaskDO validateUpgradeTaskExists(Long id) { - IotOtaUpgradeTaskDO upgradeTask = upgradeTaskMapper.selectById(id); + private IotOtaTaskDO validateUpgradeTaskExists(Long id) { + IotOtaTaskDO upgradeTask = upgradeTaskMapper.selectById(id); if (Objects.isNull(upgradeTask)) { throw exception(OTA_UPGRADE_TASK_NOT_EXISTS); } @@ -157,14 +157,14 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { /** * 初始化升级任务 */ - private IotOtaUpgradeTaskDO initOtaUpgradeTask(IotOtaUpgradeTaskSaveReqVO createReqVO, Long productId) { - IotOtaUpgradeTaskDO upgradeTask = BeanUtils.toBean(createReqVO, IotOtaUpgradeTaskDO.class); - upgradeTask.setDeviceCount(Convert.toLong(CollUtil.size(createReqVO.getDeviceIds()))) - .setStatus(IotOtaUpgradeTaskStatusEnum.IN_PROGRESS.getStatus()); - - if (Objects.equals(createReqVO.getScope(), IotOtaUpgradeTaskScopeEnum.ALL.getScope())) { + private IotOtaTaskDO initOtaUpgradeTask(IotOtaUpgradeTaskSaveReqVO createReqVO, Long productId) { + IotOtaTaskDO upgradeTask = BeanUtils.toBean(createReqVO, IotOtaTaskDO.class); + upgradeTask.setDeviceTotalCount(Convert.toLong(CollUtil.size(createReqVO.getDeviceIds()))) + .setStatus(IotOtaTaskStatusEnum.IN_PROGRESS.getStatus()); + + if (Objects.equals(createReqVO.getScope(), IotOtaTaskDeviceScopeEnum.ALL.getScope())) { List deviceList = deviceService.getDeviceListByProductId(productId); - upgradeTask.setDeviceCount((long) deviceList.size()); + upgradeTask.setDeviceTotalCount((long) deviceList.size()); upgradeTask.setDeviceIds( deviceList.stream().map(IotDeviceDO::getId).collect(Collectors.toList())); } From 4749d93d0e4b12dbfe772d9fa97b3c3ce442b061 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 1 Jul 2025 09:42:59 +0800 Subject: [PATCH 31/33] =?UTF-8?q?reactor=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E8=B0=83=E6=95=B4=20ota=20=E7=9A=84?= =?UTF-8?q?=20task=20=E5=AE=9E=E4=BD=93=E5=AE=9A=E4=B9=89=EF=BC=88?= =?UTF-8?q?=E6=9A=82=E6=97=B6=E6=9C=AA=E5=A4=84=E7=90=86=20controller?= =?UTF-8?q?=EF=BC=89x2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/ota/IotOtaTaskController.java | 64 ++++++++++ .../admin/ota/IotOtaTaskRecordController.java | 65 +++++++++++ .../ota/IotOtaUpgradeRecordController.java | 66 ----------- .../ota/IotOtaUpgradeTaskController.java | 64 ---------- .../IotOtaTaskCreateReqVO.java} | 8 +- .../IotOtaTaskPageReqVO.java} | 14 +-- .../IotOtaTaskRespVO.java} | 24 ++-- .../record/IotOtaTaskRecordPageReqVO.java} | 18 +-- .../task/record/IotOtaTaskRecordRespVO.java | 56 +++++++++ .../record/IotOtaUpgradeRecordRespVO.java | 109 ------------------ .../iot/dal/mysql/ota/IotOtaTaskMapper.java | 32 +++++ .../mysql/ota/IotOtaUpgradeRecordMapper.java | 6 +- .../mysql/ota/IotOtaUpgradeTaskMapper.java | 57 --------- ...vice.java => IotOtaTaskRecordService.java} | 24 ++-- ....java => IotOtaTaskRecordServiceImpl.java} | 41 ++++--- .../iot/service/ota/IotOtaTaskService.java | 47 ++++++++ ...ceImpl.java => IotOtaTaskServiceImpl.java} | 82 +++++-------- .../service/ota/IotOtaUpgradeTaskService.java | 68 ----------- 18 files changed, 351 insertions(+), 494 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskRecordController.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/{upgrade/task/IotOtaUpgradeTaskSaveReqVO.java => task/IotOtaTaskCreateReqVO.java} (88%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/{upgrade/task/IotOtaUpgradeTaskPageReqVO.java => task/IotOtaTaskPageReqVO.java} (50%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/{upgrade/task/IotOtaUpgradeTaskRespVO.java => task/IotOtaTaskRespVO.java} (63%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/{upgrade/record/IotOtaUpgradeRecordPageReqVO.java => task/record/IotOtaTaskRecordPageReqVO.java} (56%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordRespVO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaTaskMapper.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/{IotOtaUpgradeRecordService.java => IotOtaTaskRecordService.java} (72%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/{IotOtaUpgradeRecordServiceImpl.java => IotOtaTaskRecordServiceImpl.java} (81%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskService.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/{IotOtaUpgradeTaskServiceImpl.java => IotOtaTaskServiceImpl.java} (59%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskController.java new file mode 100644 index 0000000000..807f96993b --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskController.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.iot.controller.admin.ota; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskCreateReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO; +import cn.iocoder.yudao.module.iot.service.ota.IotOtaTaskService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - IoT OTA 升级任务") +@RestController +@RequestMapping("/iot/ota/task") +@Validated +public class IotOtaTaskController { + + @Resource + private IotOtaTaskService otaTaskService; + + @PostMapping("/create") + @Operation(summary = "创建 OTA 升级任务") + @PreAuthorize(value = "@ss.hasPermission('iot:ota-task:create')") + public CommonResult createOtaTask(@Valid @RequestBody IotOtaTaskCreateReqVO createReqVO) { + return success(otaTaskService.createOtaTask(createReqVO)); + } + + @PostMapping("/cancel") + @Operation(summary = "取消 OTA 升级任务") + @Parameter(name = "id", description = "升级任务编号", required = true) + @PreAuthorize(value = "@ss.hasPermission('iot:ota-task:cancel')") + public CommonResult cancelOtaTask(@RequestParam("id") Long id) { + otaTaskService.cancelOtaTask(id); + return success(true); + } + + @GetMapping("/page") + @Operation(summary = "获得 OTA 升级任务分页") + @PreAuthorize(value = "@ss.hasPermission('iot:ota-task:query')") + public CommonResult> getOtaTaskPage(@Valid IotOtaTaskPageReqVO pageReqVO) { + PageResult pageResult = otaTaskService.getOtaTaskPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotOtaTaskRespVO.class)); + } + + @GetMapping("/get") + @Operation(summary = "获得 OTA 升级任务") + @Parameter(name = "id", description = "升级任务编号", required = true, example = "1024") + @PreAuthorize(value = "@ss.hasPermission('iot:ota-task:query')") + public CommonResult getOtaTask(@RequestParam("id") Long id) { + IotOtaTaskDO upgradeTask = otaTaskService.getOtaTask(id); + return success(BeanUtils.toBean(upgradeTask, IotOtaTaskRespVO.class)); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskRecordController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskRecordController.java new file mode 100644 index 0000000000..e2b8d0aa48 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskRecordController.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.iot.controller.admin.ota; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordRespVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO; +import cn.iocoder.yudao.module.iot.service.ota.IotOtaTaskRecordService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - IoT OTA 升级任务记录") +@RestController +@RequestMapping("/iot/ota/task-record") +@Validated +public class IotOtaTaskRecordController { + + @Resource + private IotOtaTaskRecordService otaTaskRecordService; + + @GetMapping("/get-statistics") + @Operation(summary = "固件升级设备统计") + @PreAuthorize("@ss.hasPermission('iot:ota-task-record:query')") + @Parameter(name = "firmwareId", description = "固件编号", required = true, example = "1024") + public CommonResult> getOtaTaskRecordStatistics(@RequestParam(value = "firmwareId") Long firmwareId) { + return success(otaTaskRecordService.getOtaTaskRecordStatistics(firmwareId)); + } + + @GetMapping("/get-count") + @Operation(summary = "获得升级记录分页 tab 数量") + @PreAuthorize("@ss.hasPermission('iot:ota-task-record:query')") + public CommonResult> getOtaTaskRecordCount(@Valid IotOtaTaskRecordPageReqVO pageReqVO) { + return success(otaTaskRecordService.getOtaTaskRecordCount(pageReqVO)); + } + + @GetMapping("/page") + @Operation(summary = "获得升级记录分页") + @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") + public CommonResult> getOtaTaskRecordPage( + @Valid IotOtaTaskRecordPageReqVO pageReqVO) { + PageResult pageResult = otaTaskRecordService.getOtaTaskRecordPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotOtaTaskRecordRespVO.class)); + } + + @GetMapping("/get") + @Operation(summary = "获得升级记录") + @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") + @Parameter(name = "id", description = "升级记录编号", required = true, example = "1024") + public CommonResult getOtaTaskRecord(@RequestParam("id") Long id) { + IotOtaTaskRecordDO upgradeRecord = otaTaskRecordService.getOtaTaskRecord(id); + return success(BeanUtils.toBean(upgradeRecord, IotOtaTaskRecordRespVO.class)); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java deleted file mode 100644 index 855391b28a..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java +++ /dev/null @@ -1,66 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.ota; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordRespVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO; -import cn.iocoder.yudao.module.iot.service.ota.IotOtaUpgradeRecordService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.annotation.Resource; -import jakarta.validation.Valid; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -@Tag(name = "管理后台 - IoT OTA 升级记录") -@RestController -@RequestMapping("/iot/ota-upgrade-record") -@Validated -public class IotOtaUpgradeRecordController { - - @Resource - private IotOtaUpgradeRecordService upgradeRecordService; - - @GetMapping("/get-statistics") - @Operation(summary = "固件升级设备统计") - @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") - @Parameter(name = "firmwareId", description = "固件编号", required = true, example = "1024") - public CommonResult> getOtaUpgradeRecordStatistics(@RequestParam(value = "firmwareId") Long firmwareId) { - return success(upgradeRecordService.getOtaUpgradeRecordStatistics(firmwareId)); - } - - @GetMapping("/get-count") - @Operation(summary = "获得升级记录分页 tab 数量") - @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") - public CommonResult> getOtaUpgradeRecordCount( - @Valid IotOtaUpgradeRecordPageReqVO pageReqVO) { - return success(upgradeRecordService.getOtaUpgradeRecordCount(pageReqVO)); - } - - @GetMapping("/page") - @Operation(summary = "获得升级记录分页") - @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") - public CommonResult> getUpgradeRecordPage( - @Valid IotOtaUpgradeRecordPageReqVO pageReqVO) { - PageResult pageResult = upgradeRecordService.getUpgradeRecordPage(pageReqVO); - return success(BeanUtils.toBean(pageResult, IotOtaUpgradeRecordRespVO.class)); - } - - @GetMapping("/get") - @Operation(summary = "获得升级记录") - @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") - @Parameter(name = "id", description = "升级记录编号", required = true, example = "1024") - public CommonResult getUpgradeRecord(@RequestParam("id") Long id) { - IotOtaTaskRecordDO upgradeRecord = upgradeRecordService.getUpgradeRecord(id); - return success(BeanUtils.toBean(upgradeRecord, IotOtaUpgradeRecordRespVO.class)); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java deleted file mode 100644 index 834723700b..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java +++ /dev/null @@ -1,64 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.ota; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO; -import cn.iocoder.yudao.module.iot.service.ota.IotOtaUpgradeTaskService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.annotation.Resource; -import jakarta.validation.Valid; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -@Tag(name = "管理后台 - IoT OTA 升级任务") -@RestController -@RequestMapping("/iot/ota-upgrade-task") -@Validated -public class IotOtaUpgradeTaskController { - - @Resource - private IotOtaUpgradeTaskService upgradeTaskService; - - @PostMapping("/create") - @Operation(summary = "创建升级任务") - @PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:create')") - public CommonResult createUpgradeTask(@Valid @RequestBody IotOtaUpgradeTaskSaveReqVO createReqVO) { - return success(upgradeTaskService.createUpgradeTask(createReqVO)); - } - - @PostMapping("/cancel") - @Operation(summary = "取消升级任务") - @Parameter(name = "id", description = "升级任务编号", required = true) - @PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:cancel')") - public CommonResult cancelUpgradeTask(@RequestParam("id") Long id) { - upgradeTaskService.cancelUpgradeTask(id); - return success(true); - } - - @GetMapping("/page") - @Operation(summary = "获得升级任务分页") - @PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:query')") - public CommonResult> getUpgradeTaskPage(@Valid IotOtaUpgradeTaskPageReqVO pageReqVO) { - PageResult pageResult = upgradeTaskService.getUpgradeTaskPage(pageReqVO); - return success(BeanUtils.toBean(pageResult, IotOtaUpgradeTaskRespVO.class)); - } - - @GetMapping("/get") - @Operation(summary = "获得升级任务") - @Parameter(name = "id", description = "升级任务编号", required = true, example = "1024") - @PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:query')") - public CommonResult getUpgradeTask(@RequestParam("id") Long id) { - IotOtaTaskDO upgradeTask = upgradeTaskService.getUpgradeTask(id); - return success(BeanUtils.toBean(upgradeTask, IotOtaUpgradeTaskRespVO.class)); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/IotOtaTaskCreateReqVO.java similarity index 88% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/IotOtaTaskCreateReqVO.java index ebf49cbe92..853e10c548 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/IotOtaTaskCreateReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task; +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task; import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskDeviceScopeEnum; @@ -9,9 +9,9 @@ import lombok.Data; import java.util.List; -@Schema(description = "管理后台 - IoT OTA 升级任务创建/修改 Request VO") +@Schema(description = "管理后台 - IoT OTA 升级任务创建 Request VO") @Data -public class IotOtaUpgradeTaskSaveReqVO { +public class IotOtaTaskCreateReqVO { @NotEmpty(message = "任务名称不能为空") @Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "升级任务") @@ -27,7 +27,7 @@ public class IotOtaUpgradeTaskSaveReqVO { @Schema(description = "升级范围", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotNull(message = "升级范围不能为空") @InEnum(value = IotOtaTaskDeviceScopeEnum.class) - private Integer scope; + private Integer deviceScope; @Schema(description = "选中的设备编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3") private List deviceIds; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/IotOtaTaskPageReqVO.java similarity index 50% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskPageReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/IotOtaTaskPageReqVO.java index 9ce36b27e3..4638f1a401 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/IotOtaTaskPageReqVO.java @@ -1,19 +1,17 @@ -package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task; +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task; import cn.iocoder.yudao.framework.common.pojo.PageParam; import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotNull; import lombok.Data; -@Data @Schema(description = "管理后台 - IoT OTA 升级任务分页 Request VO") -public class IotOtaUpgradeTaskPageReqVO extends PageParam { - - @Schema(description = "固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - @NotNull(message = "固件编号不能为空") - private Long firmwareId; +@Data +public class IotOtaTaskPageReqVO extends PageParam { @Schema(description = "任务名称", example = "升级任务") private String name; + @Schema(description = "固件编号", example = "1024") + private Long firmwareId; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/IotOtaTaskRespVO.java similarity index 63% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskRespVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/IotOtaTaskRespVO.java index 666e17cb39..247f7c658f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/task/IotOtaUpgradeTaskRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/IotOtaTaskRespVO.java @@ -1,15 +1,14 @@ -package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task; +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task; import com.fhs.core.trans.vo.VO; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; -import java.util.List; -@Data @Schema(description = "管理后台 - IoT OTA 升级任务 Response VO") -public class IotOtaUpgradeTaskRespVO implements VO { +@Data +public class IotOtaTaskRespVO implements VO { @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Long id; @@ -23,20 +22,17 @@ public class IotOtaUpgradeTaskRespVO implements VO { @Schema(description = "固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Long firmwareId; - @Schema(description = "任务状态", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "任务状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") private Integer status; - @Schema(description = "升级范围", requiredMode = Schema.RequiredMode.REQUIRED, allowableValues = {"1", "2"}) - private Integer scope; + @Schema(description = "升级范围", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer deviceScope; - @Schema(description = "设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private Long deviceCount; + @Schema(description = "设备总共数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Integer deviceTotalCount; - @Schema(description = "选中的设备编号数组", example = "1024") - private List deviceIds; - - @Schema(description = "选中的设备名字数组", example = "1024") - private List deviceNames; + @Schema(description = "设备成功数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "66") + private Integer deviceSuccessCount; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-07-08 07:30:00") private LocalDateTime createTime; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordPageReqVO.java similarity index 56% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordPageReqVO.java index cf74cbb8c2..f6d1cf18be 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordPageReqVO.java @@ -1,29 +1,19 @@ -package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record; +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record; import cn.iocoder.yudao.framework.common.pojo.PageParam; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; -@Data @Schema(description = "管理后台 - IoT OTA 升级记录分页 Request VO") -public class IotOtaUpgradeRecordPageReqVO extends PageParam { +@Data +public class IotOtaTaskRecordPageReqVO extends PageParam { - // TODO @li:已经有注解,不用重复注释 - /** - * 升级任务编号字段。 - *

- * 该字段用于标识升级任务的唯一编号,不能为空。 - */ + // TODO @芋艿:分页条件字段梳理; @Schema(description = "升级任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @NotNull(message = "升级任务编号不能为空") private Long taskId; - /** - * 设备标识字段。 - *

- * 该字段用于标识设备的名称,通常用于区分不同的设备。 - */ @Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "摄像头A1-1") private String deviceName; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordRespVO.java new file mode 100644 index 0000000000..ff28c68e7a --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordRespVO.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - IoT OTA 升级记录 Response VO") +@Data +public class IotOtaTaskRecordRespVO { + + // TODO @芋艿:梳理字段 + + @Schema(description = "升级记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long firmwareId; + + @Schema(description = "固件版本", requiredMode = Schema.RequiredMode.REQUIRED, example = "v1.0.0") + private String firmwareVersion; + + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long taskId; + + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "iot") + private String productKey; + + @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "iot") + private String deviceName; + + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String deviceId; + + @Schema(description = "来源的固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long fromFirmwareId; + + @Schema(description = "来源的固件版本", requiredMode = Schema.RequiredMode.REQUIRED, example = "v1.0.0") + private String fromFirmwareVersion; + + @Schema(description = "升级状态", requiredMode = Schema.RequiredMode.REQUIRED) + private Integer status; + + @Schema(description = "升级进度,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer progress; + + @Schema(description = "升级进度描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private String description; + + @Schema(description = "升级开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime startTime; + + @Schema(description = "升级结束时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime endTime; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordRespVO.java deleted file mode 100644 index 0f7ddc75f6..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/upgrade/record/IotOtaUpgradeRecordRespVO.java +++ /dev/null @@ -1,109 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record; - -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceMessageDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO; -import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskRecordStatusEnum; -import com.fhs.core.trans.anno.Trans; -import com.fhs.core.trans.constant.TransType; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.time.LocalDateTime; - -@Data -@Schema(description = "管理后台 - IoT OTA 升级记录 Response VO") -public class IotOtaUpgradeRecordRespVO { - - /** - * 升级记录编号 - */ - @Schema(description = "升级记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private Long id; - /** - * 固件编号 - *

- * 关联 {@link IotOtaFirmwareDO#getId()} - */ - @Schema(description = "固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - @Trans(type = TransType.SIMPLE, target = IotOtaFirmwareDO.class, fields = {"version"}, refs = {"firmwareVersion"}) - private Long firmwareId; - /** - * 固件版本 - */ - @Schema(description = "固件版本", requiredMode = Schema.RequiredMode.REQUIRED, example = "v1.0.0") - private String firmwareVersion; - /** - * 任务编号 - *

- * 关联 {@link IotOtaTaskDO#getId()} - */ - @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private Long taskId; - /** - * 产品标识 - *

- * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()} - */ - @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "iot") - private String productKey; - /** - * 设备名称 - *

- * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO#getId()} - */ - @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "iot") - private String deviceName; - /** - * 设备编号 - *

- * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO#getId()} - */ - @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private String deviceId; - /** - * 来源的固件编号 - *

- * 关联 {@link IotDeviceDO#getFirmwareId()} - */ - @Schema(description = "来源的固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - @Trans(type = TransType.SIMPLE, target = IotOtaFirmwareDO.class, fields = {"version"}, refs = {"fromFirmwareVersion"}) - private Long fromFirmwareId; - /** - * 来源的固件版本 - */ - @Schema(description = "来源的固件版本", requiredMode = Schema.RequiredMode.REQUIRED, example = "v1.0.0") - private String fromFirmwareVersion; - /** - * 升级状态 - *

- * 关联 {@link IotOtaTaskRecordStatusEnum} - */ - @Schema(description = "升级状态", requiredMode = Schema.RequiredMode.REQUIRED, allowableValues = {"0", "10", "20", "30", "40", "50"}) - private Integer status; - /** - * 升级进度,百分比 - */ - @Schema(description = "升级进度,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") - private Integer progress; - /** - * 升级进度描述 - *

- * 注意,只记录设备最后一次的升级进度描述 - * 如果想看历史记录,可以查看 {@link IotDeviceMessageDO} 设备日志 - */ - @Schema(description = "升级进度描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") - private String description; - /** - * 升级开始时间 - */ - @Schema(description = "升级开始时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-07-08 07:30:00") - private LocalDateTime startTime; - /** - * 升级结束时间 - */ - @Schema(description = "升级结束时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-07-08 07:30:00") - private LocalDateTime endTime; - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaTaskMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaTaskMapper.java new file mode 100644 index 0000000000..f89fdf79e2 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaTaskMapper.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.ota; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * OTA 升级任务 Mapper + * + * @author Shelly + */ +@Mapper +public interface IotOtaTaskMapper extends BaseMapperX { + + default List selectByFirmwareIdAndName(Long firmwareId, String name) { + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(IotOtaTaskDO::getFirmwareId, firmwareId) + .eqIfPresent(IotOtaTaskDO::getName, name)); + } + + default PageResult selectUpgradeTaskPage(IotOtaTaskPageReqVO pageReqVO) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .eqIfPresent(IotOtaTaskDO::getFirmwareId, pageReqVO.getFirmwareId()) + .likeIfPresent(IotOtaTaskDO::getName, pageReqVO.getName())); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java index 81bb604c6d..53620780bf 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.dal.mysql.ota; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; @@ -80,11 +80,11 @@ public interface IotOtaUpgradeRecordMapper extends BaseMapperX selectUpgradeRecordPage(IotOtaUpgradeRecordPageReqVO pageReqVO) { + default PageResult selectUpgradeRecordPage(IotOtaTaskRecordPageReqVO pageReqVO) { // TODO @li:这里的注释,可以去掉哈;然后下面的“如果”。。。也没必要注释 // 使用LambdaQueryWrapperX构建查询条件,并根据请求参数动态添加查询条件 return selectPage(pageReqVO, new LambdaQueryWrapperX() - .likeIfPresent(IotOtaTaskRecordDO::getDeviceName, pageReqVO.getDeviceName()) // 如果设备名称存在,则添加模糊查询条件 +// .likeIfPresent(IotOtaTaskRecordDO::getDeviceName, pageReqVO.getDeviceName()) // 如果设备名称存在,则添加模糊查询条件 .eqIfPresent(IotOtaTaskRecordDO::getTaskId, pageReqVO.getTaskId())); // 如果任务ID存在,则添加等值查询条件 } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java deleted file mode 100644 index db778b2773..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeTaskMapper.java +++ /dev/null @@ -1,57 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.mysql.ota; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskPageReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO; -import org.apache.ibatis.annotations.Mapper; - -import java.util.List; - -/** - * OTA 升级任务Mapper - * - * @author Shelly - */ -@Mapper -public interface IotOtaUpgradeTaskMapper extends BaseMapperX { - - /** - * 根据固件ID和任务名称查询升级任务列表。 - * - * @param firmwareId 固件ID,用于筛选升级任务 - * @param name 任务名称,用于筛选升级任务 - * @return 符合条件的升级任务列表 - */ - default List selectByFirmwareIdAndName(Long firmwareId, String name) { - return selectList(new LambdaQueryWrapperX() - .eqIfPresent(IotOtaTaskDO::getFirmwareId, firmwareId) - .eqIfPresent(IotOtaTaskDO::getName, name)); - } - - /** - * 分页查询升级任务列表,支持根据固件ID和任务名称进行筛选。 - * - * @param pageReqVO 分页查询请求对象,包含分页参数和筛选条件 - * @return 分页结果,包含符合条件的升级任务列表 - */ - default PageResult selectUpgradeTaskPage(IotOtaUpgradeTaskPageReqVO pageReqVO) { - return selectPage(pageReqVO, new LambdaQueryWrapperX() - .eqIfPresent(IotOtaTaskDO::getFirmwareId, pageReqVO.getFirmwareId()) - .likeIfPresent(IotOtaTaskDO::getName, pageReqVO.getName())); - } - - /** - * 根据任务状态查询升级任务列表 - *

- * 该函数通过传入的任务状态,查询数据库中符合条件的升级任务列表。 - * - * @param status 任务状态,用于筛选升级任务的状态值 - * @return 返回符合条件的升级任务列表,列表中的每个元素为 IotOtaUpgradeTaskDO 对象 - */ - default List selectUpgradeTaskByState(Integer status) { - return selectList(IotOtaTaskDO::getStatus, status); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordService.java similarity index 72% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordService.java index c27380d0ab..4a8367017a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordService.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.iot.service.ota; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO; import jakarta.validation.Valid; @@ -13,7 +13,7 @@ import java.util.Map; * IotOtaUpgradeRecordService 接口定义了与物联网设备OTA升级记录相关的操作。 * 该接口提供了创建、更新、查询、统计和重试升级记录的功能。 */ -public interface IotOtaUpgradeRecordService { +public interface IotOtaTaskRecordService { /** * 批量创建 OTA 升级记录 @@ -23,37 +23,37 @@ public interface IotOtaUpgradeRecordService { * @param firmwareId 固件ID,表示要升级到的固件版本。 * @param upgradeTaskId 升级任务ID,表示此次升级任务的唯一标识。 */ - void createOtaUpgradeRecordBatch(List deviceIds, Long firmwareId, Long upgradeTaskId); + void createOtaTaskRecordBatch(List deviceIds, Long firmwareId, Long upgradeTaskId); /** * 获取 OTA 升级记录的数量统计 * * @return 返回一个 Map,其中键为状态码,值为对应状态的升级记录数量 */ - Map getOtaUpgradeRecordCount(@Valid IotOtaUpgradeRecordPageReqVO pageReqVO); + Map getOtaTaskRecordCount(@Valid IotOtaTaskRecordPageReqVO pageReqVO); /** - * 获取 OTA 升级记录的统计信息。 + * 获取 OTA 升级记录的统计信息 * * @return 返回一个 Map,其中键为状态码,值为对应状态的升级记录统计信息 */ - Map getOtaUpgradeRecordStatistics(Long firmwareId); + Map getOtaTaskRecordStatistics(Long firmwareId); /** - * 获取指定 ID 的 OTA 升级记录的详细信息。 + * 获取指定 ID 的 OTA 升级记录的详细信息 * - * @param id 需要查询的升级记录的ID。 - * @return 返回包含升级记录详细信息的响应对象。 + * @param id 需要查询的升级记录的 ID + * @return 返回包含升级记录详细信息的响应对象 */ - IotOtaTaskRecordDO getUpgradeRecord(Long id); + IotOtaTaskRecordDO getOtaTaskRecord(Long id); /** - * 分页查询 OTA 升级记录。 + * 分页查询 OTA 升级记录 * * @param pageReqVO 包含分页查询条件的请求对象,必须经过验证。 * @return 返回包含分页查询结果的响应对象。 */ - PageResult getUpgradeRecordPage(@Valid IotOtaUpgradeRecordPageReqVO pageReqVO); + PageResult getOtaTaskRecordPage(@Valid IotOtaTaskRecordPageReqVO pageReqVO); /** * 根据任务 ID 取消升级记录 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordServiceImpl.java similarity index 81% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordServiceImpl.java index 0e6d431e27..4f9cb7e1d8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordServiceImpl.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.service.ota; import cn.hutool.core.convert.Convert; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; -import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO; @@ -29,40 +29,39 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; @Slf4j @Service @Validated -public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordService { +public class IotOtaTaskRecordServiceImpl implements IotOtaTaskRecordService { @Resource - private IotOtaUpgradeRecordMapper upgradeRecordMapper; + private IotOtaUpgradeRecordMapper iotOtaUpgradeRecordMapper; + @Resource private IotDeviceService deviceService; @Resource private IotOtaFirmwareService firmwareService; @Resource - private IotOtaUpgradeTaskService upgradeTaskService; + private IotOtaTaskService upgradeTaskService; @Override - public void createOtaUpgradeRecordBatch(List deviceIds, Long firmwareId, Long upgradeTaskId) { + public void createOtaTaskRecordBatch(List deviceIds, Long firmwareId, Long upgradeTaskId) { // 1. 校验升级记录信息是否存在,并且已经取消的任务可以重新开始 deviceIds.forEach(deviceId -> validateUpgradeRecordDuplicate(firmwareId, upgradeTaskId, String.valueOf(deviceId))); // 2. 初始化OTA升级记录列表信息 - IotOtaTaskDO upgradeTask = upgradeTaskService.getUpgradeTask(upgradeTaskId); + IotOtaTaskDO upgradeTask = upgradeTaskService.getOtaTask(upgradeTaskId); IotOtaFirmwareDO firmware = firmwareService.getOtaFirmware(firmwareId); List deviceList = deviceService.getDeviceListByIdList(deviceIds); List upgradeRecordList = deviceList.stream().map(device -> { IotOtaTaskRecordDO upgradeRecord = new IotOtaTaskRecordDO(); upgradeRecord.setFirmwareId(firmware.getId()); upgradeRecord.setTaskId(upgradeTask.getId()); - upgradeRecord.setProductKey(device.getProductKey()); - upgradeRecord.setDeviceName(device.getDeviceName()); - upgradeRecord.setDeviceId(Convert.toStr(device.getId())); + upgradeRecord.setDeviceId(device.getId()); upgradeRecord.setFromFirmwareId(Convert.toLong(device.getFirmwareId())); upgradeRecord.setStatus(IotOtaTaskRecordStatusEnum.PENDING.getStatus()); upgradeRecord.setProgress(0); return upgradeRecord; }).toList(); // 3. 保存数据 - upgradeRecordMapper.insertBatch(upgradeRecordList); + iotOtaUpgradeRecordMapper.insertBatch(upgradeRecordList); // TODO @芋艿:在这里需要处理推送升级任务的逻辑 } @@ -76,9 +75,9 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic */ @Override @Transactional - public Map getOtaUpgradeRecordCount(IotOtaUpgradeRecordPageReqVO pageReqVO) { + public Map getOtaTaskRecordCount(IotOtaTaskRecordPageReqVO pageReqVO) { // 分别查询不同状态的OTA升级记录数量 - List> upgradeRecordCountList = upgradeRecordMapper.selectOtaUpgradeRecordCount( + List> upgradeRecordCountList = iotOtaUpgradeRecordMapper.selectOtaUpgradeRecordCount( pageReqVO.getTaskId(), pageReqVO.getDeviceName()); Map upgradeRecordCountMap = ObjectUtils.defaultIfNull(upgradeRecordCountList.get(0)); Objects.requireNonNull(upgradeRecordCountMap); @@ -89,9 +88,9 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic @Override @Transactional - public Map getOtaUpgradeRecordStatistics(Long firmwareId) { + public Map getOtaTaskRecordStatistics(Long firmwareId) { // 查询并统计不同状态的OTA升级记录数量 - List> upgradeRecordStatisticsList = upgradeRecordMapper.selectOtaUpgradeRecordStatistics(firmwareId); + List> upgradeRecordStatisticsList = iotOtaUpgradeRecordMapper.selectOtaUpgradeRecordStatistics(firmwareId); Map upgradeRecordStatisticsMap = ObjectUtils.defaultIfNull(upgradeRecordStatisticsList.get(0)); Objects.requireNonNull(upgradeRecordStatisticsMap); return upgradeRecordStatisticsMap.entrySet().stream().collect(Collectors.toMap( @@ -100,19 +99,19 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic } @Override - public IotOtaTaskRecordDO getUpgradeRecord(Long id) { - return upgradeRecordMapper.selectById(id); + public IotOtaTaskRecordDO getOtaTaskRecord(Long id) { + return iotOtaUpgradeRecordMapper.selectById(id); } @Override - public PageResult getUpgradeRecordPage(IotOtaUpgradeRecordPageReqVO pageReqVO) { - return upgradeRecordMapper.selectUpgradeRecordPage(pageReqVO); + public PageResult getOtaTaskRecordPage(IotOtaTaskRecordPageReqVO pageReqVO) { + return iotOtaUpgradeRecordMapper.selectUpgradeRecordPage(pageReqVO); } @Override public void cancelUpgradeRecordByTaskId(Long taskId) { // 暂定只有待推送的升级记录可以取消 TODO @芋艿:可以看看阿里云,哪些可以取消 - upgradeRecordMapper.updateUpgradeRecordStatusByTaskIdAndStatus( + iotOtaUpgradeRecordMapper.updateUpgradeRecordStatusByTaskIdAndStatus( IotOtaTaskRecordStatusEnum.CANCELED.getStatus(), taskId, IotOtaTaskRecordStatusEnum.PENDING.getStatus()); } @@ -127,7 +126,7 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic */ private IotOtaTaskRecordDO validateUpgradeRecordExists(Long id) { // 根据ID查询升级记录 - IotOtaTaskRecordDO upgradeRecord = upgradeRecordMapper.selectById(id); + IotOtaTaskRecordDO upgradeRecord = iotOtaUpgradeRecordMapper.selectById(id); // 如果查询结果为空,抛出异常 if (upgradeRecord == null) { throw exception(OTA_UPGRADE_RECORD_NOT_EXISTS); @@ -147,7 +146,7 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic * @param deviceId 设备ID,用于标识特定的设备 */ private void validateUpgradeRecordDuplicate(Long firmwareId, Long taskId, String deviceId) { - IotOtaTaskRecordDO upgradeRecord = upgradeRecordMapper.selectByConditions(firmwareId, taskId, deviceId); + IotOtaTaskRecordDO upgradeRecord = iotOtaUpgradeRecordMapper.selectByConditions(firmwareId, taskId, deviceId); if (upgradeRecord == null) { return; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskService.java new file mode 100644 index 0000000000..f3b5374697 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskService.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.iot.service.ota; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskCreateReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO; +import jakarta.validation.Valid; + +/** + * IoT OTA 升级任务 Service 接口 + * + * @author Shelly Chan + */ +public interface IotOtaTaskService { + + /** + * 创建 OTA升 级任务 + * + * @param createReqVO 创建请求对象 + * @return 升级任务编号 + */ + Long createOtaTask(@Valid IotOtaTaskCreateReqVO createReqVO); + + /** + * 取消 OTA 升级任务 + * + * @param id 升级任务编号 + */ + void cancelOtaTask(Long id); + + /** + * 获取 OTA 升级任务 + * + * @param id 升级任务编号 + * @return 升级任务 + */ + IotOtaTaskDO getOtaTask(Long id); + + /** + * 分页查询 OTA 升级任务 + * + * @param pageReqVO 分页查询请求 + * @return 升级任务分页结果 + */ + PageResult getOtaTaskPage(@Valid IotOtaTaskPageReqVO pageReqVO); + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskServiceImpl.java similarity index 59% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskServiceImpl.java index a61181d49a..13773a090b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskServiceImpl.java @@ -4,12 +4,12 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Convert; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskCreateReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO; -import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaUpgradeTaskMapper; +import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaTaskMapper; import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskDeviceScopeEnum; import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskStatusEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; @@ -22,56 +22,54 @@ import org.springframework.validation.annotation.Validated; import java.util.List; import java.util.Objects; -import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; /** - * IoT OTA升级任务 Service 实现类 + * IoT OTA 升级任务 Service 实现类 * * @author Shelly Chan */ @Service @Validated @Slf4j -public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { +public class IotOtaTaskServiceImpl implements IotOtaTaskService { @Resource - private IotOtaUpgradeTaskMapper upgradeTaskMapper; + private IotOtaTaskMapper otaTaskMapper; @Resource - @Lazy private IotDeviceService deviceService; @Resource - @Lazy - private IotOtaFirmwareService firmwareService; + private IotOtaFirmwareService otaFirmwareService; @Resource - @Lazy - private IotOtaUpgradeRecordService upgradeRecordService; + @Lazy // 延迟,避免循环依赖报错 + private IotOtaTaskRecordService otaUpgradeRecordService; @Override @Transactional(rollbackFor = Exception.class) - public Long createUpgradeTask(IotOtaUpgradeTaskSaveReqVO createReqVO) { + public Long createOtaTask(IotOtaTaskCreateReqVO createReqVO) { // 1.1 校验同一固件的升级任务名称不重复 validateFirmwareTaskDuplicate(createReqVO.getFirmwareId(), createReqVO.getName()); // 1.2 校验固件信息是否存在 - IotOtaFirmwareDO firmware = firmwareService.validateFirmwareExists(createReqVO.getFirmwareId()); + IotOtaFirmwareDO firmware = otaFirmwareService.validateFirmwareExists(createReqVO.getFirmwareId()); // 1.3 补全设备范围信息,并且校验是否又设备可以升级,如果没有设备可以升级,则报错 - validateScopeAndDevice(createReqVO.getScope(), createReqVO.getDeviceIds(), firmware.getProductId()); + validateScopeAndDevice(createReqVO.getDeviceScope(), createReqVO.getDeviceIds(), firmware.getProductId()); // 2. 保存 OTA 升级任务信息到数据库 IotOtaTaskDO upgradeTask = initOtaUpgradeTask(createReqVO, firmware.getProductId()); - upgradeTaskMapper.insert(upgradeTask); + otaTaskMapper.insert(upgradeTask); // 3. 生成设备升级记录信息并存储,等待定时任务轮询 - upgradeRecordService.createOtaUpgradeRecordBatch(upgradeTask.getDeviceIds(), firmware.getId(), upgradeTask.getId()); + // TODO @芋艿:在处理; +// otaUpgradeRecordService.createOtaUpgradeRecordBatch(upgradeTask.getDeviceIds(), firmware.getId(), upgradeTask.getId()); return upgradeTask.getId(); } @Override @Transactional(rollbackFor = Exception.class) - public void cancelUpgradeTask(Long id) { + public void cancelOtaTask(Long id) { // 1.1 校验升级任务是否存在 IotOtaTaskDO upgradeTask = validateUpgradeTaskExists(id); // 1.2 校验升级任务是否可以取消 @@ -81,52 +79,34 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { } // 2. 更新 OTA 升级任务状态为已取消 - upgradeTaskMapper.updateById(IotOtaTaskDO.builder() + otaTaskMapper.updateById(IotOtaTaskDO.builder() .id(id).status(IotOtaTaskStatusEnum.CANCELED.getStatus()) .build()); // 3. 更新 OTA 升级记录状态为已取消 - upgradeRecordService.cancelUpgradeRecordByTaskId(id); + otaUpgradeRecordService.cancelUpgradeRecordByTaskId(id); } @Override - public IotOtaTaskDO getUpgradeTask(Long id) { - return upgradeTaskMapper.selectById(id); + public IotOtaTaskDO getOtaTask(Long id) { + return otaTaskMapper.selectById(id); } @Override - public PageResult getUpgradeTaskPage(IotOtaUpgradeTaskPageReqVO pageReqVO) { - return upgradeTaskMapper.selectUpgradeTaskPage(pageReqVO); - } - - @Override - public List getUpgradeTaskByState(Integer state) { - return upgradeTaskMapper.selectUpgradeTaskByState(state); - } - - @Override - public void updateUpgradeTaskStatus(Long id, Integer status) { - upgradeTaskMapper.updateById(IotOtaTaskDO.builder().id(id).status(status).build()); + public PageResult getOtaTaskPage(IotOtaTaskPageReqVO pageReqVO) { + return otaTaskMapper.selectUpgradeTaskPage(pageReqVO); } /** * 校验固件升级任务是否重复 */ private void validateFirmwareTaskDuplicate(Long firmwareId, String taskName) { - List upgradeTaskList = upgradeTaskMapper.selectByFirmwareIdAndName(firmwareId, taskName); + List upgradeTaskList = otaTaskMapper.selectByFirmwareIdAndName(firmwareId, taskName); if (CollUtil.isNotEmpty(upgradeTaskList)) { throw exception(OTA_UPGRADE_TASK_NAME_DUPLICATE); } } - /** - * 验证升级任务的范围和设备列表的有效性。 - * - * @param scope 升级任务的范围,参考 IotOtaUpgradeTaskScopeEnum 枚举值 - * @param deviceIds 设备ID列表,当范围为"选择设备"时,该列表不能为空 - * @param productId 产品ID,当范围为"所有设备"时,用于获取设备列表 - * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,抛出相应的异常 - */ private void validateScopeAndDevice(Integer scope, List deviceIds, Long productId) { if (Objects.equals(scope, IotOtaTaskDeviceScopeEnum.SELECT.getScope())) { if (CollUtil.isEmpty(deviceIds)) { @@ -143,30 +123,24 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { } } - /** - * 验证升级任务是否存在 - */ private IotOtaTaskDO validateUpgradeTaskExists(Long id) { - IotOtaTaskDO upgradeTask = upgradeTaskMapper.selectById(id); + IotOtaTaskDO upgradeTask = otaTaskMapper.selectById(id); if (Objects.isNull(upgradeTask)) { throw exception(OTA_UPGRADE_TASK_NOT_EXISTS); } return upgradeTask; } - /** - * 初始化升级任务 - */ - private IotOtaTaskDO initOtaUpgradeTask(IotOtaUpgradeTaskSaveReqVO createReqVO, Long productId) { + private IotOtaTaskDO initOtaUpgradeTask(IotOtaTaskCreateReqVO createReqVO, Long productId) { IotOtaTaskDO upgradeTask = BeanUtils.toBean(createReqVO, IotOtaTaskDO.class); upgradeTask.setDeviceTotalCount(Convert.toLong(CollUtil.size(createReqVO.getDeviceIds()))) .setStatus(IotOtaTaskStatusEnum.IN_PROGRESS.getStatus()); - if (Objects.equals(createReqVO.getScope(), IotOtaTaskDeviceScopeEnum.ALL.getScope())) { + if (Objects.equals(createReqVO.getDeviceScope(), IotOtaTaskDeviceScopeEnum.ALL.getScope())) { List deviceList = deviceService.getDeviceListByProductId(productId); upgradeTask.setDeviceTotalCount((long) deviceList.size()); - upgradeTask.setDeviceIds( - deviceList.stream().map(IotDeviceDO::getId).collect(Collectors.toList())); +// upgradeTask.setDeviceIds( +// deviceList.stream().map(IotDeviceDO::getId).collect(Collectors.toList())); } return upgradeTask; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java deleted file mode 100644 index 9611d151f3..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskService.java +++ /dev/null @@ -1,68 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.ota; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO; -import jakarta.validation.Valid; - -import java.util.List; - -/** - * IoT OTA升级任务 Service 接口 - * - * @author Shelly Chan - */ -public interface IotOtaUpgradeTaskService { - - /** - * 创建OTA升级任务 - * - * @param createReqVO OTA升级任务的创建请求对象,包含创建任务所需的信息 - * @return 创建成功的OTA升级任务的ID - */ - Long createUpgradeTask(@Valid IotOtaUpgradeTaskSaveReqVO createReqVO); - - /** - * 取消OTA升级任务 - * - * @param id 要取消的OTA升级任务的ID - */ - void cancelUpgradeTask(Long id); - - /** - * 根据ID获取OTA升级任务的详细信息 - * - * @param id OTA升级任务的ID - * @return OTA升级任务的详细信息对象 - */ - IotOtaTaskDO getUpgradeTask(Long id); - - /** - * 分页查询OTA升级任务 - * - * @param pageReqVO OTA升级任务的分页查询请求对象,包含查询条件和分页信息 - * @return 分页查询结果,包含OTA升级任务列表和总记录数 - */ - PageResult getUpgradeTaskPage(@Valid IotOtaUpgradeTaskPageReqVO pageReqVO); - - /** - * 根据任务状态获取升级任务列表 - * - * @param state 任务状态,用于筛选符合条件的升级任务 - * @return 返回符合指定状态的升级任务列表,列表中的元素为 IotOtaUpgradeTaskDO 对象 - */ - List getUpgradeTaskByState(Integer state); - - /** - * 更新升级任务的状态。 - *

- * 该函数用于根据任务ID更新指定升级任务的状态。通常用于在任务执行过程中 - * 更新任务的状态,例如从“进行中”变为“已完成”或“失败”。 - * - * @param id 升级任务的唯一标识符,类型为Long。不能为null。 - * @param status 要更新的任务状态,类型为Integer。通常表示任务的状态码,如0表示未开始,1表示进行中,2表示已完成等。 - */ - void updateUpgradeTaskStatus(Long id, Integer status); - -} From ecf6a4a8463d416dc5a6b8b1d143458f4b98dd89 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 1 Jul 2025 22:10:29 +0800 Subject: [PATCH 32/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E5=A2=9E=E5=8A=A0=20OTA=20=E5=8D=87?= =?UTF-8?q?=E7=BA=A7=E4=BB=BB=E5=8A=A1=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/ota/IotOtaTaskRecordController.java | 38 ++-- .../ota/vo/task/IotOtaTaskCreateReqVO.java | 2 + .../record/IotOtaTaskRecordPageReqVO.java | 7 +- .../task/record/IotOtaTaskRecordRespVO.java | 14 -- .../dal/dataobject/device/IotDeviceDO.java | 2 +- .../iot/dal/dataobject/ota/IotOtaTaskDO.java | 2 +- .../dataobject/ota/IotOtaTaskRecordDO.java | 15 +- .../dal/mysql/ota/IotOtaFirmwareMapper.java | 13 +- .../iot/dal/mysql/ota/IotOtaTaskMapper.java | 14 +- .../dal/mysql/ota/IotOtaTaskRecordMapper.java | 41 ++++ .../mysql/ota/IotOtaUpgradeRecordMapper.java | 111 ----------- .../module/iot/enums/DictTypeConstants.java | 3 + .../module/iot/enums/ErrorCodeConstants.java | 23 ++- .../enums/ota/IotOtaTaskRecordStatusEnum.java | 14 ++ .../iot/service/device/IotDeviceService.java | 17 +- .../service/device/IotDeviceServiceImpl.java | 14 +- .../service/ota/IotOtaFirmwareService.java | 2 +- .../ota/IotOtaFirmwareServiceImpl.java | 28 ++- .../service/ota/IotOtaTaskRecordService.java | 60 +++--- .../ota/IotOtaTaskRecordServiceImpl.java | 183 +++++------------- .../iot/service/ota/IotOtaTaskService.java | 2 +- .../service/ota/IotOtaTaskServiceImpl.java | 120 ++++++------ .../rule/data/IotDataRuleServiceImpl.java | 2 +- 23 files changed, 278 insertions(+), 449 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaTaskRecordMapper.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskRecordController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskRecordController.java index e2b8d0aa48..1110ff8f49 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskRecordController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskRecordController.java @@ -9,12 +9,16 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO; import cn.iocoder.yudao.module.iot.service.ota.IotOtaTaskRecordService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; import java.util.Map; @@ -22,31 +26,29 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @Tag(name = "管理后台 - IoT OTA 升级任务记录") @RestController -@RequestMapping("/iot/ota/task-record") +@RequestMapping("/iot/ota/task/record") @Validated public class IotOtaTaskRecordController { @Resource private IotOtaTaskRecordService otaTaskRecordService; - @GetMapping("/get-statistics") - @Operation(summary = "固件升级设备统计") + @GetMapping("/get-status-count") + @Operation(summary = "获得 OTA 升级记录状态统计") + @Parameters({ + @Parameter(name = "firmwareId", description = "固件编号", example = "1024"), + @Parameter(name = "taskId", description = "升级任务编号", example = "2048") + }) @PreAuthorize("@ss.hasPermission('iot:ota-task-record:query')") - @Parameter(name = "firmwareId", description = "固件编号", required = true, example = "1024") - public CommonResult> getOtaTaskRecordStatistics(@RequestParam(value = "firmwareId") Long firmwareId) { - return success(otaTaskRecordService.getOtaTaskRecordStatistics(firmwareId)); - } - - @GetMapping("/get-count") - @Operation(summary = "获得升级记录分页 tab 数量") - @PreAuthorize("@ss.hasPermission('iot:ota-task-record:query')") - public CommonResult> getOtaTaskRecordCount(@Valid IotOtaTaskRecordPageReqVO pageReqVO) { - return success(otaTaskRecordService.getOtaTaskRecordCount(pageReqVO)); + public CommonResult> getOtaTaskRecordStatusCountMap( + @RequestParam(value = "firmwareId", required = false) Long firmwareId, + @RequestParam(value = "taskId", required = false) Long taskId) { + return success(otaTaskRecordService.getOtaTaskRecordStatusCountMap(firmwareId, taskId)); } @GetMapping("/page") - @Operation(summary = "获得升级记录分页") - @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") + @Operation(summary = "获得 OTA 升级记录分页") + @PreAuthorize("@ss.hasPermission('iot:ota-task-record:query')") public CommonResult> getOtaTaskRecordPage( @Valid IotOtaTaskRecordPageReqVO pageReqVO) { PageResult pageResult = otaTaskRecordService.getOtaTaskRecordPage(pageReqVO); @@ -54,8 +56,8 @@ public class IotOtaTaskRecordController { } @GetMapping("/get") - @Operation(summary = "获得升级记录") - @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')") + @Operation(summary = "获得 OTA 升级记录") + @PreAuthorize("@ss.hasPermission('iot:ota-task-record:query')") @Parameter(name = "id", description = "升级记录编号", required = true, example = "1024") public CommonResult getOtaTaskRecord(@RequestParam("id") Long id) { IotOtaTaskRecordDO upgradeRecord = otaTaskRecordService.getOtaTaskRecord(id); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/IotOtaTaskCreateReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/IotOtaTaskCreateReqVO.java index 853e10c548..65bc07c1bf 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/IotOtaTaskCreateReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/IotOtaTaskCreateReqVO.java @@ -32,4 +32,6 @@ public class IotOtaTaskCreateReqVO { @Schema(description = "选中的设备编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3") private List deviceIds; + // TODO @li:如果 deviceScope 等于 2 时,deviceIds 校验非空; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordPageReqVO.java index f6d1cf18be..839a8b06d8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordPageReqVO.java @@ -2,19 +2,16 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record; import cn.iocoder.yudao.framework.common.pojo.PageParam; import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotNull; import lombok.Data; @Schema(description = "管理后台 - IoT OTA 升级记录分页 Request VO") @Data public class IotOtaTaskRecordPageReqVO extends PageParam { - // TODO @芋艿:分页条件字段梳理; - @Schema(description = "升级任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - @NotNull(message = "升级任务编号不能为空") + @Schema(description = "升级任务编号", example = "1024") private Long taskId; - @Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "摄像头A1-1") + @Schema(description = "设备标识", example = "摄像头A1-1") private String deviceName; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordRespVO.java index ff28c68e7a..4de8204f0b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordRespVO.java @@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import java.time.LocalDateTime; - @Schema(description = "管理后台 - IoT OTA 升级记录 Response VO") @Data public class IotOtaTaskRecordRespVO { @@ -23,12 +21,6 @@ public class IotOtaTaskRecordRespVO { @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Long taskId; - @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "iot") - private String productKey; - - @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "iot") - private String deviceName; - @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private String deviceId; @@ -47,10 +39,4 @@ public class IotOtaTaskRecordRespVO { @Schema(description = "升级进度描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") private String description; - @Schema(description = "升级开始时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime startTime; - - @Schema(description = "升级结束时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime endTime; - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java index 987c6b55ee..3ceb30b18c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java @@ -117,7 +117,7 @@ public class IotDeviceDO extends TenantBaseDO { * * 关联 {@link IotOtaFirmwareDO#getId()} */ - private String firmwareId; + private Long firmwareId; /** * 设备密钥,用于设备认证 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaTaskDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaTaskDO.java index d2452950af..4c9124b89f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaTaskDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaTaskDO.java @@ -61,7 +61,7 @@ public class IotOtaTaskDO extends BaseDO { /** * 设备总数数量 */ - private Long deviceTotalCount; + private Integer deviceTotalCount; /** * 设备成功数量 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaTaskRecordDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaTaskRecordDO.java index 8cd0173396..28b4ca6734 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaTaskRecordDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaTaskRecordDO.java @@ -7,9 +7,10 @@ import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskRecordStatusEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; - -import java.time.LocalDateTime; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; /** * IoT OTA 升级任务记录 DO @@ -70,13 +71,5 @@ public class IotOtaTaskRecordDO extends BaseDO { * 如果想看历史记录,可以查看 {@link IotDeviceMessageDO} 设备日志 */ private String description; - /** - * 升级开始时间 - */ - private LocalDateTime startTime; - /** - * 升级结束时间 - */ - private LocalDateTime endTime; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java index 86288674c1..fea6272d40 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java @@ -7,20 +7,11 @@ import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwa import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; import org.apache.ibatis.annotations.Mapper; -import java.util.List; - @Mapper public interface IotOtaFirmwareMapper extends BaseMapperX { - /** - * 根据产品ID和固件版本号查询固件信息列表。 - * - * @param productId 产品ID,用于筛选固件信息。 - * @param version 固件版本号,用于筛选固件信息。 - * @return 返回符合条件的固件信息列表。 - */ - default List selectByProductIdAndVersion(Long productId, String version) { - return selectList(IotOtaFirmwareDO::getProductId, productId, + default IotOtaFirmwareDO selectByProductIdAndVersion(Long productId, String version) { + return selectOne(IotOtaFirmwareDO::getProductId, productId, IotOtaFirmwareDO::getVersion, version); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaTaskMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaTaskMapper.java index f89fdf79e2..a792dd3cc3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaTaskMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaTaskMapper.java @@ -7,20 +7,12 @@ import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskPageRe import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO; import org.apache.ibatis.annotations.Mapper; -import java.util.List; - -/** - * OTA 升级任务 Mapper - * - * @author Shelly - */ @Mapper public interface IotOtaTaskMapper extends BaseMapperX { - default List selectByFirmwareIdAndName(Long firmwareId, String name) { - return selectList(new LambdaQueryWrapperX() - .eqIfPresent(IotOtaTaskDO::getFirmwareId, firmwareId) - .eqIfPresent(IotOtaTaskDO::getName, name)); + default IotOtaTaskDO selectByFirmwareIdAndName(Long firmwareId, String name) { + return selectOne(IotOtaTaskDO::getFirmwareId, firmwareId, + IotOtaTaskDO::getName, name); } default PageResult selectUpgradeTaskPage(IotOtaTaskPageReqVO pageReqVO) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaTaskRecordMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaTaskRecordMapper.java new file mode 100644 index 0000000000..d6d147107f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaTaskRecordMapper.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.ota; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; +import java.util.Set; + +@Mapper +public interface IotOtaTaskRecordMapper extends BaseMapperX { + + default List selectListByFirmwareIdAndTaskId(Long firmwareId, Long taskId) { + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(IotOtaTaskRecordDO::getFirmwareId, firmwareId) + .eqIfPresent(IotOtaTaskRecordDO::getTaskId, taskId) + .select(IotOtaTaskRecordDO::getDeviceId, IotOtaTaskRecordDO::getStatus)); + } + + default PageResult selectPage(IotOtaTaskRecordPageReqVO pageReqVO) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .eqIfPresent(IotOtaTaskRecordDO::getTaskId, pageReqVO.getTaskId())); + } + + default void updateByTaskIdAndStatus(Long taskId, Integer fromStatus, IotOtaTaskRecordDO updateRecord) { + update(updateRecord, new LambdaUpdateWrapper() + .eq(IotOtaTaskRecordDO::getTaskId, taskId) + .eq(IotOtaTaskRecordDO::getStatus, fromStatus)); + } + + default List selectListByDeviceIdAndStatus(Set deviceIds, Set statuses) { + return selectList(new LambdaQueryWrapperX() + .inIfPresent(IotOtaTaskRecordDO::getDeviceId, deviceIds) + .inIfPresent(IotOtaTaskRecordDO::getStatus, statuses)); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java deleted file mode 100644 index 53620780bf..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaUpgradeRecordMapper.java +++ /dev/null @@ -1,111 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.mysql.ota; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordPageReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO; -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.apache.ibatis.annotations.Select; - -import java.util.List; -import java.util.Map; - -@Mapper -public interface IotOtaUpgradeRecordMapper extends BaseMapperX { - - // TODO @li:selectByFirmwareIdAndTaskIdAndDeviceId;让方法自解释 - /** - * 根据条件查询单个OTA升级记录 - * - * @param firmwareId 固件ID,可选参数,用于筛选固件ID匹配的记录 - * @param taskId 任务ID,可选参数,用于筛选任务ID匹配的记录 - * @param deviceId 设备ID,可选参数,用于筛选设备ID匹配的记录 - * @return 返回符合条件的单个OTA升级记录,如果不存在则返回null - */ - default IotOtaTaskRecordDO selectByConditions(Long firmwareId, Long taskId, String deviceId) { - // 使用LambdaQueryWrapperX构建查询条件,根据传入的参数动态添加查询条件 - return selectOne(new LambdaQueryWrapperX() - .eqIfPresent(IotOtaTaskRecordDO::getFirmwareId, firmwareId) - .eqIfPresent(IotOtaTaskRecordDO::getTaskId, taskId) - .eqIfPresent(IotOtaTaskRecordDO::getDeviceId, deviceId)); - } - - // TODO @li:这个是不是 groupby status 就 ok 拉? - /** - * 根据任务ID和设备名称查询OTA升级记录的状态统计信息。 - * 该函数通过SQL查询统计不同状态(0到5)的记录数量,并返回一个包含统计结果的Map列表。 - * - * @param taskId 任务ID,用于筛选特定任务的OTA升级记录。 - * @param deviceName 设备名称,支持模糊查询,用于筛选特定设备的OTA升级记录。 - * @return 返回一个Map列表,每个Map包含不同状态(0到5)的记录数量。 - */ - @Select("select count(case when status = 0 then 1 else 0) as `0` " + - "count(case when status = 1 then 1 else 0) as `1` " + - "count(case when status = 2 then 1 else 0) as `2` " + - "count(case when status = 3 then 1 else 0) as `3` " + - "count(case when status = 4 then 1 else 0) as `4` " + - "count(case when status = 5 then 1 else 0) as `5` " + - "from iot_ota_upgrade_record " + - "where task_id = #{taskId} " + - "and device_name like concat('%', #{deviceName}, '%') " + - "and status = #{status}") - List> selectOtaUpgradeRecordCount(@Param("taskId") Long taskId, - @Param("deviceName") String deviceName); - - /** - * 根据固件ID查询OTA升级记录的状态统计信息。 - * 该函数通过SQL查询统计不同状态(0到5)的记录数量,并返回一个包含统计结果的Map列表。 - * - * @param firmwareId 固件ID,用于筛选特定固件的OTA升级记录。 - * @return 返回一个Map列表,每个Map包含不同状态(0到5)的记录数量。 - */ - @Select("select count(case when status = 0 then 1 else 0) as `0` " + - "count(case when status = 1 then 1 else 0) as `1` " + - "count(case when status = 2 then 1 else 0) as `2` " + - "count(case when status = 3 then 1 else 0) as `3` " + - "count(case when status = 4 then 1 else 0) as `4` " + - "count(case when status = 5 then 1 else 0) as `5` " + - "from iot_ota_upgrade_record " + - "where firmware_id = #{firmwareId}") - List> selectOtaUpgradeRecordStatistics(Long firmwareId); - - // TODO @li:这里的注释,可以去掉哈 - /** - * 根据分页查询条件获取 OTA升级记录的分页结果 - * - * @param pageReqVO 分页查询请求参数,包含设备名称、任务ID等查询条件 - * @return 返回分页查询结果,包含符合条件的 OTA升级记录列表 - */ - // TODO @li:selectPage 就 ok 拉。 - default PageResult selectUpgradeRecordPage(IotOtaTaskRecordPageReqVO pageReqVO) { - // TODO @li:这里的注释,可以去掉哈;然后下面的“如果”。。。也没必要注释 - // 使用LambdaQueryWrapperX构建查询条件,并根据请求参数动态添加查询条件 - return selectPage(pageReqVO, new LambdaQueryWrapperX() -// .likeIfPresent(IotOtaTaskRecordDO::getDeviceName, pageReqVO.getDeviceName()) // 如果设备名称存在,则添加模糊查询条件 - .eqIfPresent(IotOtaTaskRecordDO::getTaskId, pageReqVO.getTaskId())); // 如果任务ID存在,则添加等值查询条件 - } - - // TODO @li:这里的注释,可以去掉哈 - /** - * 根据任务ID和状态更新升级记录的状态 - *

- * 该函数用于将符合指定任务ID和状态的升级记录的状态更新为新的状态。 - * - * @param setStatus 要设置的新状态值,类型为Integer - * @param taskId 要更新的升级记录对应的任务ID,类型为Long - * @param whereStatus 用于筛选升级记录的当前状态值,类型为Integer - */ - // TODO @li:改成 updateByTaskIdAndStatus(taskId, status, IotOtaUpgradeRecordDO) 更通用一些。 - default void updateUpgradeRecordStatusByTaskIdAndStatus(Integer setStatus, Long taskId, Integer whereStatus) { - // 使用LambdaUpdateWrapper构建更新条件,将指定状态的记录更新为指定状态 - update(new LambdaUpdateWrapper() - .set(IotOtaTaskRecordDO::getStatus, setStatus) - .eq(IotOtaTaskRecordDO::getTaskId, taskId) - .eq(IotOtaTaskRecordDO::getStatus, whereStatus) - ); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java index b7750bd0b0..384bf734e6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java @@ -16,4 +16,7 @@ public class DictTypeConstants { public static final String ALERT_LEVEL = "iot_alert_level"; + public static final String OTA_TASK_DEVICE_SCOPE = "iot_ota_task_device_scope"; + public static final String OTA_TASK_STATUS = "iot_ota_task_status"; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 8e445bf540..63d4a253e4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -41,20 +41,25 @@ public interface ErrorCodeConstants { ErrorCode DEVICE_GROUP_NOT_EXISTS = new ErrorCode(1_050_005_000, "设备分组不存在"); ErrorCode DEVICE_GROUP_DELETE_FAIL_DEVICE_EXISTS = new ErrorCode(1_050_005_001, "设备分组下存在设备,不允许删除"); - // ========== 固件相关 1-050-008-000 ========== + // ========== OTA 固件相关 1-050-008-000 ========== ErrorCode OTA_FIRMWARE_NOT_EXISTS = new ErrorCode(1_050_008_000, "固件信息不存在"); ErrorCode OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE = new ErrorCode(1_050_008_001, "产品版本号重复"); - ErrorCode OTA_UPGRADE_TASK_NOT_EXISTS = new ErrorCode(1_050_008_100, "升级任务不存在"); - ErrorCode OTA_UPGRADE_TASK_NAME_DUPLICATE = new ErrorCode(1_050_008_101, "升级任务名称重复"); - ErrorCode OTA_UPGRADE_TASK_DEVICE_IDS_EMPTY = new ErrorCode(1_050_008_102, "设备编号列表不能为空"); - ErrorCode OTA_UPGRADE_TASK_DEVICE_LIST_EMPTY = new ErrorCode(1_050_008_103, "设备列表不能为空"); - ErrorCode OTA_UPGRADE_TASK_CANNOT_CANCEL = new ErrorCode(1_050_008_104, "升级任务不能取消"); + // ========== OTA 升级任务相关 1-050-008-100 ========== - ErrorCode OTA_UPGRADE_RECORD_NOT_EXISTS = new ErrorCode(1_050_008_200, "升级记录不存在"); - ErrorCode OTA_UPGRADE_RECORD_DUPLICATE = new ErrorCode(1_050_008_201, "升级记录重复"); - ErrorCode OTA_UPGRADE_RECORD_CANNOT_RETRY = new ErrorCode(1_050_008_202, "升级记录不能重试"); + ErrorCode OTA_TASK_NOT_EXISTS = new ErrorCode(1_050_008_100, "升级任务不存在"); + ErrorCode OTA_TASK_CREATE_FAIL_NAME_DUPLICATE = new ErrorCode(1_050_008_101, "创建 OTA 任务失败,原因:任务名称重复"); + ErrorCode OTA_TASK_CREATE_FAIL_DEVICE_FIRMWARE_EXISTS = new ErrorCode(1_050_008_102, + "创建 OTA 任务失败,原因:设备({})已经是该固件版本"); + ErrorCode OTA_TASK_CREATE_FAIL_DEVICE_OTA_IN_PROCESS = new ErrorCode(1_050_008_102, + "创建 OTA 任务失败,原因:设备({})已经在升级中..."); + ErrorCode OTA_TASK_CREATE_FAIL_DEVICE_EMPTY = new ErrorCode(1_050_008_103, "创建 OTA 任务失败,原因:没有可升级的设备"); + ErrorCode OTA_TASK_CANCEL_FAIL_STATUS_END = new ErrorCode(1_050_008_104, "取消 OTA 任务失败,原因:任务状态不是进行中"); + + // ========== OTA 升级任务相关 1-050-008-100 ========== + + ErrorCode OTA_TASK_RECORD_NOT_EXISTS = new ErrorCode(1_050_008_200, "升级记录不存在"); // ========== IoT 数据流转规则 1-050-010-000 ========== ErrorCode DATA_RULE_NOT_EXISTS = new ErrorCode(1_050_010_000, "数据流转规则不存在"); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaTaskRecordStatusEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaTaskRecordStatusEnum.java index c95b033d70..8c423949b7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaTaskRecordStatusEnum.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaTaskRecordStatusEnum.java @@ -2,10 +2,13 @@ package cn.iocoder.yudao.module.iot.enums.ota; import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; import lombok.Getter; import lombok.RequiredArgsConstructor; import java.util.Arrays; +import java.util.List; +import java.util.Set; /** * IoT OTA 升级任务记录的状态枚举 @@ -26,6 +29,17 @@ public enum IotOtaTaskRecordStatusEnum implements ArrayValuable { public static final Integer[] ARRAYS = Arrays.stream(values()) .map(IotOtaTaskRecordStatusEnum::getStatus).toArray(Integer[]::new); + public static final Set IN_PROCESS_STATUSES = SetUtils.asSet( + PENDING.getStatus(), + PUSHED.getStatus(), + UPGRADING.getStatus(), + SUCCESS.getStatus()); + + public static final List PRIORITY_STATUSES = Arrays.asList( + SUCCESS.getStatus(), + PENDING.getStatus(), PUSHED.getStatus(), UPGRADING.getStatus(), + FAILURE.getStatus(), CANCELED.getStatus()); + /** * 状态 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index 7bfb9800d0..328d7bd5d6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -12,7 +12,6 @@ import java.time.LocalDateTime; import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.Set; /** * IoT 设备 Service 接口 @@ -155,21 +154,13 @@ public interface IotDeviceService { List getDeviceListByState(Integer state); /** - * 根据产品ID获取设备列表 + * 根据产品编号,获取设备列表 * - * @param productId 产品ID,用于查询特定产品的设备列表 - * @return 返回与指定产品ID关联的设备列表,列表中的每个元素为IotDeviceDO对象 + * @param productId 产品编号 + * @return 设备列表 */ List getDeviceListByProductId(Long productId); - /** - * 根据设备ID列表获取设备信息列表 - * - * @param deviceIdList 设备ID列表,包含需要查询的设备ID - * @return 返回与设备ID列表对应的设备信息列表,列表中的每个元素为IotDeviceDO对象 - */ - List getDeviceListByIdList(List deviceIdList); - /** * 基于产品编号,获得设备数量 * @@ -248,6 +239,6 @@ public interface IotDeviceService { * * @param ids 设备编号数组 */ - void validateDevicesExist(Set ids); + List validateDeviceListExists(Collection ids); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 30f7b26878..4cdf859d06 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -278,11 +278,6 @@ public class IotDeviceServiceImpl implements IotDeviceService { return deviceMapper.selectListByProductId(productId); } - @Override - public List getDeviceListByIdList(List deviceIdList) { - return deviceMapper.selectByIds(deviceIdList); - } - @Override public void updateDeviceState(IotDeviceDO device, Integer state) { // 1. 更新状态和时间 @@ -474,14 +469,15 @@ public class IotDeviceServiceImpl implements IotDeviceService { } @Override - public void validateDevicesExist(Set ids) { + public List validateDeviceListExists(Collection ids) { if (CollUtil.isEmpty(ids)) { - return; + return Collections.emptyList(); } - List deviceIds = deviceMapper.selectByIds(ids); - if (deviceIds.size() != ids.size()) { + List devices = deviceMapper.selectByIds(ids); + if (devices.size() != ids.size()) { throw exception(DEVICE_NOT_EXISTS); } + return devices; } private IotDeviceServiceImpl getSelf() { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java index 9b9ffaf796..14fc38cde7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java @@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; import jakarta.validation.Valid; /** - * OTA 固件管理 Service + * OTA 固件管理 Service 接口 * * @author Shelly Chan */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java index f0d22ea22f..a5da1dba3f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java @@ -23,9 +23,14 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.OTA_FIRMWARE_NOT_EXISTS; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE; -@Slf4j +/** + * OTA 固件管理 Service 实现类 + * + * @author Shelly Chan + */ @Service @Validated +@Slf4j public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService { @Resource @@ -37,7 +42,9 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService { @Override public Long createOtaFirmware(IotOtaFirmwareCreateReqVO saveReqVO) { // 1.1 校验固件产品 + 版本号不能重复 - validateProductAndVersionDuplicate(saveReqVO.getProductId(), saveReqVO.getVersion()); + if (otaFirmwareMapper.selectByProductIdAndVersion(saveReqVO.getProductId(), saveReqVO.getVersion()) != null) { + throw exception(OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE); + } // 1.2 校验产品存在 productService.validateProductExists(saveReqVO.getProductId()); @@ -83,25 +90,12 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService { return firmware; } - /** - * 验证产品和版本号是否重复 - */ - private void validateProductAndVersionDuplicate(Long productId, String version) { - // 只查询1条记录检查是否存在 - IotOtaFirmwareDO firmware = otaFirmwareMapper.selectOne(IotOtaFirmwareDO::getProductId, productId, - IotOtaFirmwareDO::getVersion, version); - if (firmware != null) { - throw exception(OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE); - } - } - /** * 计算文件签名 - * + * * @param firmware 固件对象 - * @throws Exception 下载或计算签名失败时抛出异常 */ - private void calculateFileDigest(IotOtaFirmwareDO firmware) throws Exception { + private void calculateFileDigest(IotOtaFirmwareDO firmware) { String fileUrl = firmware.getFileUrl(); // 下载文件并计算签名 byte[] fileBytes = HttpUtil.downloadBytes(fileUrl); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordService.java index 4a8367017a..eb5a04ac2a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordService.java @@ -2,67 +2,67 @@ package cn.iocoder.yudao.module.iot.service.ota; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO; import jakarta.validation.Valid; import java.util.List; import java.util.Map; +import java.util.Set; -// TODO @li:注释写的有点冗余,可以看看别的模块哈。= = AI 生成的注释,有的时候太啰嗦了,需要处理下的哈 /** - * IotOtaUpgradeRecordService 接口定义了与物联网设备OTA升级记录相关的操作。 - * 该接口提供了创建、更新、查询、统计和重试升级记录的功能。 + * IoT OTA 升级记录 Service 接口 */ public interface IotOtaTaskRecordService { /** * 批量创建 OTA 升级记录 - * 该函数用于为指定的设备列表、固件ID和升级任务ID创建OTA升级记录。 * - * @param deviceIds 设备ID列表,表示需要升级的设备集合。 - * @param firmwareId 固件ID,表示要升级到的固件版本。 - * @param upgradeTaskId 升级任务ID,表示此次升级任务的唯一标识。 + * @param devices 设备列表 + * @param firmwareId 固件编号 + * @param taskId 任务编号 */ - void createOtaTaskRecordBatch(List deviceIds, Long firmwareId, Long upgradeTaskId); + void createOtaTaskRecordList(List devices, Long firmwareId, Long taskId); /** - * 获取 OTA 升级记录的数量统计 + * 获取 OTA 升级记录的状态统计 * - * @return 返回一个 Map,其中键为状态码,值为对应状态的升级记录数量 + * @param firmwareId 固件编号 + * @param taskId 任务编号 + * @return 状态统计 Map,key 为状态码,value 为对应状态的升级记录数量 */ - Map getOtaTaskRecordCount(@Valid IotOtaTaskRecordPageReqVO pageReqVO); + Map getOtaTaskRecordStatusCountMap(Long firmwareId, Long taskId); /** - * 获取 OTA 升级记录的统计信息 + * 获取 OTA 升级记录 * - * @return 返回一个 Map,其中键为状态码,值为对应状态的升级记录统计信息 - */ - Map getOtaTaskRecordStatistics(Long firmwareId); - - /** - * 获取指定 ID 的 OTA 升级记录的详细信息 - * - * @param id 需要查询的升级记录的 ID - * @return 返回包含升级记录详细信息的响应对象 + * @param id 编号 + * @return OTA 升级记录 */ IotOtaTaskRecordDO getOtaTaskRecord(Long id); /** - * 分页查询 OTA 升级记录 + * 获取 OTA 升级记录分页 * - * @param pageReqVO 包含分页查询条件的请求对象,必须经过验证。 - * @return 返回包含分页查询结果的响应对象。 + * @param pageReqVO 分页查询 + * @return OTA 升级记录分页 */ PageResult getOtaTaskRecordPage(@Valid IotOtaTaskRecordPageReqVO pageReqVO); /** - * 根据任务 ID 取消升级记录 - *

- * 该函数用于根据给定的任务ID,取消与该任务相关的升级记录。通常用于在任务执行失败或用户手动取消时, - * 清理或标记相关的升级记录为取消状态。 + * 根据 OTA 任务编号,取消未结束的升级记录 * - * @param taskId 要取消升级记录的任务ID。该ID唯一标识一个任务,通常由任务管理系统生成。 + * @param taskId 升级任务编号 */ - void cancelUpgradeRecordByTaskId(Long taskId); + void cancelTaskRecordListByTaskId(Long taskId); + + /** + * 根据设备编号和记录状态,获取 OTA 升级记录列表 + * + * @param deviceIds 设备编号集合 + * @param statuses 记录状态集合 + * @return OTA 升级记录列表 + */ + List getOtaTaskRecordListByDeviceIdAndStatus(Set deviceIds, Set statuses); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordServiceImpl.java index 4f9cb7e1d8..ab156a8787 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordServiceImpl.java @@ -2,177 +2,100 @@ package cn.iocoder.yudao.module.iot.service.ota; import cn.hutool.core.convert.Convert; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO; -import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO; -import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaUpgradeRecordMapper; +import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaTaskRecordMapper; import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskRecordStatusEnum; -import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; +import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; +import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.OTA_TASK_RECORD_NOT_EXISTS; -// TODO @li:@Service、@Validated、@Slf4j,先用关键注解;2)类注释,简单写 -@Slf4j +/** + * OTA 升级任务记录 Service 实现类 + */ @Service @Validated +@Slf4j public class IotOtaTaskRecordServiceImpl implements IotOtaTaskRecordService { @Resource - private IotOtaUpgradeRecordMapper iotOtaUpgradeRecordMapper; - - @Resource - private IotDeviceService deviceService; - @Resource - private IotOtaFirmwareService firmwareService; - @Resource - private IotOtaTaskService upgradeTaskService; + private IotOtaTaskRecordMapper otaTaskRecordMapper; @Override - public void createOtaTaskRecordBatch(List deviceIds, Long firmwareId, Long upgradeTaskId) { - // 1. 校验升级记录信息是否存在,并且已经取消的任务可以重新开始 - deviceIds.forEach(deviceId -> validateUpgradeRecordDuplicate(firmwareId, upgradeTaskId, String.valueOf(deviceId))); - - // 2. 初始化OTA升级记录列表信息 - IotOtaTaskDO upgradeTask = upgradeTaskService.getOtaTask(upgradeTaskId); - IotOtaFirmwareDO firmware = firmwareService.getOtaFirmware(firmwareId); - List deviceList = deviceService.getDeviceListByIdList(deviceIds); - List upgradeRecordList = deviceList.stream().map(device -> { - IotOtaTaskRecordDO upgradeRecord = new IotOtaTaskRecordDO(); - upgradeRecord.setFirmwareId(firmware.getId()); - upgradeRecord.setTaskId(upgradeTask.getId()); - upgradeRecord.setDeviceId(device.getId()); - upgradeRecord.setFromFirmwareId(Convert.toLong(device.getFirmwareId())); - upgradeRecord.setStatus(IotOtaTaskRecordStatusEnum.PENDING.getStatus()); - upgradeRecord.setProgress(0); - return upgradeRecord; - }).toList(); - // 3. 保存数据 - iotOtaUpgradeRecordMapper.insertBatch(upgradeRecordList); - // TODO @芋艿:在这里需要处理推送升级任务的逻辑 - } - - // TODO @li:1)方法注释,简单写;2)父类写了注释,子类就不用写了。。。 - /** - * 获取OTA升级记录的数量统计。 - * 该方法根据传入的查询条件,统计不同状态的OTA升级记录数量,并返回一个包含各状态数量的映射。 - * - * @param pageReqVO 包含查询条件的请求对象,主要包括任务ID和设备名称等信息。 - * @return 返回一个Map,其中键为状态常量,值为对应状态的记录数量。 - */ - @Override - @Transactional - public Map getOtaTaskRecordCount(IotOtaTaskRecordPageReqVO pageReqVO) { - // 分别查询不同状态的OTA升级记录数量 - List> upgradeRecordCountList = iotOtaUpgradeRecordMapper.selectOtaUpgradeRecordCount( - pageReqVO.getTaskId(), pageReqVO.getDeviceName()); - Map upgradeRecordCountMap = ObjectUtils.defaultIfNull(upgradeRecordCountList.get(0)); - Objects.requireNonNull(upgradeRecordCountMap); - return upgradeRecordCountMap.entrySet().stream().collect(Collectors.toMap( - entry -> Convert.toInt(entry.getKey()), - entry -> Convert.toLong(entry.getValue()))); + public void createOtaTaskRecordList(List devices, Long firmwareId, Long taskId) { + List records = convertList(devices, device -> + IotOtaTaskRecordDO.builder().firmwareId(firmwareId).taskId(taskId) + .deviceId(device.getId()).fromFirmwareId(Convert.toLong(device.getFirmwareId())) + .status(IotOtaTaskRecordStatusEnum.PENDING.getStatus()).progress(0).build()); + otaTaskRecordMapper.insertBatch(records); } @Override - @Transactional - public Map getOtaTaskRecordStatistics(Long firmwareId) { - // 查询并统计不同状态的OTA升级记录数量 - List> upgradeRecordStatisticsList = iotOtaUpgradeRecordMapper.selectOtaUpgradeRecordStatistics(firmwareId); - Map upgradeRecordStatisticsMap = ObjectUtils.defaultIfNull(upgradeRecordStatisticsList.get(0)); - Objects.requireNonNull(upgradeRecordStatisticsMap); - return upgradeRecordStatisticsMap.entrySet().stream().collect(Collectors.toMap( - entry -> Convert.toInt(entry.getKey()), - entry -> Convert.toLong(entry.getValue()))); + public Map getOtaTaskRecordStatusCountMap(Long firmwareId, Long taskId) { + // 按照 status 枚举,初始化 countMap 为 0 + Map countMap = convertMap(Arrays.asList(IotOtaTaskRecordStatusEnum.values()), + IotOtaTaskRecordStatusEnum::getStatus, iotOtaTaskRecordStatusEnum -> 0L); + + // 查询记录,只返回 id、status 字段 + List records = otaTaskRecordMapper.selectListByFirmwareIdAndTaskId(firmwareId, taskId); + Map> deviceStatusesMap = convertMultiMap(records, + IotOtaTaskRecordDO::getDeviceId, IotOtaTaskRecordDO::getStatus); + // 找到第一个匹配的优先级状态,避免重复计算 + deviceStatusesMap.forEach((deviceId, statuses) -> { + for (Integer priorityStatus : IotOtaTaskRecordStatusEnum.PRIORITY_STATUSES) { + if (statuses.contains(priorityStatus)) { + countMap.put(priorityStatus, countMap.get(priorityStatus) + 1); + return; + } + } + }); + return countMap; } @Override public IotOtaTaskRecordDO getOtaTaskRecord(Long id) { - return iotOtaUpgradeRecordMapper.selectById(id); + return otaTaskRecordMapper.selectById(id); } @Override public PageResult getOtaTaskRecordPage(IotOtaTaskRecordPageReqVO pageReqVO) { - return iotOtaUpgradeRecordMapper.selectUpgradeRecordPage(pageReqVO); + return otaTaskRecordMapper.selectPage(pageReqVO); } @Override - public void cancelUpgradeRecordByTaskId(Long taskId) { - // 暂定只有待推送的升级记录可以取消 TODO @芋艿:可以看看阿里云,哪些可以取消 - iotOtaUpgradeRecordMapper.updateUpgradeRecordStatusByTaskIdAndStatus( - IotOtaTaskRecordStatusEnum.CANCELED.getStatus(), taskId, - IotOtaTaskRecordStatusEnum.PENDING.getStatus()); + public void cancelTaskRecordListByTaskId(Long taskId) { + // 设置取消记录的描述 + IotOtaTaskRecordDO updateRecord = IotOtaTaskRecordDO.builder() + .status(IotOtaTaskRecordStatusEnum.CANCELED.getStatus()) + .description("管理员取消升级任务") + .build(); + + otaTaskRecordMapper.updateByTaskIdAndStatus( + taskId, IotOtaTaskRecordStatusEnum.PENDING.getStatus(), updateRecord); + } + + @Override + public List getOtaTaskRecordListByDeviceIdAndStatus(Set deviceIds, Set statuses) { + return otaTaskRecordMapper.selectListByDeviceIdAndStatus(deviceIds, statuses); } - /** - * 验证指定的升级记录是否存在。 - *

- * 该函数通过给定的ID查询升级记录,如果查询结果为空,则抛出异常,表示升级记录不存在。 - * - * @param id 升级记录的唯一标识符,类型为Long。 - * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,则抛出异常,异常类型为OTA_UPGRADE_RECORD_NOT_EXISTS。 - */ private IotOtaTaskRecordDO validateUpgradeRecordExists(Long id) { - // 根据ID查询升级记录 - IotOtaTaskRecordDO upgradeRecord = iotOtaUpgradeRecordMapper.selectById(id); - // 如果查询结果为空,抛出异常 + IotOtaTaskRecordDO upgradeRecord = otaTaskRecordMapper.selectById(id); if (upgradeRecord == null) { - throw exception(OTA_UPGRADE_RECORD_NOT_EXISTS); + throw exception(OTA_TASK_RECORD_NOT_EXISTS); } return upgradeRecord; } - // TODO @li:注释有点冗余 - /** - * 校验固件升级记录是否重复。 - *

- * 该函数用于检查给定的固件ID、任务ID和设备ID是否已经存在未取消的升级记录。 - * 如果存在未取消的记录,则抛出异常,提示升级记录重复。 - * - * @param firmwareId 固件ID,用于标识特定的固件版本 - * @param taskId 任务ID,用于标识特定的升级任务 - * @param deviceId 设备ID,用于标识特定的设备 - */ - private void validateUpgradeRecordDuplicate(Long firmwareId, Long taskId, String deviceId) { - IotOtaTaskRecordDO upgradeRecord = iotOtaUpgradeRecordMapper.selectByConditions(firmwareId, taskId, deviceId); - if (upgradeRecord == null) { - return; - } - if (!Objects.equals(upgradeRecord.getStatus(), IotOtaTaskRecordStatusEnum.CANCELED.getStatus())) { - throw exception(OTA_UPGRADE_RECORD_DUPLICATE); - } - } - - // TODO @li:注释有点冗余 - /** - * 验证升级记录是否可以重试。 - *

- * 该方法用于检查给定的升级记录是否处于允许重试的状态。如果升级记录的状态为 - * PENDING、PUSHED 或 UPGRADING,则抛出异常,表示不允许重试。 - * - * @param upgradeRecord 需要验证的升级记录对象,类型为 IotOtaUpgradeRecordDO - * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,则抛出 OTA_UPGRADE_RECORD_CANNOT_RETRY 异常 - */ - // TODO @li:这种一次性的方法(不复用的),其实一步一定要抽成小方法; - private void validateUpgradeRecordCanRetry(IotOtaTaskRecordDO upgradeRecord) { - if (ObjectUtils.equalsAny(upgradeRecord.getStatus(), - IotOtaTaskRecordStatusEnum.PENDING.getStatus(), - IotOtaTaskRecordStatusEnum.PUSHED.getStatus(), - IotOtaTaskRecordStatusEnum.UPGRADING.getStatus())) { - throw exception(OTA_UPGRADE_RECORD_CANNOT_RETRY); - } - } - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskService.java index f3b5374697..2e9153b7f8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskService.java @@ -14,7 +14,7 @@ import jakarta.validation.Valid; public interface IotOtaTaskService { /** - * 创建 OTA升 级任务 + * 创建 OTA 升级任务 * * @param createReqVO 创建请求对象 * @return 升级任务编号 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskServiceImpl.java index 13773a090b..309cefa942 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskServiceImpl.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.iot.service.ota; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskCreateReqVO; @@ -9,8 +9,10 @@ import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.IotOtaTaskPageRe import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO; import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaTaskMapper; import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskDeviceScopeEnum; +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskRecordStatusEnum; import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskStatusEnum; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import jakarta.annotation.Resource; @@ -24,6 +26,7 @@ import java.util.List; import java.util.Objects; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; /** @@ -45,26 +48,29 @@ public class IotOtaTaskServiceImpl implements IotOtaTaskService { private IotOtaFirmwareService otaFirmwareService; @Resource @Lazy // 延迟,避免循环依赖报错 - private IotOtaTaskRecordService otaUpgradeRecordService; + private IotOtaTaskRecordService otaTaskRecordService; @Override @Transactional(rollbackFor = Exception.class) public Long createOtaTask(IotOtaTaskCreateReqVO createReqVO) { - // 1.1 校验同一固件的升级任务名称不重复 - validateFirmwareTaskDuplicate(createReqVO.getFirmwareId(), createReqVO.getName()); - // 1.2 校验固件信息是否存在 + // 1.1 校验固件信息是否存在 IotOtaFirmwareDO firmware = otaFirmwareService.validateFirmwareExists(createReqVO.getFirmwareId()); - // 1.3 补全设备范围信息,并且校验是否又设备可以升级,如果没有设备可以升级,则报错 - validateScopeAndDevice(createReqVO.getDeviceScope(), createReqVO.getDeviceIds(), firmware.getProductId()); + // 1.2 校验同一固件的升级任务名称不重复 + if (otaTaskMapper.selectByFirmwareIdAndName(firmware.getId(), createReqVO.getName()) != null) { + throw exception(OTA_TASK_CREATE_FAIL_NAME_DUPLICATE); + } + // 1.3 校验设备范围信息 + List devices = validateOtaTaskDeviceScope(createReqVO, firmware.getProductId()); - // 2. 保存 OTA 升级任务信息到数据库 - IotOtaTaskDO upgradeTask = initOtaUpgradeTask(createReqVO, firmware.getProductId()); - otaTaskMapper.insert(upgradeTask); + // 2. 保存升级任务,直接转换 + IotOtaTaskDO task = BeanUtils.toBean(createReqVO, IotOtaTaskDO.class) + .setStatus(IotOtaTaskStatusEnum.IN_PROGRESS.getStatus()) + .setDeviceTotalCount(devices.size()).setDeviceSuccessCount(0); + otaTaskMapper.insert(task); - // 3. 生成设备升级记录信息并存储,等待定时任务轮询 - // TODO @芋艿:在处理; -// otaUpgradeRecordService.createOtaUpgradeRecordBatch(upgradeTask.getDeviceIds(), firmware.getId(), upgradeTask.getId()); - return upgradeTask.getId(); + // 3. 生成设备升级记录 + otaTaskRecordService.createOtaTaskRecordList(devices, firmware.getId(), task.getId()); + return task.getId(); } @Override @@ -73,18 +79,17 @@ public class IotOtaTaskServiceImpl implements IotOtaTaskService { // 1.1 校验升级任务是否存在 IotOtaTaskDO upgradeTask = validateUpgradeTaskExists(id); // 1.2 校验升级任务是否可以取消 - // TODO @li:ObjUtil notequals - if (!Objects.equals(upgradeTask.getStatus(), IotOtaTaskStatusEnum.IN_PROGRESS.getStatus())) { - throw exception(OTA_UPGRADE_TASK_CANNOT_CANCEL); + if (ObjUtil.notEqual(upgradeTask.getStatus(), IotOtaTaskStatusEnum.IN_PROGRESS.getStatus())) { + throw exception(OTA_TASK_CANCEL_FAIL_STATUS_END); } - // 2. 更新 OTA 升级任务状态为已取消 + // 2. 更新升级任务状态为已取消 otaTaskMapper.updateById(IotOtaTaskDO.builder() .id(id).status(IotOtaTaskStatusEnum.CANCELED.getStatus()) .build()); - // 3. 更新 OTA 升级记录状态为已取消 - otaUpgradeRecordService.cancelUpgradeRecordByTaskId(id); + // 3. 更新升级记录状态为已取消 + otaTaskRecordService.cancelTaskRecordListByTaskId(id); } @Override @@ -97,50 +102,55 @@ public class IotOtaTaskServiceImpl implements IotOtaTaskService { return otaTaskMapper.selectUpgradeTaskPage(pageReqVO); } - /** - * 校验固件升级任务是否重复 - */ - private void validateFirmwareTaskDuplicate(Long firmwareId, String taskName) { - List upgradeTaskList = otaTaskMapper.selectByFirmwareIdAndName(firmwareId, taskName); - if (CollUtil.isNotEmpty(upgradeTaskList)) { - throw exception(OTA_UPGRADE_TASK_NAME_DUPLICATE); - } - } - - private void validateScopeAndDevice(Integer scope, List deviceIds, Long productId) { - if (Objects.equals(scope, IotOtaTaskDeviceScopeEnum.SELECT.getScope())) { - if (CollUtil.isEmpty(deviceIds)) { - throw exception(OTA_UPGRADE_TASK_DEVICE_IDS_EMPTY); + private List validateOtaTaskDeviceScope(IotOtaTaskCreateReqVO createReqVO, Long productId) { + // 情况一:选择设备 + if (Objects.equals(createReqVO.getDeviceScope(), IotOtaTaskDeviceScopeEnum.SELECT.getScope())) { + // 1.1 校验设备存在 + List devices = deviceService.validateDeviceListExists(createReqVO.getDeviceIds()); + for (IotDeviceDO device : devices) { + if (ObjUtil.notEqual(device.getProductId(), productId)) { + throw exception(DEVICE_NOT_EXISTS); + } } - return; + // 1.2 校验设备是否已经是该固件版本 + devices.forEach(device -> { + if (Objects.equals(device.getFirmwareId(), createReqVO.getFirmwareId())) { + throw exception(OTA_TASK_CREATE_FAIL_DEVICE_FIRMWARE_EXISTS, device.getDeviceName()); + } + }); + // 1.3 校验设备是否已经在升级中 + List records = otaTaskRecordService.getOtaTaskRecordListByDeviceIdAndStatus( + convertSet(devices, IotDeviceDO::getId), IotOtaTaskRecordStatusEnum.IN_PROCESS_STATUSES); + devices.forEach(device -> { + if (CollUtil.contains(records, item -> item.getDeviceId().equals(device.getId()))) { + throw exception(OTA_TASK_CREATE_FAIL_DEVICE_OTA_IN_PROCESS, device.getDeviceName()); + } + }); + return devices; } - - if (Objects.equals(scope, IotOtaTaskDeviceScopeEnum.ALL.getScope())) { - List deviceList = deviceService.getDeviceListByProductId(productId); - if (CollUtil.isEmpty(deviceList)) { - throw exception(OTA_UPGRADE_TASK_DEVICE_LIST_EMPTY); + // 情况二:全部设备 + if (Objects.equals(createReqVO.getDeviceScope(), IotOtaTaskDeviceScopeEnum.ALL.getScope())) { + List devices = deviceService.getDeviceListByProductId(productId); + // 2.1.1 移除已经是该固件版本的设备 + devices.removeIf(device -> Objects.equals(device.getFirmwareId(), createReqVO.getFirmwareId())); + // 2.1.2 移除已经在升级中的设备 + List records = otaTaskRecordService.getOtaTaskRecordListByDeviceIdAndStatus( + convertSet(devices, IotDeviceDO::getId), IotOtaTaskRecordStatusEnum.IN_PROCESS_STATUSES); + devices.removeIf(device -> CollUtil.contains(records, + item -> item.getDeviceId().equals(device.getId()))); + // 2.2 校验是否有可升级的设备 + if (CollUtil.isEmpty(devices)) { + throw exception(OTA_TASK_CREATE_FAIL_DEVICE_EMPTY); } + return devices; } + throw new IllegalArgumentException("不支持的设备范围:" + createReqVO.getDeviceScope()); } private IotOtaTaskDO validateUpgradeTaskExists(Long id) { IotOtaTaskDO upgradeTask = otaTaskMapper.selectById(id); if (Objects.isNull(upgradeTask)) { - throw exception(OTA_UPGRADE_TASK_NOT_EXISTS); - } - return upgradeTask; - } - - private IotOtaTaskDO initOtaUpgradeTask(IotOtaTaskCreateReqVO createReqVO, Long productId) { - IotOtaTaskDO upgradeTask = BeanUtils.toBean(createReqVO, IotOtaTaskDO.class); - upgradeTask.setDeviceTotalCount(Convert.toLong(CollUtil.size(createReqVO.getDeviceIds()))) - .setStatus(IotOtaTaskStatusEnum.IN_PROGRESS.getStatus()); - - if (Objects.equals(createReqVO.getDeviceScope(), IotOtaTaskDeviceScopeEnum.ALL.getScope())) { - List deviceList = deviceService.getDeviceListByProductId(productId); - upgradeTask.setDeviceTotalCount((long) deviceList.size()); -// upgradeTask.setDeviceIds( -// deviceList.stream().map(IotDeviceDO::getId).collect(Collectors.toList())); + throw exception(OTA_TASK_NOT_EXISTS); } return upgradeTask; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java index 3144a1362a..8eafcb681a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java @@ -121,7 +121,7 @@ public class IotDataRuleServiceImpl implements IotDataRuleService { convertSet(sourceConfigs, IotDataRuleDO.SourceConfig::getProductId)); // 2. 校验设备 - deviceService.validateDevicesExist(convertSet(sourceConfigs, IotDataRuleDO.SourceConfig::getDeviceId, + deviceService.validateDeviceListExists(convertSet(sourceConfigs, IotDataRuleDO.SourceConfig::getDeviceId, config -> ObjUtil.notEqual(config.getDeviceId(), IotDeviceDO.DEVICE_ID_ALL))); // 3. 校验物模型存在 From e5ce1952795ab19302afbc1dca0473d0eabf630b Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 2 Jul 2025 23:28:03 +0800 Subject: [PATCH 33/33] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9?= =?UTF-8?q?=E8=81=94=E7=BD=91=E3=80=91=E5=A2=9E=E5=8A=A0=20OTA=20=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E7=9A=84=E6=95=B0=E6=8D=AE=E8=AF=BB=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/device/IotDeviceController.java | 11 ++++-- .../admin/ota/IotOtaFirmwareController.java | 18 ++++++++-- .../admin/ota/IotOtaTaskRecordController.java | 34 ++++++++++++++++--- .../ota/vo/firmware/IotOtaFirmwareRespVO.java | 3 ++ .../record/IotOtaTaskRecordPageReqVO.java | 7 ++-- .../task/record/IotOtaTaskRecordRespVO.java | 34 +++++++++++-------- .../iot/dal/mysql/device/IotDeviceMapper.java | 6 ++-- .../dal/mysql/ota/IotOtaTaskRecordMapper.java | 3 +- .../module/iot/enums/DictTypeConstants.java | 1 + .../iot/service/device/IotDeviceService.java | 26 ++++++++++++-- .../service/device/IotDeviceServiceImpl.java | 17 ++++++---- .../service/ota/IotOtaFirmwareService.java | 34 ++++++++++++++++--- .../ota/IotOtaFirmwareServiceImpl.java | 13 +++++++ .../service/ota/IotOtaTaskRecordService.java | 2 +- .../ota/IotOtaTaskRecordServiceImpl.java | 2 +- 15 files changed, 167 insertions(+), 44 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java index 052d34edc4..b72717f5f1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletResponse; @@ -121,10 +122,14 @@ public class IotDeviceController { @GetMapping("/simple-list") @Operation(summary = "获取设备的精简信息列表", description = "主要用于前端的下拉选项") - @Parameter(name = "deviceType", description = "设备类型", example = "1") + @Parameters({ + @Parameter(name = "deviceType", description = "设备类型", example = "1"), + @Parameter(name = "productId", description = "产品编号", example = "1024") + }) public CommonResult> getDeviceSimpleList( - @RequestParam(value = "deviceType", required = false) Integer deviceType) { - List list = deviceService.getDeviceListByDeviceType(deviceType); + @RequestParam(value = "deviceType", required = false) Integer deviceType, + @RequestParam(value = "productId", required = false) Long productId) { + List list = deviceService.getDeviceListByCondition(deviceType, productId); return success(convertList(list, device -> // 只返回 id、name、productId 字段 new IotDeviceRespVO().setId(device.getId()).setDeviceName(device.getDeviceName()) .setProductId(device.getProductId()))); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java index a2a5a114e7..7c3a5b78f4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java @@ -3,12 +3,14 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareCreateReqVO; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwarePageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareCreateReqVO; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareUpdateReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.service.ota.IotOtaFirmwareService; +import cn.iocoder.yudao.module.iot.service.product.IotProductService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; @@ -27,6 +29,8 @@ public class IotOtaFirmwareController { @Resource private IotOtaFirmwareService otaFirmwareService; + @Resource + private IotProductService productService; @PostMapping("/create") @Operation(summary = "创建 OTA 固件") @@ -47,8 +51,16 @@ public class IotOtaFirmwareController { @Operation(summary = "获得 OTA 固件") @PreAuthorize("@ss.hasPermission('iot:ota-firmware:query')") public CommonResult getOtaFirmware(@RequestParam("id") Long id) { - IotOtaFirmwareDO otaFirmware = otaFirmwareService.getOtaFirmware(id); - return success(BeanUtils.toBean(otaFirmware, IotOtaFirmwareRespVO.class)); + IotOtaFirmwareDO firmware = otaFirmwareService.getOtaFirmware(id); + if (firmware == null) { + return success(null); + } + return success(BeanUtils.toBean(firmware, IotOtaFirmwareRespVO.class, o -> { + IotProductDO product = productService.getProduct(firmware.getProductId()); + if (product != null) { + o.setProductName(product.getName()); + } + })); } @GetMapping("/page") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskRecordController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskRecordController.java index 1110ff8f49..cc17108e5e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskRecordController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaTaskRecordController.java @@ -2,10 +2,15 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record.IotOtaTaskRecordRespVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaTaskRecordDO; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; +import cn.iocoder.yudao.module.iot.service.ota.IotOtaFirmwareService; import cn.iocoder.yudao.module.iot.service.ota.IotOtaTaskRecordService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -13,6 +18,7 @@ import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; +import org.dromara.hutool.core.collection.CollUtil; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; @@ -23,6 +29,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.Map; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; @Tag(name = "管理后台 - IoT OTA 升级任务记录") @RestController @@ -32,18 +39,22 @@ public class IotOtaTaskRecordController { @Resource private IotOtaTaskRecordService otaTaskRecordService; + @Resource + private IotDeviceService deviceService; + @Resource + private IotOtaFirmwareService otaFirmwareService; - @GetMapping("/get-status-count") + @GetMapping("/get-status-statistics") @Operation(summary = "获得 OTA 升级记录状态统计") @Parameters({ @Parameter(name = "firmwareId", description = "固件编号", example = "1024"), @Parameter(name = "taskId", description = "升级任务编号", example = "2048") }) @PreAuthorize("@ss.hasPermission('iot:ota-task-record:query')") - public CommonResult> getOtaTaskRecordStatusCountMap( + public CommonResult> getOtaTaskRecordStatusStatistics( @RequestParam(value = "firmwareId", required = false) Long firmwareId, @RequestParam(value = "taskId", required = false) Long taskId) { - return success(otaTaskRecordService.getOtaTaskRecordStatusCountMap(firmwareId, taskId)); + return success(otaTaskRecordService.getOtaTaskRecordStatusStatistics(firmwareId, taskId)); } @GetMapping("/page") @@ -52,7 +63,22 @@ public class IotOtaTaskRecordController { public CommonResult> getOtaTaskRecordPage( @Valid IotOtaTaskRecordPageReqVO pageReqVO) { PageResult pageResult = otaTaskRecordService.getOtaTaskRecordPage(pageReqVO); - return success(BeanUtils.toBean(pageResult, IotOtaTaskRecordRespVO.class)); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty()); + } + + // 批量查询固件信息 + Map firmwareMap = otaFirmwareService.getOtaFirmwareMap( + convertSet(pageResult.getList(), IotOtaTaskRecordDO::getFromFirmwareId)); + Map deviceMap = deviceService.getDeviceMap( + convertSet(pageResult.getList(), IotOtaTaskRecordDO::getDeviceId)); + // 转换为响应 VO + return success(BeanUtils.toBean(pageResult, IotOtaTaskRecordRespVO.class, (vo) -> { + MapUtils.findAndThen(firmwareMap, vo.getFromFirmwareId(), firmware -> + vo.setFromFirmwareVersion(firmware.getVersion())); + MapUtils.findAndThen(deviceMap, vo.getDeviceId(), device -> + vo.setDeviceName(device.getDeviceName())); + })); } @GetMapping("/get") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java index 0ad8a82ee6..d6fdbf7260 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java @@ -25,6 +25,9 @@ public class IotOtaFirmwareRespVO implements VO { @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Long productId; + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "智能设备") + private String productName; + @Schema(description = "固件文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/firmware.bin") private String fileUrl; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordPageReqVO.java index 839a8b06d8..00c6fe7f32 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordPageReqVO.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record; import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskRecordStatusEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -11,7 +13,8 @@ public class IotOtaTaskRecordPageReqVO extends PageParam { @Schema(description = "升级任务编号", example = "1024") private Long taskId; - @Schema(description = "设备标识", example = "摄像头A1-1") - private String deviceName; + @Schema(description = "升级记录状态", example = "5") + @InEnum(IotOtaTaskRecordStatusEnum.class) + private Integer status; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordRespVO.java index 4de8204f0b..f7ab1edf58 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/record/IotOtaTaskRecordRespVO.java @@ -3,40 +3,46 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.task.record; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -@Schema(description = "管理后台 - IoT OTA 升级记录 Response VO") +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - IoT OTA 升级任务记录 Response VO") @Data public class IotOtaTaskRecordRespVO { - // TODO @芋艿:梳理字段 - - @Schema(description = "升级记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Long id; @Schema(description = "固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Long firmwareId; - @Schema(description = "固件版本", requiredMode = Schema.RequiredMode.REQUIRED, example = "v1.0.0") - private String firmwareVersion; - - @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") private Long taskId; @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private String deviceId; + private Long deviceId; - @Schema(description = "来源的固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @Schema(description = "设备名称", example = "智能开关") + private String deviceName; + + @Schema(description = "来源的固件编号", example = "1023") private Long fromFirmwareId; - @Schema(description = "来源的固件版本", requiredMode = Schema.RequiredMode.REQUIRED, example = "v1.0.0") + @Schema(description = "来源固件版本", example = "1.0.0") private String fromFirmwareVersion; - @Schema(description = "升级状态", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "升级状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer status; - @Schema(description = "升级进度,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @Schema(description = "升级进度,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") private Integer progress; - @Schema(description = "升级进度描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @Schema(description = "升级进度描述", example = "正在下载固件...") private String description; + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime updateTime; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index 5f3dc56e04..606cf8f033 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -52,9 +52,11 @@ public interface IotDeviceMapper extends BaseMapperX { return selectCount(IotDeviceDO::getProductId, productId); } - default List selectListByDeviceType(@Nullable Integer deviceType) { + default List selectListByCondition(@Nullable Integer deviceType, + @Nullable Long productId) { return selectList(new LambdaQueryWrapperX() - .geIfPresent(IotDeviceDO::getDeviceType, deviceType)); + .eqIfPresent(IotDeviceDO::getDeviceType, deviceType) + .eqIfPresent(IotDeviceDO::getProductId, productId)); } default List selectListByState(Integer state) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaTaskRecordMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaTaskRecordMapper.java index d6d147107f..76c83beef1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaTaskRecordMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaTaskRecordMapper.java @@ -23,7 +23,8 @@ public interface IotOtaTaskRecordMapper extends BaseMapperX default PageResult selectPage(IotOtaTaskRecordPageReqVO pageReqVO) { return selectPage(pageReqVO, new LambdaQueryWrapperX() - .eqIfPresent(IotOtaTaskRecordDO::getTaskId, pageReqVO.getTaskId())); + .eqIfPresent(IotOtaTaskRecordDO::getTaskId, pageReqVO.getTaskId()) + .eqIfPresent(IotOtaTaskRecordDO::getStatus, pageReqVO.getStatus())); } default void updateByTaskIdAndStatus(Long taskId, Integer fromStatus, IotOtaTaskRecordDO updateRecord) { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java index 384bf734e6..6e089632c4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java @@ -18,5 +18,6 @@ public class DictTypeConstants { public static final String OTA_TASK_DEVICE_SCOPE = "iot_ota_task_device_scope"; public static final String OTA_TASK_STATUS = "iot_ota_task_status"; + public static final String OTA_TASK_RECORD_STATUS = "iot_ota_task_record_status"; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index 328d7bd5d6..e1219cd5f7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -13,6 +13,8 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + /** * IoT 设备 Service 接口 * @@ -138,12 +140,14 @@ public interface IotDeviceService { PageResult getDevicePage(IotDevicePageReqVO pageReqVO); /** - * 基于设备类型,获得设备列表 + * 根据条件,获得设备列表 * * @param deviceType 设备类型 + * @param productId 产品编号 * @return 设备列表 */ - List getDeviceListByDeviceType(@Nullable Integer deviceType); + List getDeviceListByCondition(@Nullable Integer deviceType, + @Nullable Long productId); /** * 获得状态,获得设备列表 @@ -241,4 +245,22 @@ public interface IotDeviceService { */ List validateDeviceListExists(Collection ids); + /** + * 获得设备列表 + * + * @param ids 设备编号数组 + * @return 设备列表 + */ + List getDeviceList(Collection ids); + + /** + * 获得设备 Map + * + * @param ids 设备编号数组 + * @return 设备 Map + */ + default Map getDeviceMap(Collection ids) { + return convertMap(getDeviceList(ids), IotDeviceDO::getId); + } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index 4cdf859d06..1a5578526b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -264,8 +264,8 @@ public class IotDeviceServiceImpl implements IotDeviceService { } @Override - public List getDeviceListByDeviceType(@Nullable Integer deviceType) { - return deviceMapper.selectListByDeviceType(deviceType); + public List getDeviceListByCondition(@Nullable Integer deviceType, @Nullable Long productId) { + return deviceMapper.selectListByCondition(deviceType, productId); } @Override @@ -470,16 +470,21 @@ public class IotDeviceServiceImpl implements IotDeviceService { @Override public List validateDeviceListExists(Collection ids) { - if (CollUtil.isEmpty(ids)) { - return Collections.emptyList(); - } - List devices = deviceMapper.selectByIds(ids); + List devices = getDeviceList(ids); if (devices.size() != ids.size()) { throw exception(DEVICE_NOT_EXISTS); } return devices; } + @Override + public List getDeviceList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return deviceMapper.selectByIds(ids); + } + private IotDeviceServiceImpl getSelf() { return SpringUtil.getBean(getClass()); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java index 14fc38cde7..c6fafc7f92 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java @@ -7,6 +7,12 @@ import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwa import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; import jakarta.validation.Valid; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + /** * OTA 固件管理 Service 接口 * @@ -30,13 +36,31 @@ public interface IotOtaFirmwareService { void updateOtaFirmware(@Valid IotOtaFirmwareUpdateReqVO updateReqVO); /** - * 根据 ID 获取 OTA 固件信息 + * 获取 OTA 固件信息 * - * @param id OTA 固件编号 + * @param id 固件编号 * @return 固件信息 */ IotOtaFirmwareDO getOtaFirmware(Long id); + /** + * 获取 OTA 固件信息列表 + * + * @param ids 固件编号集合 + * @return 固件信息列表 + */ + List getOtaFirmwareList(Collection ids); + + /** + * 获取 OTA 固件信息 Map + * + * @param ids 固件编号集合 + * @return 固件信息 Map + */ + default Map getOtaFirmwareMap(Collection ids) { + return convertMap(getOtaFirmwareList(ids), IotOtaFirmwareDO::getId); + } + /** * 分页查询 OTA 固件信息 * @@ -46,10 +70,10 @@ public interface IotOtaFirmwareService { PageResult getOtaFirmwarePage(@Valid IotOtaFirmwarePageReqVO pageReqVO); /** - * 验证物联网 OTA 固件是否存在 + * 验证 OTA 固件是否存在 * - * @param id 物联网 OTA 固件编号 - * @return OTA 固件 + * @param id 固件编号 + * @return 固件信息 */ IotOtaFirmwareDO validateFirmwareExists(Long id); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java index a5da1dba3f..87290c14fb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java @@ -18,8 +18,13 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import java.io.ByteArrayInputStream; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.OTA_FIRMWARE_NOT_EXISTS; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE; @@ -76,6 +81,14 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService { return otaFirmwareMapper.selectById(id); } + @Override + public List getOtaFirmwareList(Collection ids) { + if (ids == null || ids.isEmpty()) { + return Collections.emptyList(); + } + return otaFirmwareMapper.selectByIds(ids); + } + @Override public PageResult getOtaFirmwarePage(IotOtaFirmwarePageReqVO pageReqVO) { return otaFirmwareMapper.selectPage(pageReqVO); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordService.java index eb5a04ac2a..ba5dc826c8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordService.java @@ -31,7 +31,7 @@ public interface IotOtaTaskRecordService { * @param taskId 任务编号 * @return 状态统计 Map,key 为状态码,value 为对应状态的升级记录数量 */ - Map getOtaTaskRecordStatusCountMap(Long firmwareId, Long taskId); + Map getOtaTaskRecordStatusStatistics(Long firmwareId, Long taskId); /** * 获取 OTA 升级记录 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordServiceImpl.java index ab156a8787..88b009caa3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskRecordServiceImpl.java @@ -42,7 +42,7 @@ public class IotOtaTaskRecordServiceImpl implements IotOtaTaskRecordService { } @Override - public Map getOtaTaskRecordStatusCountMap(Long firmwareId, Long taskId) { + public Map getOtaTaskRecordStatusStatistics(Long firmwareId, Long taskId) { // 按照 status 枚举,初始化 countMap 为 0 Map countMap = convertMap(Arrays.asList(IotOtaTaskRecordStatusEnum.values()), IotOtaTaskRecordStatusEnum::getStatus, iotOtaTaskRecordStatusEnum -> 0L);