From da60e649dfd068519ca2f040b9579fe23ff07b10 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 29 Jun 2025 17:09:20 +0800 Subject: [PATCH] feat:【IoT 物联网】物模型数据使用 NVARCHAR 存储,并兼容 struct、array 等数据结构 --- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDevicePropertyController.java | 2 +- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/property/IotDevicePropertyDetailRespVO.java | 2 +- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.java | 35 ++++++++++++++++++----------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java | 56 -------------------------------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java | 63 --------------------------------------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java | 63 --------------------------------------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java | 62 -------------------------------------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArrayDataSpecs.java | 37 ------------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java | 30 ------------------------------ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDataSpecs.java | 35 ----------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java | 32 -------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelNumericDataSpec.java | 56 -------------------------------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java | 57 --------------------------------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java | 6 +++--- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelSaveReqVO.java | 6 +++--- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelTSLRespVO.java | 8 ++++---- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/IotThingModelConvert.java | 6 +++--- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/IotThingModelDO.java | 6 +++--- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelEvent.java | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelParam.java | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelProperty.java | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelService.java | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelArrayDataSpecs.java | 37 +++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java | 30 ++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelDataSpecs.java | 35 +++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java | 33 +++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelNumericDataSpec.java | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelStructDataSpecs.java | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableField.java | 6 ++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java | 37 +++++++++++++++++++++++++------------ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/IotDataRuleServiceImpl.java | 2 +- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java | 2 +- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java | 29 ++++++++++++----------------- 33 files changed, 573 insertions(+), 557 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArrayDataSpecs.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDataSpecs.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelNumericDataSpec.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelEvent.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelParam.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelProperty.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelArrayDataSpecs.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelDataSpecs.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelNumericDataSpec.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelStructDataSpecs.java 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 b78793f..4988efb 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 2fa2702..5771269 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 6b143a6..d93c18d 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/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 deleted file mode 100644 index bf6e20b..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java +++ /dev/null @@ -1,56 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; - -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelServiceEventTypeEnum; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.Pattern; -import lombok.Data; - -import java.util.List; - -// TODO @puhui999:感觉这个,是不是放到 dal 里会好点?(讨论下,先不改哈) -/** - * IoT 物模型中的事件 - * - * @author HUIHUI - */ -@Data -public class ThingModelEvent { - - /** - * 事件标识符 - */ - @NotEmpty(message = "事件标识符不能为空") - @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "事件标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过 32 个字符") - private String identifier; - /** - * 事件名称 - */ - @NotEmpty(message = "事件名称不能为空") - private String name; - /** - * 是否是标准品类的必选事件 - */ - private Boolean required; - /** - * 事件类型 - * - * 枚举 {@link IotThingModelServiceEventTypeEnum} - */ - @NotEmpty(message = "事件类型不能为空") - @InEnum(IotThingModelServiceEventTypeEnum.class) - private String type; - /** - * 事件的输出参数 - * - * 输出参数定义事件调用后返回的结果或反馈信息,用于确认操作结果或提供额外的信息。 - */ - @Valid - 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/ThingModelParam.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java deleted file mode 100644 index 2afad89..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java +++ /dev/null @@ -1,63 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.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.enums.thingmodel.IotDataSpecsDataTypeEnum; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelParamDirectionEnum; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.Pattern; -import lombok.Data; - -import java.util.List; - -/** - * IoT 产品物模型中的参数 - * - * @author HUIHUI - */ -@Data -public class ThingModelParam { - - /** - * 参数标识符 - */ - @NotEmpty(message = "参数标识符不能为空") - @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "参数标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过 32 个字符") - private String identifier; - /** - * 参数名称 - */ - @NotEmpty(message = "参数名称不能为空") - private String name; - /** - * 用于区分输入或输出参数 - * - * 枚举 {@link IotThingModelParamDirectionEnum} - */ - @NotEmpty(message = "参数方向不能为空") - @InEnum(IotThingModelParamDirectionEnum.class) - private String direction; - /** - * 参数的序号。从 0 开始排序,且不能重复。 - * - * TODO 考虑要不要序号,感觉是要的, 先留一手看看 - */ - private Integer paraOrder; - /** - * 参数值的数据类型,与 dataSpecs 的 dataType 保持一致 - * - * 枚举 {@link IotDataSpecsDataTypeEnum} - */ - @NotEmpty(message = "数据类型不能为空") - @InEnum(IotDataSpecsDataTypeEnum.class) - 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 deleted file mode 100644 index 4b9a05a..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java +++ /dev/null @@ -1,63 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.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.enums.thingmodel.IotDataSpecsDataTypeEnum; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelAccessModeEnum; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.Pattern; -import lombok.Data; - -import java.util.List; - -/** - * IoT 物模型中的属性 - * - * dataSpecs 和 dataSpecsList 之中必须传入且只能传入一个 - * - * @author HUIHUI - */ -@Data -public class ThingModelProperty { - - /** - * 属性标识符 - */ - @NotEmpty(message = "属性标识符不能为空") - @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "属性标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过 32 个字符") - private String identifier; - /** - * 属性名称 - */ - @NotEmpty(message = "属性名称不能为空") - private String name; - /** - * 云端可以对该属性进行的操作类型 - * - * 枚举 {@link IotThingModelAccessModeEnum} - */ - @NotEmpty(message = "操作类型不能为空") - @InEnum(IotThingModelAccessModeEnum.class) - private String accessMode; - /** - * 是否是标准品类的必选服务 - */ - private Boolean required; - /** - * 参数值的数据类型,与 dataSpecs 的 dataType 保持一致 - * - * 枚举 {@link IotDataSpecsDataTypeEnum} - */ - @NotEmpty(message = "数据类型不能为空") - @InEnum(IotDataSpecsDataTypeEnum.class) - 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/ThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java deleted file mode 100644 index c98acd8..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java +++ /dev/null @@ -1,62 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; - -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelServiceCallTypeEnum; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.Pattern; -import lombok.Data; - -import java.util.List; - -/** - * IoT 物模型中的服务 - * - * @author HUIHUI - */ -@Data -public class ThingModelService { - - /** - * 服务标识符 - */ - @NotEmpty(message = "服务标识符不能为空") - @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "服务标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过 32 个字符") - private String identifier; - /** - * 服务名称 - */ - @NotEmpty(message = "服务名称不能为空") - private String name; - /** - * 是否是标准品类的必选服务 - */ - private Boolean required; - /** - * 调用类型 - * - * 枚举 {@link IotThingModelServiceCallTypeEnum} - */ - @NotEmpty(message = "调用类型不能为空") - @InEnum(IotThingModelServiceCallTypeEnum.class) - private String callType; - /** - * 服务的输入参数 - * - * 输入参数定义服务调用时所需提供的信息,用于控制设备行为或执行特定任务 - */ - @Valid - private List inputParams; - /** - * 服务的输出参数 - * - * 输出参数定义服务调用后返回的结果或反馈信息,用于确认操作结果或提供额外的信息。 - */ - @Valid - 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/ThingModelArrayDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArrayDataSpecs.java deleted file mode 100644 index 554bd2a..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArrayDataSpecs.java +++ /dev/null @@ -1,37 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Pattern; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.util.List; - -/** - * IoT 物模型数据类型为数组的 DataSpec 定义 - * - * @author HUIHUI - */ -@Data -@EqualsAndHashCode(callSuper = true) -@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复 -public class ThingModelArrayDataSpecs extends ThingModelDataSpecs { - - @NotNull(message = "数组元素个数不能为空") - private Integer size; - - @NotEmpty(message = "数组元素的数据类型不能为空") - @Pattern(regexp = "^(struct|int|float|double|text)$", message = "数组元素的数据类型必须为:struct、int、float、double 或 text") - private String childDataType; - /** - * 数据类型(childDataType)为列表型 struct 的数据规范存储在 dataSpecsList 中 - * 此时 struct 取值范围为:int、float、double、text、date、enum、bool - */ - @Valid - 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/dataType/ThingModelBoolOrEnumDataSpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java deleted file mode 100644 index 80a4e0d..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Pattern; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * IoT 物模型数据类型为布尔型或枚举型的 DataSpec 定义 - * - * 数据类型,取值为 bool 或 enum。 - * - * @author HUIHUI - */ -@Data -@EqualsAndHashCode(callSuper = true) -@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复 -public class ThingModelBoolOrEnumDataSpecs extends ThingModelDataSpecs { - - @NotEmpty(message = "枚举项的名称不能为空") - @Pattern(regexp = "^[\\u4e00-\\u9fa5a-zA-Z0-9][\\u4e00-\\u9fa5a-zA-Z0-9_-]{0,19}$", - message = "枚举项的名称只能包含中文、大小写英文字母、数字、下划线和短划线,必须以中文、英文字母或数字开头,长度不超过 20 个字符") - private String name; - - @NotNull(message = "枚举值不能为空") - private Integer value; - -} 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/controller/admin/thingmodel/model/dataType/ThingModelDataSpecs.java deleted file mode 100644 index d9fc12d..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDataSpecs.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; - -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import lombok.Data; - -/** - * IoT ThingModelDataSpecs 抽象类 - * - * 用于表示物模型数据的通用类型,根据具体的 "dataType" 字段动态映射到对应的子类。 - * 提供多态支持,适用于不同类型的数据结构序列化和反序列化场景。 - * - * @author HUIHUI - */ -@Data -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "dataType", visible = true) -@JsonSubTypes({ - @JsonSubTypes.Type(value = ThingModelNumericDataSpec.class, name = "int"), - @JsonSubTypes.Type(value = ThingModelNumericDataSpec.class, name = "float"), - @JsonSubTypes.Type(value = ThingModelNumericDataSpec.class, name = "double"), - @JsonSubTypes.Type(value = ThingModelDateOrTextDataSpecs.class, name = "text"), - @JsonSubTypes.Type(value = ThingModelDateOrTextDataSpecs.class, name = "date"), - @JsonSubTypes.Type(value = ThingModelBoolOrEnumDataSpecs.class, name = "bool"), - @JsonSubTypes.Type(value = ThingModelBoolOrEnumDataSpecs.class, name = "enum"), - @JsonSubTypes.Type(value = ThingModelArrayDataSpecs.class, name = "array"), - @JsonSubTypes.Type(value = ThingModelStructDataSpecs.class, name = "struct") -}) -public abstract class ThingModelDataSpecs { - - /** - * 数据类型 - */ - private String dataType; - -} 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/controller/admin/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java deleted file mode 100644 index 489833d..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import jakarta.validation.constraints.Max; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * IoT 物模型数据类型为时间型或文本型的 DataSpec 定义 - * - * 数据类型,取值为 date 或 text。 - * - * @author HUIHUI - */ -@Data -@EqualsAndHashCode(callSuper = true) -@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复 -public class ThingModelDateOrTextDataSpecs extends ThingModelDataSpecs { - - /** - * 数据长度,单位为字节。取值不能超过 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/controller/admin/thingmodel/model/dataType/ThingModelNumericDataSpec.java deleted file mode 100644 index bd3457d..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelNumericDataSpec.java +++ /dev/null @@ -1,56 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.Pattern; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * IoT 物模型数据类型为数值的 DataSpec 定义 - * - * 数据类型,取值为 int、float 或 double。 - * - * @author HUIHUI - */ -@Data -@EqualsAndHashCode(callSuper = true) -@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复 -public class ThingModelNumericDataSpec extends ThingModelDataSpecs { - - /** - * 最大值,需转为字符串类型。值必须与 dataType 类型一致。 - */ - @NotEmpty(message = "最大值不能为空") - @Pattern(regexp = "^-?\\d+(\\.\\d+)?$", message = "最大值必须为数值类型") - private String max; - /** - * 最小值,需转为字符串类型。值必须与 dataType 类型一致。 - */ - @NotEmpty(message = "最小值不能为空") - @Pattern(regexp = "^-?\\d+(\\.\\d+)?$", message = "最小值必须为数值类型") - private String min; - /** - * 步长,需转为字符串类型。值必须与 dataType 类型一致。 - */ - @NotEmpty(message = "步长不能为空") - @Pattern(regexp = "^-?\\d+(\\.\\d+)?$", message = "步长必须为数值类型") - private String step; - /** - * 精度。当 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/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java deleted file mode 100644 index 6ab7902..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java +++ /dev/null @@ -1,57 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType; - -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelAccessModeEnum; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.Pattern; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.util.List; - -/** - * IoT 物模型数据类型为 struct 的 DataSpec 定义 - * - * @author HUIHUI - */ -@Data -@EqualsAndHashCode(callSuper = true) -@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复 -public class ThingModelStructDataSpecs extends ThingModelDataSpecs { - - @NotEmpty(message = "属性标识符不能为空") - @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "属性标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过 32 个字符") - private String identifier; - - @NotEmpty(message = "属性名称不能为空") - private String name; - - @NotEmpty(message = "操作类型不能为空") - @InEnum(IotThingModelAccessModeEnum.class) - private String accessMode; - - /** - * 是否是标准品类的必选服务 - */ - private Boolean required; - - @NotEmpty(message = "数据类型不能为空") - @Pattern(regexp = "^(int|float|double|text|date|enum|bool)$", message = "数据类型必须为:int、float、double、text、date、enum、bool") - private String childDataType; - - /** - * 数据类型(dataType)为非列表型(int、float、double、text、date、array)的数据规范存储在 dataSpecs 中 - */ - @Valid - private ThingModelDataSpecs dataSpecs; - - /** - * 数据类型(dataType)为列表型(enum、bool、struct)的数据规范存储在 dataSpecsList 中 - */ - @Valid - private List dataSpecsList; - -} - 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 2b7f17a..a7a17dd 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 1e8564d..9740498 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 a5b28fd..d3809d8 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 9577b18..6abbe97 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 e3b4a6d..d70d2e1 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/dal/dataobject/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 new file mode 100644 index 0000000..4d85370 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelEvent.java @@ -0,0 +1,56 @@ +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; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Pattern; +import lombok.Data; + +import java.util.List; + +// TODO @puhui999:感觉这个,是不是放到 dal 里会好点?(讨论下,先不改哈) +/** + * IoT 物模型中的事件 + * + * @author HUIHUI + */ +@Data +public class ThingModelEvent { + + /** + * 事件标识符 + */ + @NotEmpty(message = "事件标识符不能为空") + @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "事件标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过 32 个字符") + private String identifier; + /** + * 事件名称 + */ + @NotEmpty(message = "事件名称不能为空") + private String name; + /** + * 是否是标准品类的必选事件 + */ + private Boolean required; + /** + * 事件类型 + * + * 枚举 {@link IotThingModelServiceEventTypeEnum} + */ + @NotEmpty(message = "事件类型不能为空") + @InEnum(IotThingModelServiceEventTypeEnum.class) + private String type; + /** + * 事件的输出参数 + * + * 输出参数定义事件调用后返回的结果或反馈信息,用于确认操作结果或提供额外的信息。 + */ + @Valid + private List outputParams; + /** + * 标识设备需要执行的具体操作 + */ + private String method; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/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 new file mode 100644 index 0000000..3919542 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelParam.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +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; +import jakarta.validation.constraints.Pattern; +import lombok.Data; + +import java.util.List; + +/** + * IoT 产品物模型中的参数 + * + * @author HUIHUI + */ +@Data +public class ThingModelParam { + + /** + * 参数标识符 + */ + @NotEmpty(message = "参数标识符不能为空") + @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "参数标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过 32 个字符") + private String identifier; + /** + * 参数名称 + */ + @NotEmpty(message = "参数名称不能为空") + private String name; + /** + * 用于区分输入或输出参数 + * + * 枚举 {@link IotThingModelParamDirectionEnum} + */ + @NotEmpty(message = "参数方向不能为空") + @InEnum(IotThingModelParamDirectionEnum.class) + private String direction; + /** + * 参数的序号。从 0 开始排序,且不能重复。 + * + * TODO 考虑要不要序号,感觉是要的, 先留一手看看 + */ + private Integer paraOrder; + /** + * 参数值的数据类型,与 dataSpecs 的 dataType 保持一致 + * + * 枚举 {@link IotDataSpecsDataTypeEnum} + */ + @NotEmpty(message = "数据类型不能为空") + @InEnum(IotDataSpecsDataTypeEnum.class) + 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/dal/dataobject/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 new file mode 100644 index 0000000..2fe103a --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelProperty.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +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; +import jakarta.validation.constraints.Pattern; +import lombok.Data; + +import java.util.List; + +/** + * IoT 物模型中的属性 + * + * dataSpecs 和 dataSpecsList 之中必须传入且只能传入一个 + * + * @author HUIHUI + */ +@Data +public class ThingModelProperty { + + /** + * 属性标识符 + */ + @NotEmpty(message = "属性标识符不能为空") + @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "属性标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过 32 个字符") + private String identifier; + /** + * 属性名称 + */ + @NotEmpty(message = "属性名称不能为空") + private String name; + /** + * 云端可以对该属性进行的操作类型 + * + * 枚举 {@link IotThingModelAccessModeEnum} + */ + @NotEmpty(message = "操作类型不能为空") + @InEnum(IotThingModelAccessModeEnum.class) + private String accessMode; + /** + * 是否是标准品类的必选服务 + */ + private Boolean required; + /** + * 参数值的数据类型,与 dataSpecs 的 dataType 保持一致 + * + * 枚举 {@link IotDataSpecsDataTypeEnum} + */ + @NotEmpty(message = "数据类型不能为空") + @InEnum(IotDataSpecsDataTypeEnum.class) + 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/dal/dataobject/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 new file mode 100644 index 0000000..1047695 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelService.java @@ -0,0 +1,62 @@ +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; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Pattern; +import lombok.Data; + +import java.util.List; + +/** + * IoT 物模型中的服务 + * + * @author HUIHUI + */ +@Data +public class ThingModelService { + + /** + * 服务标识符 + */ + @NotEmpty(message = "服务标识符不能为空") + @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "服务标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过 32 个字符") + private String identifier; + /** + * 服务名称 + */ + @NotEmpty(message = "服务名称不能为空") + private String name; + /** + * 是否是标准品类的必选服务 + */ + private Boolean required; + /** + * 调用类型 + * + * 枚举 {@link IotThingModelServiceCallTypeEnum} + */ + @NotEmpty(message = "调用类型不能为空") + @InEnum(IotThingModelServiceCallTypeEnum.class) + private String callType; + /** + * 服务的输入参数 + * + * 输入参数定义服务调用时所需提供的信息,用于控制设备行为或执行特定任务 + */ + @Valid + private List inputParams; + /** + * 服务的输出参数 + * + * 输出参数定义服务调用后返回的结果或反馈信息,用于确认操作结果或提供额外的信息。 + */ + @Valid + private List outputParams; + /** + * 标识设备需要执行的具体操作 + */ + private String method; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/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 new file mode 100644 index 0000000..7107f99 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelArrayDataSpecs.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +/** + * IoT 物模型数据类型为数组的 DataSpec 定义 + * + * @author HUIHUI + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复 +public class ThingModelArrayDataSpecs extends ThingModelDataSpecs { + + @NotNull(message = "数组元素个数不能为空") + private Integer size; + + @NotEmpty(message = "数组元素的数据类型不能为空") + @Pattern(regexp = "^(struct|int|float|double|text)$", message = "数组元素的数据类型必须为:struct、int、float、double 或 text") + private String childDataType; + /** + * 数据类型(childDataType)为列表型 struct 的数据规范存储在 dataSpecsList 中 + * 此时 struct 取值范围为:int、float、double、text、date、enum、bool + */ + @Valid + private List dataSpecsList; + +} + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/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 new file mode 100644 index 0000000..8533fcc --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelBoolOrEnumDataSpecs.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * IoT 物模型数据类型为布尔型或枚举型的 DataSpec 定义 + * + * 数据类型,取值为 bool 或 enum + * + * @author HUIHUI + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复 +public class ThingModelBoolOrEnumDataSpecs extends ThingModelDataSpecs { + + @NotEmpty(message = "枚举项的名称不能为空") + @Pattern(regexp = "^[\\u4e00-\\u9fa5a-zA-Z0-9][\\u4e00-\\u9fa5a-zA-Z0-9_-]{0,19}$", + message = "枚举项的名称只能包含中文、大小写英文字母、数字、下划线和短划线,必须以中文、英文字母或数字开头,长度不超过 20 个字符") + private String name; + + @NotNull(message = "枚举值不能为空") + private Integer value; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/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 new file mode 100644 index 0000000..1643ab2 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelDataSpecs.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import lombok.Data; + +/** + * IoT ThingModelDataSpecs 抽象类 + * + * 用于表示物模型数据的通用类型,根据具体的 "dataType" 字段动态映射到对应的子类 + * 提供多态支持,适用于不同类型的数据结构序列化和反序列化场景 + * + * @author HUIHUI + */ +@Data +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "dataType", visible = true) +@JsonSubTypes({ + @JsonSubTypes.Type(value = ThingModelNumericDataSpec.class, name = "int"), + @JsonSubTypes.Type(value = ThingModelNumericDataSpec.class, name = "float"), + @JsonSubTypes.Type(value = ThingModelNumericDataSpec.class, name = "double"), + @JsonSubTypes.Type(value = ThingModelDateOrTextDataSpecs.class, name = "text"), + @JsonSubTypes.Type(value = ThingModelDateOrTextDataSpecs.class, name = "date"), + @JsonSubTypes.Type(value = ThingModelBoolOrEnumDataSpecs.class, name = "bool"), + @JsonSubTypes.Type(value = ThingModelBoolOrEnumDataSpecs.class, name = "enum"), + @JsonSubTypes.Type(value = ThingModelArrayDataSpecs.class, name = "array"), + @JsonSubTypes.Type(value = ThingModelStructDataSpecs.class, name = "struct") +}) +public abstract class ThingModelDataSpecs { + + /** + * 数据类型 + */ + private String dataType; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/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 new file mode 100644 index 0000000..18ca982 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import jakarta.validation.constraints.Max; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * IoT 物模型数据类型为时间型或文本型的 DataSpec 定义 + * + * 数据类型,取值为 date 或 text + * + * @author HUIHUI + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复 +public class ThingModelDateOrTextDataSpecs extends ThingModelDataSpecs { + + /** + * 数据长度,单位为字节。取值不能超过 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/dal/dataobject/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 new file mode 100644 index 0000000..4433a9b --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelNumericDataSpec.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.model.dataType; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Pattern; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * IoT 物模型数据类型为数值的 DataSpec 定义 + * + * 数据类型,取值为 int、float 或 double + * + * @author HUIHUI + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复 +public class ThingModelNumericDataSpec extends ThingModelDataSpecs { + + /** + * 最大值,需转为字符串类型。值必须与 dataType 类型一致 + */ + @NotEmpty(message = "最大值不能为空") + @Pattern(regexp = "^-?\\d+(\\.\\d+)?$", message = "最大值必须为数值类型") + private String max; + /** + * 最小值,需转为字符串类型。值必须与 dataType 类型一致 + */ + @NotEmpty(message = "最小值不能为空") + @Pattern(regexp = "^-?\\d+(\\.\\d+)?$", message = "最小值必须为数值类型") + private String min; + /** + * 步长,需转为字符串类型。值必须与 dataType 类型一致 + */ + @NotEmpty(message = "步长不能为空") + @Pattern(regexp = "^-?\\d+(\\.\\d+)?$", message = "步长必须为数值类型") + private String step; + /** + * 精度。当 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/dal/dataobject/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 new file mode 100644 index 0000000..a866a00 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelStructDataSpecs.java @@ -0,0 +1,57 @@ +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; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Pattern; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +/** + * IoT 物模型数据类型为 struct 的 DataSpec 定义 + * + * @author HUIHUI + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JsonIgnoreProperties({"dataType"}) // 忽略子类中的 dataType 字段,从而避免重复 +public class ThingModelStructDataSpecs extends ThingModelDataSpecs { + + @NotEmpty(message = "属性标识符不能为空") + @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "属性标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过 32 个字符") + private String identifier; + + @NotEmpty(message = "属性名称不能为空") + private String name; + + @NotEmpty(message = "操作类型不能为空") + @InEnum(IotThingModelAccessModeEnum.class) + private String accessMode; + + /** + * 是否是标准品类的必选服务 + */ + private Boolean required; + + @NotEmpty(message = "数据类型不能为空") + @Pattern(regexp = "^(int|float|double|text|date|enum|bool)$", message = "数据类型必须为:int、float、double、text、date、enum、bool") + private String childDataType; + + /** + * 数据类型(dataType)为非列表型(int、float、double、text、date、array)的数据规范存储在 dataSpecs 中 + */ + @Valid + private ThingModelDataSpecs dataSpecs; + + /** + * 数据类型(dataType)为列表型(enum、bool、struct)的数据规范存储在 dataSpecsList 中 + */ + @Valid + private List dataSpecsList; + +} + 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 e3bbdd2..48c3142 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,9 +23,15 @@ 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 字段 */ public static final String NOTE_TAG = "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 b3fe9f4..8031c2a 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 81ce34d..3144a13 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 b4af6f6..b8c951b 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 a72b6d4..ca04ecd 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() { -- libgit2 0.21.4