diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java index a755018034..7fca10a467 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java @@ -4,7 +4,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; /** - * IOT 访问方式枚举类 + * IOT 产品物模型属性读取类型枚举 * * @author ahh */ diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelParamDirectionEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelParamDirectionEnum.java new file mode 100644 index 0000000000..e12332b6dd --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelParamDirectionEnum.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.iot.enums.thingmodel; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * IOT 产品物模型参数是输入参数还是输出参数枚举 + * + * @author HUIHUI + */ +@AllArgsConstructor +@Getter +public enum IotProductThingModelParamDirectionEnum { + + INPUT("input"), // 输入参数 + OUTPUT("output"); // 输出参数 + + private final String direction; + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceCallTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceCallTypeEnum.java new file mode 100644 index 0000000000..81ffccc493 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceCallTypeEnum.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.iot.enums.thingmodel; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * IOT 产品物模型服务调用方式枚举 + * + * @author HUIHUI + */ +@AllArgsConstructor +@Getter +public enum IotProductThingModelServiceCallTypeEnum { + + ASYNC("async"), // 异步调用 + SYNC("sync"); // 同步调用 + + private final String type; + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceEventTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceEventTypeEnum.java new file mode 100644 index 0000000000..fbf76da77b --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceEventTypeEnum.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.iot.enums.thingmodel; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * IOT 产品物模型事件类型枚举 + * + * @author HUIHUI + */ +@AllArgsConstructor +@Getter +public enum IotProductThingModelServiceEventTypeEnum { + + INFO("info"), // 信息 + ALERT("alert"), // 告警 + ERROR("error"); // 故障 + + private final String type; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index 19b50ec215..d0ed0bcacd 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -25,13 +25,6 @@ ${revision} - - cn.iocoder.boot - yudao-module-iot-plugin-api - 0.0.1 - compile - - cn.iocoder.boot yudao-spring-boot-starter-biz-tenant diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.http index 7742705ef1..7e7aa05d6e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.http +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.http @@ -176,7 +176,7 @@ tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} ### 请求 /iot/product-thing-model/get 接口 => 成功 -GET {{baseUrl}}/iot/product-thing-model/get?id=40 +GET {{baseUrl}}/iot/product-thing-model/get?id=67 tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} 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 718c7b60e8..f49f5f86e6 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 @@ -1,9 +1,15 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelArgument; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelServiceEventTypeEnum; import lombok.Data; + import java.util.List; +/** + * 物模型中的事件 + * + * @author HUIHUI + */ @Data public class ThingModelEvent { @@ -16,17 +22,27 @@ public class ThingModelEvent { */ private String name; /** - * 事件描述 + * 是否是标准品类的必选事件。 + * + * - true:是 + * - false:否 */ - private String description; - + private Boolean required; /** * 事件类型 * - * "info"、"alert"、"error" + * 关联枚举 {@link IotProductThingModelServiceEventTypeEnum} */ private String type; - private List outputData; + /** + * 事件的输出参数 + * + * 输出参数定义事件调用后返回的结果或反馈信息,用于确认操作结果或提供额外的信息。 + */ + private List outputParams; + /** + * 标识设备需要执行的具体操作 + */ private String method; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java new file mode 100644 index 0000000000..3b7b1414fa --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; + +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDataSpecs; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelParamDirectionEnum; +import lombok.Data; + +import java.util.List; + +/** + * IOT 产品物模型中的参数 // TODO @puhui999 考虑要不改成 ThingModelParam ? + * + * @author HUIHUI + */ +@Data +public class ThingModelInputOutputParam { + + /** + * 参数标识符 + */ + private String identifier; + /** + * 参数名称 + */ + private String name; + /** + * 用于区分输入或输出参数 + * + * 关联枚举 {@link IotProductThingModelParamDirectionEnum} + */ + private String direction; + /** + * 参数的序号。从 0 开始排序,且不能重复。 + * + * TODO 考虑要不要序号,感觉是要的, 先留一手看看 + */ + private Integer paraOrder; + /** + * 参数值的数据类型,与 dataSpecs 的 dataType 保持一致 + */ + private String dataType; + /** + * 参数值的数据类型(dataType)为非列表型(int、float、double、text、date、array)的数据规范存储在 dataSpecs 中 + */ + private ThingModelDataSpecs dataSpecs; + /** + * 参数值的数据类型(dataType)为列表型(enum、bool、struct)的数据规范存储在 dataSpecsList 中 + */ + private List dataSpecsList; + +} 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/controller/admin/thingmodel/model/ThingModelProperty.java index f296cecd62..bb7376fc8c 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/controller/admin/thingmodel/model/ThingModelProperty.java @@ -24,10 +24,6 @@ public class ThingModelProperty { * 属性名称 */ private String name; - /** - * 属性描述 - */ - private String description; /** * 云端可以对该属性进行的操作类型 * 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/controller/admin/thingmodel/model/ThingModelService.java index ec4bd34e99..0bdf498d3c 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/controller/admin/thingmodel/model/ThingModelService.java @@ -1,9 +1,15 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelArgument; +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelServiceCallTypeEnum; import lombok.Data; + import java.util.List; +/** + * 物模型中的服务 + * + * @author HUIHUI + */ @Data public class ThingModelService { @@ -16,18 +22,33 @@ public class ThingModelService { */ private String name; /** - * 服务描述 + * 是否是标准品类的必选服务。 + * + * - true:是 + * - false:否 */ - private String description; - + private Boolean required; /** * 调用类型 * - * "sync"、"async" + * 关联枚举 {@link IotProductThingModelServiceCallTypeEnum} */ private String callType; - private List inputData; - private List outputData; + /** + * 服务的输入参数 + * + * 输入参数定义服务调用时所需提供的信息,用于控制设备行为或执行特定任务 + */ + private List inputParams; + /** + * 服务的输出参数 + * + * 输出参数定义服务调用后返回的结果或反馈信息,用于确认操作结果或提供额外的信息。 + */ + private List outputParams; + /** + * 标识设备需要执行的具体操作 + */ private String method; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArgument.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArgument.java deleted file mode 100644 index 96f51150f5..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArgument.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; - -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.Data; - -@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class ThingModelArgument { - - public static final String DIRECTION_INPUT = "input"; - public static final String DIRECTION_OUTPUT = "output"; - - private String identifier; - private String name; - /** - * 物模型中的属性 - */ - private ThingModelProperty property; - /** - * 用于区分输入或输出参数,"input" 或 "output" - */ - private String direction; - private String description; - -} 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/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java index e0f5bb5397..5e31d3996a 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/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java @@ -25,10 +25,6 @@ public class ThingModelStructDataSpecs extends ThingModelDataSpecs { * 属性名称 */ private String name; - /** - * 属性描述 - */ - private String description; /** * 云端可以对该属性进行的操作类型 * 关联枚举 {@link IotProductThingModelAccessModeEnum} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java index a53fb69473..3dc5790a5e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java @@ -3,14 +3,10 @@ package cn.iocoder.yudao.module.iot.service.thingmodel; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 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.ThingModelInputOutputParam; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelArgument; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelArrayDataSpecs; -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelSaveReqVO; import cn.iocoder.yudao.module.iot.convert.thingmodel.IotProductThingModelConvert; @@ -18,8 +14,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; import cn.iocoder.yudao.module.iot.dal.mysql.thingmodel.IotProductThingModelMapper; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelAccessModeEnum; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; +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; @@ -30,8 +25,7 @@ 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.diffList; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; /** @@ -73,9 +67,91 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ if (Objects.equals(createReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); } + // TODO @puhui999: 服务和事件的情况 method 怎么设置?在前端设置还是后端设置? return thingModel.getId(); } + @Override + @Transactional(rollbackFor = Exception.class) + public void updateProductThingModel(IotProductThingModelSaveReqVO updateReqVO) { + // 1. 校验功能是否存在 + validateProductThingModelMapperExists(updateReqVO.getId()); + + // 2. 校验功能标识符是否唯一 + validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier()); + + // 3. 校验产品状态,发布状态下,不允许操作功能 + validateProductStatus(updateReqVO.getProductId()); + + // 4. 更新数据库 + IotProductThingModelDO thingModel = IotProductThingModelConvert.INSTANCE.convert(updateReqVO); + productThingModelMapper.updateById(thingModel); + + // 5. 如果更新的是属性,需要更新默认的事件和服务 + if (Objects.equals(updateReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { + createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey()); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteProductThingModel(Long id) { + // 1. 校验功能是否存在 + IotProductThingModelDO thingModel = productThingModelMapper.selectById(id); + if (thingModel == null) { + throw exception(THING_MODEL_NOT_EXISTS); + } + + // 3. 校验产品状态,发布状态下,不允许操作功能 + validateProductStatus(thingModel.getProductId()); + + // 2. 删除功能 + productThingModelMapper.deleteById(id); + + // 3. 如果删除的是属性,需要更新默认的事件和服务 + if (Objects.equals(thingModel.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { + createDefaultEventsAndServices(thingModel.getProductId(), thingModel.getProductKey()); + } + } + + @Override + public IotProductThingModelDO getProductThingModel(Long id) { + return productThingModelMapper.selectById(id); + } + + @Override + public List getProductThingModelListByProductId(Long productId) { + return productThingModelMapper.selectListByProductId(productId); + } + + @Override + public PageResult getProductThingModelPage(IotProductThingModelPageReqVO pageReqVO) { + return productThingModelMapper.selectPage(pageReqVO); + } + + @Override + public List getProductThingModelListByProductKey(String productKey) { + return productThingModelMapper.selectListByProductKey(productKey); + } + + /** + * 校验功能是否存在 + * + * @param id 功能编号 + */ + private void validateProductThingModelMapperExists(Long id) { + if (productThingModelMapper.selectById(id) == null) { + throw exception(THING_MODEL_NOT_EXISTS); + } + } + + private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) { + IotProductThingModelDO thingModel = productThingModelMapper.selectByProductIdAndIdentifier(productId, identifier); + if (thingModel != null && ObjectUtil.notEqual(thingModel.getId(), id)) { + throw exception(THING_MODEL_IDENTIFIER_EXISTS); + } + } + private void validateProductStatus(Long createReqVO) { IotProductDO product = productService.getProduct(createReqVO); if (Objects.equals(product.getStatus(), IotProductStatusEnum.PUBLISHED.getStatus())) { @@ -104,87 +180,6 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ } } - @Override - @Transactional(rollbackFor = Exception.class) - public void updateProductThingModel(IotProductThingModelSaveReqVO updateReqVO) { - // 1. 校验功能是否存在 - validateProductThingModelMapperExists(updateReqVO.getId()); - - // 2. 校验功能标识符是否唯一 - validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier()); - - // 3. 校验产品状态,发布状态下,不允许操作功能 - validateProductStatus(updateReqVO.getProductId()); - - // 4. 更新数据库 - IotProductThingModelDO thingModel = IotProductThingModelConvert.INSTANCE.convert(updateReqVO); - productThingModelMapper.updateById(thingModel); - - // 5. 如果更新的是属性,需要更新默认的事件和服务 - if (Objects.equals(updateReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { - createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey()); - } - } - - private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) { - IotProductThingModelDO thingModel = productThingModelMapper.selectByProductIdAndIdentifier(productId, identifier); - if (thingModel != null && ObjectUtil.notEqual(thingModel.getId(), id)) { - throw exception(THING_MODEL_IDENTIFIER_EXISTS); - } - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void deleteProductThingModel(Long id) { - // 1. 校验功能是否存在 - IotProductThingModelDO thingModel = productThingModelMapper.selectById(id); - if (thingModel == null) { - throw exception(THING_MODEL_NOT_EXISTS); - } - - // 3. 校验产品状态,发布状态下,不允许操作功能 - validateProductStatus(thingModel.getProductId()); - - // 2. 删除功能 - productThingModelMapper.deleteById(id); - - // 3. 如果删除的是属性,需要更新默认的事件和服务 - if (Objects.equals(thingModel.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { - createDefaultEventsAndServices(thingModel.getProductId(), thingModel.getProductKey()); - } - } - - /** - * 校验功能是否存在 - * - * @param id 功能编号 - */ - private void validateProductThingModelMapperExists(Long id) { - if (productThingModelMapper.selectById(id) == null) { - throw exception(THING_MODEL_NOT_EXISTS); - } - } - - @Override - public IotProductThingModelDO getProductThingModel(Long id) { - return productThingModelMapper.selectById(id); - } - - @Override - public List getProductThingModelListByProductId(Long productId) { - return productThingModelMapper.selectListByProductId(productId); - } - - @Override - public PageResult getProductThingModelPage(IotProductThingModelPageReqVO pageReqVO) { - return productThingModelMapper.selectPage(pageReqVO); - } - - @Override - public List getProductThingModelListByProductKey(String productKey) { - return productThingModelMapper.selectListByProductKey(productKey); - } - /** * 创建默认的事件和服务 */ @@ -195,231 +190,140 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ // 2. 生成新的事件和服务列表 List newThingModelList = new ArrayList<>(); - // 生成属性上报事件 + // 2.1 生成属性上报事件 ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList); if (propertyPostEvent != null) { - IotProductThingModelDO eventThingModel = buildEventThingModelDO(productId, productKey, propertyPostEvent); - newThingModelList.add(eventThingModel); + newThingModelList.add(buildEventThingModelDO(productId, productKey, propertyPostEvent, "属性上报事件")); } - // 生成属性设置服务 + // 2.2 生成属性设置服务 ThingModelService propertySetService = generatePropertySetService(propertyList); if (propertySetService != null) { - IotProductThingModelDO setServiceThingModel = buildServiceThingModelDO(productId, productKey, propertySetService); - newThingModelList.add(setServiceThingModel); + newThingModelList.add(buildServiceThingModelDO(productId, productKey, propertySetService, "属性设置服务")); } - // 生成属性获取服务 + // 2.3 生成属性获取服务 ThingModelService propertyGetService = generatePropertyGetService(propertyList); if (propertyGetService != null) { - IotProductThingModelDO getServiceThingModel = buildServiceThingModelDO(productId, productKey, propertyGetService); - newThingModelList.add(getServiceThingModel); + newThingModelList.add(buildServiceThingModelDO(productId, productKey, propertyGetService,"属性获取服务")); } - // 3. 获取数据库中的默认的旧事件和服务列表 + // 3.1 获取数据库中的默认的旧事件和服务列表 List oldThingModelList = productThingModelMapper.selectListByProductIdAndIdentifiersAndTypes( productId, Arrays.asList("post", "set", "get"), Arrays.asList(IotProductThingModelTypeEnum.EVENT.getType(), IotProductThingModelTypeEnum.SERVICE.getType()) ); - - // 3.1 使用 diffList 方法比较新旧列表 - List> diffResult = diffList(oldThingModelList, newThingModelList, - // 继续使用 identifier 和 type 进行比较:这样可以准确地匹配对应的功能对象。 - (oldFunc, newFunc) -> Objects.equals(oldFunc.getIdentifier(), newFunc.getIdentifier()) - && Objects.equals(oldFunc.getType(), newFunc.getType())); - List createList = diffResult.get(0); // 需要新增的 - List updateList = diffResult.get(1); // 需要更新的 - List deleteList = diffResult.get(2); // 需要删除的 - - // 3.2 批量执行数据库操作 - // 新增数据库中的新事件和服务列表 - if (CollUtil.isNotEmpty(createList)) { - productThingModelMapper.insertBatch(createList); - } - // 更新数据库中的事件和服务列表 - if (CollUtil.isNotEmpty(updateList)) { - // 首先,为每个需要更新的对象设置其对应的 ID - updateList.forEach(updateFunc -> { - IotProductThingModelDO oldFunc = findThingModelByIdentifierAndType( - oldThingModelList, updateFunc.getIdentifier(), updateFunc.getType()); - if (oldFunc != null) { - updateFunc.setId(oldFunc.getId()); - } - }); - // 过滤掉没有设置 ID 的对象 - List validUpdateList = filterList(updateList, thingModel -> thingModel.getId() != null); - // 执行批量更新 - if (CollUtil.isNotEmpty(validUpdateList)) { - productThingModelMapper.updateBatch(validUpdateList); - } - } - - // 删除数据库中的旧事件和服务列表 - if (CollUtil.isNotEmpty(deleteList)) { - Set idsToDelete = CollectionUtils.convertSet(deleteList, IotProductThingModelDO::getId); - productThingModelMapper.deleteByIds(idsToDelete); - } + // 3.2 创建默认的事件和服务 + createDefaultEventsAndServices(oldThingModelList, newThingModelList); } /** - * 根据标识符和类型查找功能对象 + * 创建默认的事件和服务 */ - private IotProductThingModelDO findThingModelByIdentifierAndType(List thingModelList, - String identifier, Integer type) { - return CollUtil.findOne(thingModelList, func -> - Objects.equals(func.getIdentifier(), identifier) && Objects.equals(func.getType(), type)); + private void createDefaultEventsAndServices(List oldThingModelList, List newThingModelList) { + // 1.1 使用 diffList 方法比较新旧列表 + List> diffResult = diffList(oldThingModelList, newThingModelList, + (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; + }); + // 1.2 批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffResult.get(0))) { + productThingModelMapper.insertBatch(diffResult.get(0)); + } + if (CollUtil.isNotEmpty(diffResult.get(1))) { + productThingModelMapper.updateBatch(diffResult.get(1)); + } + if (CollUtil.isNotEmpty(diffResult.get(2))) { + productThingModelMapper.deleteByIds(convertSet(diffResult.get(2), IotProductThingModelDO::getId)); + } } /** * 构建事件功能对象 */ - private IotProductThingModelDO buildEventThingModelDO(Long productId, String productKey, ThingModelEvent event) { - return new IotProductThingModelDO() - .setProductId(productId) - .setProductKey(productKey) - .setIdentifier(event.getIdentifier()) - .setName(event.getName()) - .setDescription(event.getDescription()) - .setType(IotProductThingModelTypeEnum.EVENT.getType()) - .setEvent(event); + private IotProductThingModelDO buildEventThingModelDO(Long productId, String productKey, ThingModelEvent event, + String description) { + return new IotProductThingModelDO().setProductId(productId).setProductKey(productKey) + .setIdentifier(event.getIdentifier()).setName(event.getName()).setDescription(description) + .setType(IotProductThingModelTypeEnum.EVENT.getType()).setEvent(event); } /** * 构建服务功能对象 */ - private IotProductThingModelDO buildServiceThingModelDO(Long productId, String productKey, ThingModelService service) { - return new IotProductThingModelDO() - .setProductId(productId) - .setProductKey(productKey) - .setIdentifier(service.getIdentifier()) - .setName(service.getName()) - .setDescription(service.getDescription()) - .setType(IotProductThingModelTypeEnum.SERVICE.getType()) - .setService(service); + private IotProductThingModelDO buildServiceThingModelDO(Long productId, String productKey, ThingModelService service, + String description) { + return new IotProductThingModelDO().setProductId(productId).setProductKey(productKey) + .setIdentifier(service.getIdentifier()).setName(service.getName()).setDescription(description) + .setType(IotProductThingModelTypeEnum.SERVICE.getType()).setService(service); } /** * 生成属性上报事件 */ - private ThingModelEvent generatePropertyPostEvent(List propertyList) { - if (CollUtil.isEmpty(propertyList)) { + private ThingModelEvent generatePropertyPostEvent(List thingModelList) { + // 1.1 没有属性则不生成 + if (CollUtil.isEmpty(thingModelList)) { return null; } - ThingModelEvent event = new ThingModelEvent() - .setIdentifier("post") - .setName("属性上报") - .setType("info") - .setDescription("属性上报事件") - .setMethod("thing.event.property.post"); - - // 将属性列表转换为事件的输出参数 - List outputData = new ArrayList<>(); - for (IotProductThingModelDO thingModel : propertyList) { - ThingModelArgument arg = new ThingModelArgument() - .setIdentifier(thingModel.getIdentifier()) - .setName(thingModel.getName()) - .setProperty(thingModel.getProperty()) - .setDescription(thingModel.getDescription()) - .setDirection("output"); // 设置为输出参数 - outputData.add(arg); - } - event.setOutputData(outputData); - return event; + // 1.2 生成属性上报事件 + return new ThingModelEvent().setIdentifier("post").setName("属性上报").setMethod("thing.event.property.post") + .setType(IotProductThingModelServiceEventTypeEnum.INFO.getType()) + .setOutputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.OUTPUT)); } /** * 生成属性设置服务 */ - private ThingModelService generatePropertySetService(List propertyList) { - if (propertyList == null || propertyList.isEmpty()) { + private ThingModelService generatePropertySetService(List thingModelList) { + // 1.1 过滤出所有可写属性 + thingModelList = filterList(thingModelList, thingModel -> + IotProductThingModelAccessModeEnum.READ_WRITE.getMode().equals(thingModel.getProperty().getAccessMode())); + // 1.2 没有可写属性则不生成 + if (CollUtil.isEmpty(thingModelList)) { return null; } - List inputData = new ArrayList<>(); - for (IotProductThingModelDO thingModel : propertyList) { - ThingModelProperty property = thingModel.getProperty(); - if (IotProductThingModelAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) { - ThingModelArgument arg = new ThingModelArgument() - .setIdentifier(property.getIdentifier()) - .setName(property.getName()) - .setProperty(property) - .setDescription(property.getDescription()) - .setDirection("input"); // 设置为输入参数 - inputData.add(arg); - } - } - if (inputData.isEmpty()) { - // 如果没有可写属性,不生成属性设置服务 - return null; - } - - // 属性设置服务一般不需要输出参数 - return new ThingModelService() - .setIdentifier("set") - .setName("属性设置") - .setCallType("async") - .setDescription("属性设置服务") - .setMethod("thing.service.property.set") - .setInputData(inputData) - // 属性设置服务一般不需要输出参数 - .setOutputData(new ArrayList<>()); + // 2. 生成属性设置服务 + return new ThingModelService().setIdentifier("set").setName("属性设置").setMethod("thing.service.property.set") + .setCallType(IotProductThingModelServiceCallTypeEnum.ASYNC.getType()) + .setInputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.INPUT)) + .setOutputParams(Collections.emptyList()); // 属性设置服务一般不需要输出参数 } /** * 生成属性获取服务 */ - private ThingModelService generatePropertyGetService(List propertyList) { - if (propertyList == null || propertyList.isEmpty()) { + private ThingModelService generatePropertyGetService(List thingModelList) { + // 1.1 没有属性则不生成 + if (CollUtil.isEmpty(thingModelList)) { return null; } - List outputData = new ArrayList<>(); - for (IotProductThingModelDO thingModelDO : propertyList) { - ThingModelProperty property = thingModelDO.getProperty(); - if (ObjectUtils.equalsAny(property.getAccessMode(), - IotProductThingModelAccessModeEnum.READ_ONLY.getMode(), IotProductThingModelAccessModeEnum.READ_WRITE.getMode())) { - ThingModelArgument arg = new ThingModelArgument() - .setIdentifier(property.getIdentifier()) - .setName(property.getName()) - .setProperty(property) - .setDescription(property.getDescription()) - .setDirection("output"); // 设置为输出参数 - outputData.add(arg); - } - } - if (outputData.isEmpty()) { - // 如果没有可读属性,不生成属性获取服务 - return null; - } + // 1.2 生成属性获取服务 + return new ThingModelService().setIdentifier("get").setName("属性获取").setMethod("thing.service.property.get") + .setCallType(IotProductThingModelServiceCallTypeEnum.ASYNC.getType()) + .setInputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.INPUT)) + .setOutputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.OUTPUT)); + } - ThingModelService service = new ThingModelService() - .setIdentifier("get") - .setName("属性获取") - .setCallType("async") - .setDescription("属性获取服务") - .setMethod("thing.service.property.get"); - - // 定义输入参数:属性标识符列表 - ThingModelArgument inputArg = new ThingModelArgument() - .setIdentifier("properties") - .setName("属性标识符列表") - .setDescription("需要获取的属性标识符列表") - .setDirection("input"); // 设置为输入参数 - - // 创建数组类型,元素类型为文本类型(字符串)TODO @puhui999: 还得研究研究 - ThingModelArrayDataSpecs arrayType = new ThingModelArrayDataSpecs(); - arrayType.setDataType("array"); - inputArg.setProperty(new ThingModelProperty().setIdentifier(inputArg.getIdentifier()).setName(inputArg.getName()) - .setDescription(inputArg.getDescription()).setDataSpecs(arrayType)); - - ThingModelDateOrTextDataSpecs textType = new ThingModelDateOrTextDataSpecs(); - textType.setDataType("text"); - inputArg.setProperty(new ThingModelProperty().setIdentifier(inputArg.getIdentifier()).setName(inputArg.getName()) - .setDescription(inputArg.getDescription()).setDataSpecs(textType)); - - service.setInputData(Collections.singletonList(inputArg)); - service.setOutputData(outputData); - return service; + /** + * 构建输入/输出参数列表 + * + * @param thingModelList 属性列表 + * @return 输入/输出参数列表 + */ + private List buildInputOutputParam(List thingModelList, + IotProductThingModelParamDirectionEnum directionEnum) { + return convertList(thingModelList, thingModel -> + BeanUtils.toBean(thingModel.getProperty(), ThingModelInputOutputParam.class).setParaOrder(0) // TODO @puhui999: 先搞个默认值看看怎么个事 + .setDirection(directionEnum.getDirection())); } }