pageResult = productService.getProductPage(pageReqVO);
+ return success(BeanUtils.toBean(pageResult, IotProductRespVO.class));
}
}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductPageReqVO.java
new file mode 100644
index 000000000..afc3aafa0
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductPageReqVO.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.iot.controller.admin.product.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+// TODO @haohao:涉及到 iot 的拼写,要不都用 IoT,貌似更规范
+@Schema(description = "管理后台 - iot 产品分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class IotProductPageReqVO extends PageParam {
+
+ @Schema(description = "产品名称", example = "李四")
+ private String name;
+
+ @Schema(description = "产品标识")
+ private String productKey;
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductRespVO.java
similarity index 98%
rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductRespVO.java
rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductRespVO.java
index 1a60f0290..066efca93 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductRespVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductRespVO.java
@@ -10,7 +10,7 @@ import java.time.LocalDateTime;
@Schema(description = "管理后台 - iot 产品 Response VO")
@Data
@ExcelIgnoreUnannotated
-public class ProductRespVO {
+public class IotProductRespVO {
@Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26087")
@ExcelProperty("产品ID")
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java
similarity index 85%
rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java
rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java
index ecbbb03c9..ad01bcd03 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java
@@ -3,13 +3,13 @@ package cn.iocoder.yudao.module.iot.controller.admin.product.vo;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.iot.enums.product.*;
import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.*;
-import java.util.*;
-import jakarta.validation.constraints.*;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
@Schema(description = "管理后台 - iot 产品新增/修改 Request VO")
@Data
-public class ProductSaveReqVO {
+public class IotProductSaveReqVO {
@Schema(description = "产品编号", requiredMode = Schema.RequiredMode.AUTO, example = "1")
private Long id;
@@ -26,15 +26,15 @@ public class ProductSaveReqVO {
@NotNull(message = "设备类型不能为空")
private Integer deviceType;
- @Schema(description = "联网方式", requiredMode = Schema.RequiredMode.REQUIRED,example = "0")
+ @Schema(description = "联网方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@InEnum(value = IotNetTypeEnum.class, message = "联网方式必须是 {value}")
private Integer netType;
- @Schema(description = "接入网关协议", requiredMode = Schema.RequiredMode.REQUIRED,example = "0")
+ @Schema(description = "接入网关协议", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@InEnum(value = IotProtocolTypeEnum.class, message = "接入网关协议必须是 {value}")
private Integer protocolType;
- @Schema(description = "数据格式",requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ @Schema(description = "数据格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@InEnum(value = IotDataFormatEnum.class, message = "数据格式必须是 {value}")
@NotNull(message = "数据格式不能为空")
private Integer dataFormat;
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductPageReqVO.java
deleted file mode 100644
index dc0ae9d65..000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductPageReqVO.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package cn.iocoder.yudao.module.iot.controller.admin.product.vo;
-
-import cn.iocoder.yudao.framework.common.pojo.PageParam;
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-import org.springframework.format.annotation.DateTimeFormat;
-
-import java.time.LocalDateTime;
-
-import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
-
-// TODO @haohao:涉及到 iot 的拼写,要不都用 IoT,貌似更规范
-// TODO 芋艿:需要清理掉一些无用字段
-@Schema(description = "管理后台 - iot 产品分页 Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class ProductPageReqVO extends PageParam {
-
- @Schema(description = "产品名称", example = "李四")
- private String name;
-
- @Schema(description = "创建时间")
- @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
- private LocalDateTime[] createTime;
-
- @Schema(description = "产品标识")
- private String productKey;
-
- @Schema(description = "接入网关协议", example = "2")
- private Integer protocolType;
-
- @Schema(description = "协议编号(脚本解析 id)", example = "13177")
- private Long protocolId;
-
- @Schema(description = "产品所属品类标识符", example = "14237")
- private Long categoryId;
-
- @Schema(description = "产品描述", example = "你猜")
- private String description;
-
- @Schema(description = "数据校验级别", example = "1")
- private Integer validateType;
-
- @Schema(description = "产品状态", example = "1")
- private Integer status;
-
- @Schema(description = "设备类型", example = "2")
- private Integer deviceType;
-
- @Schema(description = "联网方式", example = "2")
- private Integer netType;
-
- @Schema(description = "数据格式", example = "0")
- private Integer dataFormat;
-
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/ProductDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java
similarity index 94%
rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/ProductDO.java
rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java
index 37c1eb513..1fa22c7d1 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/ProductDO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java
@@ -19,7 +19,7 @@ import lombok.*;
@Builder
@NoArgsConstructor
@AllArgsConstructor
-public class ProductDO extends BaseDO {
+public class IotProductDO extends BaseDO {
/**
* 产品ID
@@ -37,7 +37,7 @@ public class ProductDO extends BaseDO {
private String productKey;
/**
* 产品所属品类编号
- *
+ *
* TODO 外键:后续加
*/
private Long categoryId;
@@ -48,44 +48,44 @@ public class ProductDO extends BaseDO {
/**
* 产品状态
- *
+ *
* 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum}
*/
private Integer status;
/**
* 设备类型
- *
+ *
* 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum}
*/
private Integer deviceType;
/**
* 联网方式
- *
+ *
* 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotNetTypeEnum}
*/
private Integer netType;
/**
* 接入网关协议
- *
+ *
* 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotProtocolTypeEnum}
*/
private Integer protocolType;
/**
* 协议编号
- *
+ *
* TODO 外键:后续加
*/
private Long protocolId;
/**
* 数据格式
- *
+ *
* 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotDataFormatEnum}
*/
private Integer dataFormat;
/**
* 数据校验级别
- *
+ *
* 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotValidateTypeEnum}
*/
private Integer validateType;
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java
new file mode 100644
index 000000000..111ed4969
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java
@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.iot.dal.mysql.product;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductPageReqVO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * iot 产品 Mapper
+ *
+ * @author ahh
+ */
+@Mapper
+public interface IotProductMapper extends BaseMapperX {
+
+ default PageResult selectPage(IotProductPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX()
+ .likeIfPresent(IotProductDO::getName, reqVO.getName())
+ .likeIfPresent(IotProductDO::getProductKey, reqVO.getProductKey())
+ .orderByDesc(IotProductDO::getId));
+ }
+
+ default IotProductDO selectByProductKey(String productKey) {
+ return selectOne(new LambdaQueryWrapperX().eq(IotProductDO::getProductKey, productKey));
+ }
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java
deleted file mode 100644
index d9af9b4b9..000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package cn.iocoder.yudao.module.iot.dal.mysql.product;
-
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
-import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductPageReqVO;
-import cn.iocoder.yudao.module.iot.dal.dataobject.product.ProductDO;
-import org.apache.ibatis.annotations.Mapper;
-
-/**
- * iot 产品 Mapper
- *
- * @author ahh
- */
-@Mapper
-public interface ProductMapper extends BaseMapperX {
-
- default PageResult selectPage(ProductPageReqVO reqVO) {
- return selectPage(reqVO, new LambdaQueryWrapperX()
- .likeIfPresent(ProductDO::getName, reqVO.getName())
- .betweenIfPresent(ProductDO::getCreateTime, reqVO.getCreateTime())
- .likeIfPresent(ProductDO::getProductKey, reqVO.getProductKey())
- .eqIfPresent(ProductDO::getProtocolId, reqVO.getProtocolId())
- .eqIfPresent(ProductDO::getCategoryId, reqVO.getCategoryId())
- .eqIfPresent(ProductDO::getDescription, reqVO.getDescription())
- .eqIfPresent(ProductDO::getValidateType, reqVO.getValidateType())
- .eqIfPresent(ProductDO::getStatus, reqVO.getStatus())
- .eqIfPresent(ProductDO::getDeviceType, reqVO.getDeviceType())
- .eqIfPresent(ProductDO::getNetType, reqVO.getNetType())
- .eqIfPresent(ProductDO::getProtocolType, reqVO.getProtocolType())
- .eqIfPresent(ProductDO::getDataFormat, reqVO.getDataFormat())
- .orderByDesc(ProductDO::getId));
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java
similarity index 62%
rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java
rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java
index 8d4fdf801..14f408030 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java
@@ -1,9 +1,9 @@
package cn.iocoder.yudao.module.iot.service.product;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductPageReqVO;
-import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductSaveReqVO;
-import cn.iocoder.yudao.module.iot.dal.dataobject.product.ProductDO;
+import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductPageReqVO;
+import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSaveReqVO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import jakarta.validation.Valid;
/**
@@ -11,7 +11,7 @@ import jakarta.validation.Valid;
*
* @author ahh
*/
-public interface ProductService {
+public interface IotProductService {
/**
* 创建产品
@@ -19,14 +19,14 @@ public interface ProductService {
* @param createReqVO 创建信息
* @return 编号
*/
- Long createProduct(@Valid ProductSaveReqVO createReqVO);
+ Long createProduct(@Valid IotProductSaveReqVO createReqVO);
/**
* 更新产品
*
* @param updateReqVO 更新信息
*/
- void updateProduct(@Valid ProductSaveReqVO updateReqVO);
+ void updateProduct(@Valid IotProductSaveReqVO updateReqVO);
/**
* 删除产品
@@ -41,7 +41,7 @@ public interface ProductService {
* @param id 编号
* @return 产品
*/
- ProductDO getProduct(Long id);
+ IotProductDO getProduct(Long id);
/**
* 获得产品分页
@@ -49,7 +49,7 @@ public interface ProductService {
* @param pageReqVO 分页查询
* @return 产品分页
*/
- PageResult getProductPage(ProductPageReqVO pageReqVO);
+ PageResult getProductPage(IotProductPageReqVO pageReqVO);
/**
* 更新产品状态
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java
new file mode 100644
index 000000000..65686f533
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java
@@ -0,0 +1,117 @@
+package cn.iocoder.yudao.module.iot.service.product;
+
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductPageReqVO;
+import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSaveReqVO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
+import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper;
+import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.Objects;
+import java.util.UUID;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS;
+import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_STATUS_NOT_DELETE;
+
+/**
+ * IOT 产品 Service 实现类
+ *
+ * @author ahh
+ */
+@Service
+@Validated
+public class IotProductServiceImpl implements IotProductService {
+
+ @Resource
+ private IotProductMapper productMapper;
+
+ @Override
+ public Long createProduct(IotProductSaveReqVO createReqVO) {
+ // 1. 生成 ProductKey
+ createProductKey(createReqVO);
+ // 2. 插入
+ IotProductDO product = BeanUtils.toBean(createReqVO, IotProductDO.class);
+ productMapper.insert(product);
+ return product.getId();
+ }
+
+ /**
+ * 创建 ProductKey
+ *
+ * @param createReqVO 创建信息
+ */
+ private void createProductKey(IotProductSaveReqVO createReqVO) {
+ String productKey = createReqVO.getProductKey();
+ // 1. productKey为空,生成随机的 11 位字符串
+ if (StrUtil.isEmpty(productKey)) {
+ productKey = UUID.randomUUID().toString().replace("-", "").substring(0, 11);
+ }
+ // 2. 校验唯一性
+ if (productMapper.selectByProductKey(productKey) != null) {
+ throw exception(PRODUCT_NOT_EXISTS);
+ }
+ createReqVO.setProductKey(productKey);
+ }
+
+ @Override
+ public void updateProduct(IotProductSaveReqVO updateReqVO) {
+ updateReqVO.setProductKey(null); // 不更新产品标识
+ // 1.1 校验存在
+ IotProductDO iotProductDO = validateProductExists(updateReqVO.getId());
+ // 1.2 发布状态不可更新
+ validateProductStatus(iotProductDO);
+ // 2. 更新
+ IotProductDO updateObj = BeanUtils.toBean(updateReqVO, IotProductDO.class);
+ productMapper.updateById(updateObj);
+ }
+
+ @Override
+ public void deleteProduct(Long id) {
+ // 1.1 校验存在
+ IotProductDO iotProductDO = validateProductExists(id);
+ // 1.2 发布状态不可删除
+ validateProductStatus(iotProductDO);
+ // 2. 删除
+ productMapper.deleteById(id);
+ }
+
+ private IotProductDO validateProductExists(Long id) {
+ IotProductDO iotProductDO = productMapper.selectById(id);
+ if (iotProductDO == null) {
+ throw exception(PRODUCT_NOT_EXISTS);
+ }
+ return iotProductDO;
+ }
+
+ private void validateProductStatus(IotProductDO iotProductDO) {
+ if (Objects.equals(iotProductDO.getStatus(), IotProductStatusEnum.PUBLISHED.getType())) {
+ throw exception(PRODUCT_STATUS_NOT_DELETE);
+ }
+ }
+
+ @Override
+ public IotProductDO getProduct(Long id) {
+ return productMapper.selectById(id);
+ }
+
+ @Override
+ public PageResult getProductPage(IotProductPageReqVO pageReqVO) {
+ return productMapper.selectPage(pageReqVO);
+ }
+
+ @Override
+ public void updateProductStatus(Long id, Integer status) {
+ // 1. 校验存在
+ validateProductExists(id);
+ // 2. 更新
+ IotProductDO updateObj = IotProductDO.builder().id(id).status(status).build();
+ productMapper.updateById(updateObj);
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java
deleted file mode 100644
index e5e3bc421..000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package cn.iocoder.yudao.module.iot.service.product;
-
-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.product.vo.ProductPageReqVO;
-import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductSaveReqVO;
-import cn.iocoder.yudao.module.iot.dal.dataobject.product.ProductDO;
-import cn.iocoder.yudao.module.iot.dal.mysql.product.ProductMapper;
-import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum;
-import jakarta.annotation.Resource;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import java.util.Objects;
-import java.util.UUID;
-
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS;
-import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_STATUS_NOT_DELETE;
-
-/**
- * IOT 产品 Service 实现类
- *
- * @author ahh
- */
-@Service
-@Validated
-public class ProductServiceImpl implements ProductService {
-
- @Resource
- private ProductMapper productMapper;
-
- @Override
- public Long createProduct(ProductSaveReqVO createReqVO) {
- // 生成 ProductKey
- createProductKey(createReqVO);
- // 插入
- ProductDO product = BeanUtils.toBean(createReqVO, ProductDO.class);
- productMapper.insert(product);
- return product.getId();
- }
-
- /**
- * 创建 ProductKey
- *
- * @param createReqVO 创建信息
- */
- private void createProductKey(ProductSaveReqVO createReqVO) {
- // TODO @haohao:应该前端没传递的时候,才生成哇?ps:需要校验下唯一性,万一有重复;
- // 生成随机的 11 位字符串
- String productKey = UUID.randomUUID().toString().replace("-", "").substring(0, 11);
- createReqVO.setProductKey(productKey);
- }
-
- @Override
- public void updateProduct(ProductSaveReqVO updateReqVO) {
- updateReqVO.setProductKey(null); // 不更新产品标识
- // 校验存在
- validateProductExists(updateReqVO.getId());
- // TODO @haohao:如果已经发布,允许编辑么?
- // 更新
- ProductDO updateObj = BeanUtils.toBean(updateReqVO, ProductDO.class);
- productMapper.updateById(updateObj);
- }
-
- @Override
- public void deleteProduct(Long id) {
- // TODO @haohao:这里最好只查询一次哈
- // 1.1 校验存在
- validateProductExists(id);
- // 1.2 发布状态不可删除
- validateProductStatus(id);
- // 2. 删除
- productMapper.deleteById(id);
- }
-
- private void validateProductExists(Long id) {
- if (productMapper.selectById(id) == null) {
- throw exception(PRODUCT_NOT_EXISTS);
- }
- }
-
- private void validateProductStatus(Long id) {
- ProductDO product = productMapper.selectById(id);
- if (Objects.equals(product.getStatus(), IotProductStatusEnum.PUBLISHED.getType())) {
- throw exception(PRODUCT_STATUS_NOT_DELETE);
- }
- }
-
- @Override
- public ProductDO getProduct(Long id) {
- return productMapper.selectById(id);
- }
-
- @Override
- public PageResult getProductPage(ProductPageReqVO pageReqVO) {
- return productMapper.selectPage(pageReqVO);
- }
-
- @Override
- public void updateProductStatus(Long id, Integer status) {
- // 校验存在
- validateProductExists(id);
- // 更新
- ProductDO updateObj = ProductDO.builder().id(id).status(status).build();
- productMapper.updateById(updateObj);
- }
-
-}
\ No newline at end of file
From 1aef8515e2ce87e539518752a11e8a13e98b09dc Mon Sep 17 00:00:00 2001
From: YunaiV
Date: Tue, 10 Sep 2024 21:35:31 +0800
Subject: [PATCH 11/31] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?=
=?UTF-8?q?=E5=AE=A1=E3=80=91IOT=EF=BC=9A=E4=BA=A7=E5=93=81=E7=9A=84?=
=?UTF-8?q?=E7=AE=A1=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../controller/admin/product/IotProductController.java | 10 +---------
.../admin/product/vo/IotProductPageReqVO.java | 3 +--
.../controller/admin/product/vo/IotProductRespVO.java | 6 +++---
.../admin/product/vo/IotProductSaveReqVO.java | 2 +-
.../iot/dal/dataobject/product/IotProductDO.java | 2 +-
.../module/iot/dal/mysql/product/IotProductMapper.java | 2 +-
.../module/iot/service/product/IotProductService.java | 2 +-
.../iot/service/product/IotProductServiceImpl.java | 2 +-
8 files changed, 10 insertions(+), 19 deletions(-)
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java
index fe2f1de17..2a298e6a3 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java
@@ -1,11 +1,8 @@
package cn.iocoder.yudao.module.iot.controller.admin.product;
-import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductPageReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductRespVO;
import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSaveReqVO;
@@ -15,19 +12,14 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
-import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
-import java.io.IOException;
-import java.util.List;
-
-import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-@Tag(name = "管理后台 - IOT 产品")
+@Tag(name = "管理后台 - IoT 产品")
@RestController
@RequestMapping("/iot/product")
@Validated
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductPageReqVO.java
index afc3aafa0..3437f563f 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductPageReqVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductPageReqVO.java
@@ -6,8 +6,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
-// TODO @haohao:涉及到 iot 的拼写,要不都用 IoT,貌似更规范
-@Schema(description = "管理后台 - iot 产品分页 Request VO")
+@Schema(description = "管理后台 - IoT 产品分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductRespVO.java
index 066efca93..0958b3e84 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductRespVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductRespVO.java
@@ -7,13 +7,13 @@ import lombok.Data;
import java.time.LocalDateTime;
-@Schema(description = "管理后台 - iot 产品 Response VO")
+@Schema(description = "管理后台 - IoT 产品 Response VO")
@Data
@ExcelIgnoreUnannotated
public class IotProductRespVO {
- @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26087")
- @ExcelProperty("产品ID")
+ @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26087")
+ @ExcelProperty("产品编号")
private Long id;
@Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java
index ad01bcd03..254b6b9da 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java
@@ -7,7 +7,7 @@ import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
-@Schema(description = "管理后台 - iot 产品新增/修改 Request VO")
+@Schema(description = "管理后台 - IoT 产品新增/修改 Request VO")
@Data
public class IotProductSaveReqVO {
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java
index 1fa22c7d1..eef466eda 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java
@@ -7,7 +7,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
/**
- * iot 产品 DO
+ * IoT 产品 DO
*
* @author ahh
*/
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java
index 111ed4969..694d7c007 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java
@@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import org.apache.ibatis.annotations.Mapper;
/**
- * iot 产品 Mapper
+ * IoT 产品 Mapper
*
* @author ahh
*/
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java
index 14f408030..9677701f1 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java
@@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import jakarta.validation.Valid;
/**
- * IOT 产品 Service 接口
+ * IoT 产品 Service 接口
*
* @author ahh
*/
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java
index 65686f533..844e074d9 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java
@@ -20,7 +20,7 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_NOT_E
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_STATUS_NOT_DELETE;
/**
- * IOT 产品 Service 实现类
+ * IoT 产品 Service 实现类
*
* @author ahh
*/
From 18e789d4fb988dd4014a65fb4bda5ea90aa8307e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com>
Date: Wed, 11 Sep 2024 23:00:33 +0800
Subject: [PATCH 12/31] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=E5=A2=9E?=
=?UTF-8?q?=E5=8A=A0=20IOT=20=E7=89=A9=E6=A8=A1=E5=9E=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../module/iot/enums/ErrorCodeConstants.java | 5 +-
.../IotThinkModelFunctionController.http | 96 +++++++++++++++++++
.../IotThinkModelFunctionController.java | 63 ++++++++++++
.../vo/IotThingModelProperty.java | 90 +++++++++++++++++
.../vo/IotThinkModelFunctionRespVO.java | 38 ++++++++
.../vo/IotThinkModelFunctionSaveReqVO.java | 26 +++++
.../IotThinkModelFunctionDO.java | 44 +++++++++
.../IotThinkModelFunctionMapper.java | 25 +++++
.../product/IotProductServiceImpl.java | 5 +-
.../IotThinkModelFunctionService.java | 43 +++++++++
.../IotThinkModelFunctionServiceImpl.java | 74 ++++++++++++++
.../IotThinkModelFunctionMapper.xml | 12 +++
.../IotThinkModelFunctionServiceImplTest.java | 71 ++++++++++++++
13 files changed, 588 insertions(+), 4 deletions(-)
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/thinkmodelfunction/IotThinkModelFunctionMapper.xml
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImplTest.java
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
index 3fd09ce8e..19ee8972d 100644
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
+++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
@@ -9,8 +9,11 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
*/
public interface ErrorCodeConstants {
- // ========== 产品相关 1-050-001-000 ============
+ // ========== IoT 产品相关 1-050-001-000 ============
ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_050_001_000, "产品不存在");
ErrorCode PRODUCT_IDENTIFICATION_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在");
ErrorCode PRODUCT_STATUS_NOT_DELETE = new ErrorCode(1_050_001_002, "产品状是发布状态,不允许删除");
+
+ // ========== IoT 产品物模型 1-050-002-000 ============
+ ErrorCode THINK_MODEL_FUNCTION_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在");
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
new file mode 100644
index 000000000..bc0229bfb
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
@@ -0,0 +1,96 @@
+### 请求 /iot/think-model-function/create 接口 => 成功
+POST {{baseUrl}}/iot/think-model-function/create
+Content-Type: application/json
+tenant-id: {{adminTenentId}}
+Authorization: Bearer {{token}}
+
+{
+ "productKey": "123456",
+ "properties": [
+ {
+ "identifier": "CurrentTemperature",
+ "name": "当前温度",
+ "accessMode": "r",
+ "required": true,
+ "dataType": {
+ "type": "float",
+ "specs": {
+ "min": "-40",
+ "max": "120",
+ "unit": "°C",
+ "unitName": "摄氏度",
+ "step": "0.1"
+ }
+ }
+ },
+ {
+ "identifier": "CurrentHumidity",
+ "name": "当前湿度",
+ "accessMode": "r",
+ "required": true,
+ "dataType": {
+ "type": "float",
+ "specs": {
+ "min": "0",
+ "max": "100",
+ "unit": "%",
+ "unitName": "百分比",
+ "step": "0.1"
+ }
+ }
+ }
+ ],
+ "services": "{}",
+ "events": "{}"
+}
+
+### 请求 /iot/think-model-function/update 接口 => 成功
+PUT {{baseUrl}}/iot/think-model-function/update
+Content-Type: application/json
+tenant-id: {{adminTenentId}}
+Authorization: Bearer {{token}}
+
+{
+ "productKey": "123456",
+ "properties": [
+ {
+ "identifier": "CurrentTemperature",
+ "name": "当前温度",
+ "accessMode": "r",
+ "required": true,
+ "dataType": {
+ "type": "float",
+ "specs": {
+ "min": "-40",
+ "max": "130",
+ "unit": "°C",
+ "unitName": "摄氏度",
+ "step": "0.1"
+ }
+ }
+ },
+ {
+ "identifier": "CurrentHumidity",
+ "name": "当前湿度",
+ "accessMode": "r",
+ "required": true,
+ "dataType": {
+ "type": "float",
+ "specs": {
+ "min": "0",
+ "max": "100",
+ "unit": "%",
+ "unitName": "百分比",
+ "step": "0.1"
+ }
+ }
+ }
+ ],
+ "services": "{}",
+ "events": "{}"
+}
+
+### 请求 /iot/think-model-function/get 接口 => 成功
+GET {{baseUrl}}/iot/think-model-function/get?productKey=123456
+tenant-id: {{adminTenentId}}
+Authorization: Bearer {{token}}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java
new file mode 100644
index 000000000..cebaca4f5
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java
@@ -0,0 +1,63 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction;
+
+import org.springframework.web.bind.annotation.*;
+import jakarta.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import jakarta.validation.*;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.*;
+import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
+import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService;
+
+@Tag(name = "管理后台 - IoT 产品物模型")
+@RestController
+@RequestMapping("/iot/think-model-function")
+@Validated
+public class IotThinkModelFunctionController {
+
+ @Resource
+ private IotThinkModelFunctionService thinkModelFunctionService;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建IoT 产品物模型")
+ @PreAuthorize("@ss.hasPermission('iot:think-model-function:create')")
+ public CommonResult createThinkModelFunction(@Valid @RequestBody IotThinkModelFunctionSaveReqVO createReqVO) {
+ return success(thinkModelFunctionService.createThinkModelFunction(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新IoT 产品物模型")
+ @PreAuthorize("@ss.hasPermission('iot:think-model-function:update')")
+ public CommonResult updateThinkModelFunction(@Valid @RequestBody IotThinkModelFunctionSaveReqVO updateReqVO) {
+ thinkModelFunctionService.updateThinkModelFunctionByProductKey(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除IoT 产品物模型")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('iot:think-model-function:delete')")
+ public CommonResult deleteThinkModelFunction(@RequestParam("id") Long id) {
+ thinkModelFunctionService.deleteThinkModelFunction(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得IoT 产品物模型")
+ @Parameter(name = "productKey", description = "产品Key", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')")
+ public CommonResult getThinkModelFunctionByProductKey(@RequestParam("productKey") String productKey) {
+ IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionService.getThinkModelFunctionByProductKey(productKey);
+ return success(BeanUtils.toBean(thinkModelFunction, IotThinkModelFunctionRespVO.class));
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java
new file mode 100644
index 000000000..0187ae514
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java
@@ -0,0 +1,90 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "管理后台 - IoT 产品物模型属性")
+@Data
+public class IotThingModelProperty {
+
+ @Schema(description = "属性标识符")
+ private String identifier;
+
+ @Schema(description = "属性名称")
+ private String name;
+
+ @Schema(description = "访问模式 (r/rw)")
+ private String accessMode;
+
+ @Schema(description = "是否必需")
+ private boolean required;
+
+ @Schema(description = "数据类型")
+ private DataType dataType;
+
+ @Schema(description = "数据类型")
+ @Data
+ public static class DataType {
+
+ @Schema(description = "数据类型(float, double, struct, enum等)")
+ private String type;
+
+ @Schema(description = "单一类型的规格(适用于float, double等)")
+ private Specs specs;
+
+ @Schema(description = "结构体字段(适用于struct类型)")
+ private List structSpecs;
+
+ @Schema(description = "规格")
+ @Data
+ public static class Specs {
+
+ @Schema(description = "最小值")
+ private String min;
+
+ @Schema(description = "最大值")
+ private String max;
+
+ @Schema(description = "单位符号")
+ private String unit;
+
+ @Schema(description = "单位名称")
+ private String unitName;
+
+ @Schema(description = "步进值")
+ private String step;
+ }
+
+ @Schema(description = "结构体字段")
+ @Data
+ public static class StructField {
+
+ @Schema(description = "字段标识符")
+ private String identifier;
+
+ @Schema(description = "字段名称")
+ private String name;
+
+ @Schema(description = "字段的数据类型")
+ private DataType dataType;
+ }
+ }
+
+ @Schema(description = "枚举规格")
+ @Data
+ public static class EnumSpecs {
+
+ @Schema(description = "枚举值")
+ private int value;
+
+ @Schema(description = "枚举名称")
+ private String name;
+
+ public EnumSpecs(int value, String name) {
+ this.value = value;
+ this.name = name;
+ }
+ }
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java
new file mode 100644
index 000000000..74f7bfb6f
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java
@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - IoT 产品物模型 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class IotThinkModelFunctionRespVO {
+
+ @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "21816")
+ @ExcelProperty("产品ID")
+ private Long id;
+
+ @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("产品标识")
+ private String productKey;
+
+ @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("属性列表")
+ private String properties;
+
+ @Schema(description = "服务列表")
+ @ExcelProperty("服务列表")
+ private String services;
+
+ @Schema(description = "事件列表")
+ @ExcelProperty("事件列表")
+ private String events;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("创建时间")
+ private LocalDateTime createTime;
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java
new file mode 100644
index 000000000..200e7682c
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java
@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import jakarta.validation.constraints.*;
+
+@Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO")
+@Data
+public class IotThinkModelFunctionSaveReqVO {
+
+ @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotEmpty(message = "产品标识不能为空")
+ private String productKey;
+
+ @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotEmpty(message = "属性列表不能为空")
+ private List properties;
+
+ @Schema(description = "服务列表")
+ private String services;
+
+ @Schema(description = "事件列表")
+ private String events;
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java
new file mode 100644
index 000000000..7d9ea4589
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java
@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction;
+
+import lombok.*;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * IoT 产品物模型 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("iot_think_model_function")
+@KeySequence("iot_think_model_function_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class IotThinkModelFunctionDO extends BaseDO {
+
+ /**
+ * 产品ID
+ */
+ @TableId
+ private Long id;
+ /**
+ * 产品标识
+ */
+ private String productKey;
+ /**
+ * 属性列表
+ */
+ private String properties;
+ /**
+ * 服务列表
+ */
+ private String services;
+ /**
+ * 事件列表
+ */
+ private String events;
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
new file mode 100644
index 000000000..5475a723b
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction;
+
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * IoT 产品物模型 Mapper
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface IotThinkModelFunctionMapper extends BaseMapperX {
+
+ default IotThinkModelFunctionDO selectByProductKey(String productKey) {
+ return selectOne(new LambdaQueryWrapperX().eq(IotThinkModelFunctionDO::getProductKey, productKey));
+ }
+
+ default int updateByProductKey(IotThinkModelFunctionDO thinkModelFunction) {
+ return update(thinkModelFunction, new LambdaQueryWrapperX()
+ .eq(IotThinkModelFunctionDO::getProductKey, thinkModelFunction.getProductKey())
+ );
+ }
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java
index 844e074d9..96975c27f 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java
@@ -16,8 +16,7 @@ import java.util.Objects;
import java.util.UUID;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS;
-import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_STATUS_NOT_DELETE;
+import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
/**
* IoT 产品 Service 实现类
@@ -54,7 +53,7 @@ public class IotProductServiceImpl implements IotProductService {
}
// 2. 校验唯一性
if (productMapper.selectByProductKey(productKey) != null) {
- throw exception(PRODUCT_NOT_EXISTS);
+ throw exception(PRODUCT_IDENTIFICATION_EXISTS);
}
createReqVO.setProductKey(productKey);
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java
new file mode 100644
index 000000000..a52142810
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java
@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.iot.service.thinkmodelfunction;
+
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
+import jakarta.validation.Valid;
+
+/**
+ * IoT 产品物模型 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface IotThinkModelFunctionService {
+
+ /**
+ * 创建IoT 产品物模型
+ *
+ * @param createReqVO 创建信息
+ * @return 编号
+ */
+ Long createThinkModelFunction(@Valid IotThinkModelFunctionSaveReqVO createReqVO);
+
+ /**
+ * 删除IoT 产品物模型
+ *
+ * @param id 编号
+ */
+ void deleteThinkModelFunction(Long id);
+
+ /**
+ * 获得IoT 产品物模型
+ *
+ * @param productKey 产品Key
+ * @return IoT 产品物模型
+ */
+ IotThinkModelFunctionDO getThinkModelFunctionByProductKey(String productKey);
+
+ /**
+ * 更新IoT 产品物模型
+ *
+ * @param updateReqVO 更新信息
+ */
+ void updateThinkModelFunctionByProductKey(@Valid IotThinkModelFunctionSaveReqVO updateReqVO);
+}
\ 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/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
new file mode 100644
index 000000000..1f1355dd3
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
@@ -0,0 +1,74 @@
+package cn.iocoder.yudao.module.iot.service.thinkmodelfunction;
+
+import cn.hutool.json.JSONUtil;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
+import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS;
+
+/**
+ * IoT 产品物模型 Service 实现类
+ *
+ * @author 芋道源码
+ */
+@Service
+@Validated
+public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionService {
+
+ @Resource
+ private IotThinkModelFunctionMapper thinkModelFunctionMapper;
+
+ @Override
+ public Long createThinkModelFunction(IotThinkModelFunctionSaveReqVO createReqVO) {
+ // 插入
+ IotThinkModelFunctionDO thinkModelFunction = BeanUtils.toBean(createReqVO, IotThinkModelFunctionDO.class);
+ // properties 字段,需要转换成 JSON
+ thinkModelFunction.setProperties(JSONUtil.toJsonStr(createReqVO.getProperties()));
+ thinkModelFunctionMapper.insert(thinkModelFunction);
+ // 返回
+ return thinkModelFunction.getId();
+ }
+
+ @Override
+ public void deleteThinkModelFunction(Long id) {
+ // 校验存在
+ validateThinkModelFunctionExists(id);
+ // 删除
+ thinkModelFunctionMapper.deleteById(id);
+ }
+
+ private void validateThinkModelFunctionExists(Long id) {
+ if (thinkModelFunctionMapper.selectById(id) == null) {
+ throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS);
+ }
+ }
+
+ private void validateThinkModelFunctionExistsByProductKey(String productKey) {
+ if (thinkModelFunctionMapper.selectByProductKey(productKey) == null) {
+ throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS);
+ }
+ }
+
+ @Override
+ public IotThinkModelFunctionDO getThinkModelFunctionByProductKey(String productKey) {
+ return thinkModelFunctionMapper.selectByProductKey(productKey);
+ }
+
+ @Override
+ public void updateThinkModelFunctionByProductKey(IotThinkModelFunctionSaveReqVO updateReqVO) {
+ // 校验存在
+ validateThinkModelFunctionExistsByProductKey(updateReqVO.getProductKey());
+ // 更新
+ IotThinkModelFunctionDO thinkModelFunction = BeanUtils.toBean(updateReqVO, IotThinkModelFunctionDO.class);
+ // properties 字段,需要转换成 JSON
+ thinkModelFunction.setProperties(JSONUtil.toJsonStr(updateReqVO.getProperties()));
+ thinkModelFunctionMapper.updateByProductKey(thinkModelFunction);
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/thinkmodelfunction/IotThinkModelFunctionMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/thinkmodelfunction/IotThinkModelFunctionMapper.xml
new file mode 100644
index 000000000..525a32bd6
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/thinkmodelfunction/IotThinkModelFunctionMapper.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImplTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImplTest.java
new file mode 100644
index 000000000..762f6021b
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImplTest.java
@@ -0,0 +1,71 @@
+package cn.iocoder.yudao.module.iot.service.thinkmodelfunction;
+
+import org.junit.jupiter.api.Test;
+
+import jakarta.annotation.Resource;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.*;
+import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
+import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper;
+
+import org.springframework.context.annotation.Import;
+
+import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * {@link IotThinkModelFunctionServiceImpl} 的单元测试类
+ *
+ * @author 芋道源码
+ */
+@Import(IotThinkModelFunctionServiceImpl.class)
+public class IotThinkModelFunctionServiceImplTest extends BaseDbUnitTest {
+
+ @Resource
+ private IotThinkModelFunctionServiceImpl thinkModelFunctionService;
+
+ @Resource
+ private IotThinkModelFunctionMapper thinkModelFunctionMapper;
+
+ @Test
+ public void testCreateThinkModelFunction_success() {
+ // 准备参数
+ IotThinkModelFunctionSaveReqVO createReqVO = randomPojo(IotThinkModelFunctionSaveReqVO.class);
+
+ // 调用
+ Long thinkModelFunctionId = thinkModelFunctionService.createThinkModelFunction(createReqVO);
+ // 断言
+ assertNotNull(thinkModelFunctionId);
+ // 校验记录的属性是否正确
+ IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionMapper.selectById(thinkModelFunctionId);
+ assertPojoEquals(createReqVO, thinkModelFunction, "id");
+ }
+
+ @Test
+ public void testDeleteThinkModelFunction_success() {
+ // mock 数据
+ IotThinkModelFunctionDO dbThinkModelFunction = randomPojo(IotThinkModelFunctionDO.class);
+ thinkModelFunctionMapper.insert(dbThinkModelFunction);// @Sql: 先插入出一条存在的数据
+ // 准备参数
+ Long id = dbThinkModelFunction.getId();
+
+ // 调用
+ thinkModelFunctionService.deleteThinkModelFunction(id);
+ // 校验数据不存在了
+ assertNull(thinkModelFunctionMapper.selectById(id));
+ }
+
+ @Test
+ public void testDeleteThinkModelFunction_notExists() {
+ // 准备参数
+ Long id = randomLongId();
+
+ // 调用, 并断言异常
+ assertServiceException(() -> thinkModelFunctionService.deleteThinkModelFunction(id), THINK_MODEL_FUNCTION_NOT_EXISTS);
+ }
+
+}
\ No newline at end of file
From 9e77692414dc805be24c8ee12d5ccc3c05d1bb23 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com>
Date: Fri, 13 Sep 2024 22:30:19 +0800
Subject: [PATCH 13/31] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9A=E4=BC=98?=
=?UTF-8?q?=E5=8C=96=20IOT=20=E7=89=A9=E6=A8=A1=E5=9E=8B=20=E4=BF=AE?=
=?UTF-8?q?=E6=94=B9=E5=92=8C=E6=9F=A5=E8=AF=A2=E6=8E=A5=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../module/iot/enums/ErrorCodeConstants.java | 1 +
.../IotThinkModelFunctionController.http | 7 ++-
.../IotThinkModelFunctionController.java | 47 +++++++++------
.../vo/IotThinkModelFunctionRespVO.java | 8 ++-
.../vo/IotThinkModelFunctionSaveReqVO.java | 7 +++
.../IotThinkModelFunctionConvert.java | 51 ++++++++++++++++
.../IotThinkModelFunctionDO.java | 15 ++++-
.../IotThinkModelFunctionMapper.java | 7 +--
.../IotThinkModelFunctionService.java | 12 +++-
.../IotThinkModelFunctionServiceImpl.java | 60 +++++++++++--------
10 files changed, 159 insertions(+), 56 deletions(-)
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
index 19ee8972d..d26e5f2ec 100644
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
+++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
@@ -16,4 +16,5 @@ public interface ErrorCodeConstants {
// ========== IoT 产品物模型 1-050-002-000 ============
ErrorCode THINK_MODEL_FUNCTION_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在");
+ ErrorCode THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY = new ErrorCode(1_050_002_001, "ProductKey 对应的产品物模型已存在");
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
index bc0229bfb..b29ae8ddf 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
@@ -5,6 +5,7 @@ tenant-id: {{adminTenentId}}
Authorization: Bearer {{token}}
{
+ "productId": 1,
"productKey": "123456",
"properties": [
{
@@ -51,6 +52,8 @@ tenant-id: {{adminTenentId}}
Authorization: Bearer {{token}}
{
+ "id": 1,
+ "productId": 1,
"productKey": "123456",
"properties": [
{
@@ -90,7 +93,7 @@ Authorization: Bearer {{token}}
"events": "{}"
}
-### 请求 /iot/think-model-function/get 接口 => 成功
-GET {{baseUrl}}/iot/think-model-function/get?productKey=123456
+### 请求 /iot/think-model-function/get-by-product-key 接口 => 成功
+GET {{baseUrl}}/iot/think-model-function/get-by-product-key?productKey=123456
tenant-id: {{adminTenentId}}
Authorization: Bearer {{token}}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java
index cebaca4f5..a0051d9eb 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java
@@ -1,22 +1,21 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction;
-import org.springframework.web.bind.annotation.*;
-import jakarta.annotation.Resource;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.security.access.prepost.PreAuthorize;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.Operation;
-
-import jakarta.validation.*;
-
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-
-import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.*;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
+import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert;
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - IoT 产品物模型")
@RestController
@@ -38,7 +37,7 @@ public class IotThinkModelFunctionController {
@Operation(summary = "更新IoT 产品物模型")
@PreAuthorize("@ss.hasPermission('iot:think-model-function:update')")
public CommonResult updateThinkModelFunction(@Valid @RequestBody IotThinkModelFunctionSaveReqVO updateReqVO) {
- thinkModelFunctionService.updateThinkModelFunctionByProductKey(updateReqVO);
+ thinkModelFunctionService.updateThinkModelFunction(updateReqVO);
return success(true);
}
@@ -51,13 +50,23 @@ public class IotThinkModelFunctionController {
return success(true);
}
- @GetMapping("/get")
+ @GetMapping("/get-by-product-key")
@Operation(summary = "获得IoT 产品物模型")
@Parameter(name = "productKey", description = "产品Key", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('iot:think-model-function:query')")
- public CommonResult getThinkModelFunctionByProductKey(@RequestParam("productKey") String productKey) {
+ public CommonResult getThinkModelFunctionByProductKey(@RequestParam("productKey") String productKey) {
IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionService.getThinkModelFunctionByProductKey(productKey);
- return success(BeanUtils.toBean(thinkModelFunction, IotThinkModelFunctionRespVO.class));
+ IotThinkModelFunctionRespVO respVO = IotThinkModelFunctionConvert.INSTANCE.convert(thinkModelFunction);
+ return success(respVO);
}
-}
\ No newline at end of file
+ @GetMapping("/get-by-product-id")
+ @Operation(summary = "获得IoT 产品物模型")
+ @Parameter(name = "productId", description = "产品ID", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')")
+ public CommonResult getThinkModelFunctionByProductId(@RequestParam("productId") Long productId) {
+ IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionService.getThinkModelFunctionByProductId(productId);
+ IotThinkModelFunctionRespVO respVO = IotThinkModelFunctionConvert.INSTANCE.convert(thinkModelFunction);
+ return success(respVO);
+ }
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java
index 74f7bfb6f..5d525e5b5 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java
@@ -1,10 +1,12 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.*;
+import lombok.Data;
import java.time.LocalDateTime;
-import com.alibaba.excel.annotation.*;
+import java.util.List;
@Schema(description = "管理后台 - IoT 产品物模型 Response VO")
@Data
@@ -21,7 +23,7 @@ public class IotThinkModelFunctionRespVO {
@Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("属性列表")
- private String properties;
+ private List properties;
@Schema(description = "服务列表")
@ExcelProperty("服务列表")
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java
index 200e7682c..705846210 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java
@@ -9,6 +9,13 @@ import jakarta.validation.constraints.*;
@Data
public class IotThinkModelFunctionSaveReqVO {
+ @Schema(description = "编号", example = "1")
+ private Long id;
+
+ @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotNull(message = "产品ID不能为空")
+ private Long productId;
+
@Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "产品标识不能为空")
private String productKey;
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java
new file mode 100644
index 000000000..783ef658a
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java
@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.module.iot.convert.thinkmodelfunction;
+
+import cn.hutool.json.JSONUtil;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThingModelProperty;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
+import org.mapstruct.AfterMapping;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.MappingTarget;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+@Mapper
+public interface IotThinkModelFunctionConvert {
+
+ IotThinkModelFunctionConvert INSTANCE = Mappers.getMapper(IotThinkModelFunctionConvert.class);
+
+ // 将 SaveReqVO 转换为 DO
+ @Mapping(target = "properties", ignore = true)
+ IotThinkModelFunctionDO convert(IotThinkModelFunctionSaveReqVO bean);
+
+ // 将 DO 转换为 RespVO
+ @Mapping(target = "properties", ignore = true)
+ IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean);
+
+ // 处理 properties 字段的转换,从 VO 到 DO
+ @AfterMapping
+ default void convertPropertiesToDO(IotThinkModelFunctionSaveReqVO source, @MappingTarget IotThinkModelFunctionDO target) {
+ target.setProperties(JSONUtil.toJsonStr(source.getProperties()));
+ }
+
+ // 处理 properties 字段的转换,从 DO 到 VO
+ @AfterMapping
+ default void convertPropertiesToVO(IotThinkModelFunctionDO source, @MappingTarget IotThinkModelFunctionRespVO target) {
+ target.setProperties(JSONUtil.toList(source.getProperties(), IotThingModelProperty.class));
+ }
+
+ // 批量转换 DO 列表到 RespVO 列表
+ List convertList(List list);
+
+ // 批量转换处理 properties 字段
+ @AfterMapping
+ default void convertPropertiesListToVO(List sourceList, @MappingTarget List targetList) {
+ for (int i = 0; i < sourceList.size(); i++) {
+ convertPropertiesToVO(sourceList.get(i), targetList.get(i));
+ }
+ }
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java
index 7d9ea4589..564eefb2b 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java
@@ -1,8 +1,10 @@
package cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction;
-import lombok.*;
-import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
/**
* IoT 产品物模型 DO
@@ -24,18 +26,27 @@ public class IotThinkModelFunctionDO extends BaseDO {
*/
@TableId
private Long id;
+
+ /**
+ * 产品标识
+ */
+ private Long productId;
+
/**
* 产品标识
*/
private String productKey;
+
/**
* 属性列表
*/
private String properties;
+
/**
* 服务列表
*/
private String services;
+
/**
* 事件列表
*/
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
index 5475a723b..21ae1967a 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
@@ -17,9 +17,8 @@ public interface IotThinkModelFunctionMapper extends BaseMapperX().eq(IotThinkModelFunctionDO::getProductKey, productKey));
}
- default int updateByProductKey(IotThinkModelFunctionDO thinkModelFunction) {
- return update(thinkModelFunction, new LambdaQueryWrapperX()
- .eq(IotThinkModelFunctionDO::getProductKey, thinkModelFunction.getProductKey())
- );
+ default IotThinkModelFunctionDO selectByProductId(Long productId){
+ return selectOne(new LambdaQueryWrapperX().eq(IotThinkModelFunctionDO::getProductId, productId));
}
+
}
\ 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/thinkmodelfunction/IotThinkModelFunctionService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java
index a52142810..d24ce0031 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java
@@ -27,17 +27,25 @@ public interface IotThinkModelFunctionService {
void deleteThinkModelFunction(Long id);
/**
- * 获得IoT 产品物模型
+ * 获得IoT 产品物模型,通过产品Key
*
* @param productKey 产品Key
* @return IoT 产品物模型
*/
IotThinkModelFunctionDO getThinkModelFunctionByProductKey(String productKey);
+ /**
+ * 获得IoT 产品物模型,通过产品ID
+ *
+ * @param productId 产品ID
+ * @return IoT 产品物模型
+ */
+ IotThinkModelFunctionDO getThinkModelFunctionByProductId(Long productId);
+
/**
* 更新IoT 产品物模型
*
* @param updateReqVO 更新信息
*/
- void updateThinkModelFunctionByProductKey(@Valid IotThinkModelFunctionSaveReqVO updateReqVO);
+ void updateThinkModelFunction(@Valid IotThinkModelFunctionSaveReqVO updateReqVO);
}
\ 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/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
index 1f1355dd3..89c5f6b98 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
@@ -1,22 +1,20 @@
package cn.iocoder.yudao.module.iot.service.thinkmodelfunction;
-import cn.hutool.json.JSONUtil;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
+import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert;
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper;
import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS;
-/**
- * IoT 产品物模型 Service 实现类
- *
- * @author 芋道源码
- */
+@Slf4j
@Service
@Validated
public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionService {
@@ -26,17 +24,25 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
@Override
public Long createThinkModelFunction(IotThinkModelFunctionSaveReqVO createReqVO) {
+ log.info("创建物模型,参数:{}", createReqVO);
+ // 验证 ProductKey 对应的产品物模型是否已存在
+ validateThinkModelFunctionNotExistsByProductKey(createReqVO.getProductKey());
// 插入
- IotThinkModelFunctionDO thinkModelFunction = BeanUtils.toBean(createReqVO, IotThinkModelFunctionDO.class);
- // properties 字段,需要转换成 JSON
- thinkModelFunction.setProperties(JSONUtil.toJsonStr(createReqVO.getProperties()));
+ IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO);
thinkModelFunctionMapper.insert(thinkModelFunction);
// 返回
return thinkModelFunction.getId();
}
+ private void validateThinkModelFunctionNotExistsByProductKey(String productKey) {
+ if (thinkModelFunctionMapper.selectByProductKey(productKey) != null) {
+ throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY);
+ }
+ }
+
@Override
public void deleteThinkModelFunction(Long id) {
+ log.info("删除物模型,id:{}", id);
// 校验存在
validateThinkModelFunctionExists(id);
// 删除
@@ -49,26 +55,32 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
}
}
- private void validateThinkModelFunctionExistsByProductKey(String productKey) {
- if (thinkModelFunctionMapper.selectByProductKey(productKey) == null) {
- throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS);
- }
- }
-
@Override
public IotThinkModelFunctionDO getThinkModelFunctionByProductKey(String productKey) {
return thinkModelFunctionMapper.selectByProductKey(productKey);
}
@Override
- public void updateThinkModelFunctionByProductKey(IotThinkModelFunctionSaveReqVO updateReqVO) {
- // 校验存在
- validateThinkModelFunctionExistsByProductKey(updateReqVO.getProductKey());
- // 更新
- IotThinkModelFunctionDO thinkModelFunction = BeanUtils.toBean(updateReqVO, IotThinkModelFunctionDO.class);
- // properties 字段,需要转换成 JSON
- thinkModelFunction.setProperties(JSONUtil.toJsonStr(updateReqVO.getProperties()));
- thinkModelFunctionMapper.updateByProductKey(thinkModelFunction);
+ public IotThinkModelFunctionDO getThinkModelFunctionByProductId(Long productId) {
+ return thinkModelFunctionMapper.selectByProductId(productId);
}
+ @Override
+ public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) {
+ log.info("更新物模型,参数:{}", updateReqVO);
+ // 校验存在
+ validateThinkModelFunctionExists(updateReqVO.getId());
+ // 校验 productKey 是否重复
+ validateProductKeyUnique(updateReqVO.getId(), updateReqVO.getProductKey());
+ // 更新
+ IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO);
+ thinkModelFunctionMapper.updateById(thinkModelFunction);
+ }
+
+ private void validateProductKeyUnique(Long id, String productKey) {
+ IotThinkModelFunctionDO existingFunction = thinkModelFunctionMapper.selectByProductKey(productKey);
+ if (existingFunction != null && !existingFunction.getId().equals(id)) {
+ throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY);
+ }
+ }
}
\ No newline at end of file
From 1f8576f6432fe5201497d2c3704de809d7185307 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com>
Date: Sat, 14 Sep 2024 00:35:43 +0800
Subject: [PATCH 14/31] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9AIOT=20?=
=?UTF-8?q?=E6=A0=B9=E6=8D=AE=E5=B1=9E=E6=80=A7=E5=88=97=E8=A1=A8=EF=BC=8C?=
=?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90=E5=B1=9E=E6=80=A7=E4=B8=8A?=
=?UTF-8?q?=E6=8A=A5=E4=BA=8B=E4=BB=B6=E5=92=8C=E5=B1=9E=E6=80=A7=E8=AE=BE?=
=?UTF-8?q?=E7=BD=AE=E3=80=81=E8=8E=B7=E5=8F=96=E6=9C=8D=E5=8A=A1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../IotThinkModelFunctionController.http | 265 +++++++++++++++---
.../thingModel/ThingModelArgument.java | 12 +
.../thingModel/ThingModelArraySpecs.java | 9 +
.../thingModel/ThingModelArrayType.java | 11 +
.../thingModel/ThingModelBoolType.java | 10 +
.../thingModel/ThingModelDataType.java | 22 ++
.../thingModel/ThingModelDateType.java | 10 +
.../thingModel/ThingModelDoubleType.java | 18 ++
.../thingModel/ThingModelEnumType.java | 11 +
.../thingModel/ThingModelEvent.java | 14 +
.../thingModel/ThingModelFloatType.java | 18 ++
.../thingModel/ThingModelIntType.java | 18 ++
.../thingModel/ThingModelProperty.java | 13 +
.../thingModel/ThingModelService.java | 15 +
.../thingModel/ThingModelStructField.java | 11 +
.../thingModel/ThingModelStructType.java | 13 +
.../thingModel/ThingModelTextType.java | 15 +
.../vo/IotThingModelProperty.java | 90 ------
.../vo/IotThinkModelFunctionRespVO.java | 9 +-
.../vo/IotThinkModelFunctionSaveReqVO.java | 17 +-
.../IotThinkModelFunctionConvert.java | 60 ++--
.../IotThinkModelFunctionServiceImpl.java | 176 +++++++++++-
22 files changed, 664 insertions(+), 173 deletions(-)
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArgument.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArrayType.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelBoolType.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDataType.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDateType.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDoubleType.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEnumType.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelFloatType.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelIntType.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructField.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructType.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelTextType.java
delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
index b29ae8ddf..e31540710 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
@@ -5,46 +5,140 @@ tenant-id: {{adminTenentId}}
Authorization: Bearer {{token}}
{
- "productId": 1,
- "productKey": "123456",
+ "productId": 1002,
+ "productKey": "smart-sensor-002",
"properties": [
{
- "identifier": "CurrentTemperature",
- "name": "当前温度",
+ "identifier": "Temperature",
+ "name": "温度",
"accessMode": "r",
"required": true,
"dataType": {
"type": "float",
"specs": {
- "min": "-40",
- "max": "120",
- "unit": "°C",
- "unitName": "摄氏度",
- "step": "0.1"
+ "min": -40.0,
+ "max": 125.0,
+ "step": 0.1,
+ "unit": "℃"
}
- }
+ },
+ "description": "当前温度值"
},
{
- "identifier": "CurrentHumidity",
- "name": "当前湿度",
+ "identifier": "Humidity",
+ "name": "湿度",
"accessMode": "r",
"required": true,
"dataType": {
"type": "float",
"specs": {
- "min": "0",
- "max": "100",
- "unit": "%",
- "unitName": "百分比",
- "step": "0.1"
+ "min": 0.0,
+ "max": 100.0,
+ "step": 0.1,
+ "unit": "%"
}
- }
+ },
+ "description": "当前湿度值"
+ },
+ {
+ "identifier": "GeoLocation",
+ "name": "地理位置",
+ "accessMode": "r",
+ "required": false,
+ "dataType": {
+ "type": "struct",
+ "specs": [
+ {
+ "identifier": "Longitude",
+ "name": "经度",
+ "dataType": {
+ "type": "double",
+ "specs": {
+ "min": -180.0,
+ "max": 180.0,
+ "step": 0.000001,
+ "unit": "°"
+ }
+ },
+ "description": "设备所在位置的经度"
+ },
+ {
+ "identifier": "Latitude",
+ "name": "纬度",
+ "dataType": {
+ "type": "double",
+ "specs": {
+ "min": -90.0,
+ "max": 90.0,
+ "step": 0.000001,
+ "unit": "°"
+ }
+ },
+ "description": "设备所在位置的纬度"
+ }
+ ]
+ },
+ "description": "设备的地理位置信息"
}
],
- "services": "{}",
- "events": "{}"
+ "services": [
+ {
+ "identifier": "Reboot",
+ "name": "重启设备",
+ "callType": "async",
+ "inputData": [],
+ "description": "远程重启设备",
+ "method": "thing.service.reboot"
+ },
+ {
+ "identifier": "SetThreshold",
+ "name": "设置温度阈值",
+ "callType": "sync",
+ "inputData": [
+ {
+ "identifier": "Threshold",
+ "name": "阈值",
+ "dataType": {
+ "type": "float",
+ "specs": {
+ "min": -40.0,
+ "max": 125.0,
+ "step": 0.1,
+ "unit": "℃"
+ }
+ },
+ "description": "报警温度阈值"
+ }
+ ],
+ "description": "设置设备的温度报警阈值",
+ "method": "thing.service.setThreshold"
+ }
+ ],
+ "events": [
+ {
+ "identifier": "HighTemperatureAlert",
+ "name": "高温报警",
+ "type": "alert",
+ "outputData": [
+ {
+ "identifier": "CurrentTemperature",
+ "name": "当前温度",
+ "dataType": {
+ "type": "float",
+ "specs": {
+ "unit": "℃"
+ }
+ },
+ "description": "触发报警时的温度值"
+ }
+ ],
+ "description": "当温度超过阈值时触发高温报警事件",
+ "method": "thing.event.highTemperatureAlert"
+ }
+ ]
}
+
### 请求 /iot/think-model-function/update 接口 => 成功
PUT {{baseUrl}}/iot/think-model-function/update
Content-Type: application/json
@@ -53,46 +147,137 @@ Authorization: Bearer {{token}}
{
"id": 1,
- "productId": 1,
- "productKey": "123456",
+ "productId": 1001,
+ "productKey": "smart-sensor-001",
"properties": [
{
- "identifier": "CurrentTemperature",
- "name": "当前温度",
+ "identifier": "Temperature",
+ "name": "温度",
"accessMode": "r",
"required": true,
"dataType": {
"type": "float",
"specs": {
- "min": "-40",
- "max": "130",
- "unit": "°C",
- "unitName": "摄氏度",
- "step": "0.1"
+ "min": -40.0,
+ "max": 125.0,
+ "step": 0.1,
+ "unit": "℃"
}
- }
+ },
+ "description": "当前温度值"
},
{
- "identifier": "CurrentHumidity",
- "name": "当前湿度",
+ "identifier": "Humidity",
+ "name": "湿度",
"accessMode": "r",
"required": true,
"dataType": {
"type": "float",
"specs": {
- "min": "0",
- "max": "100",
- "unit": "%",
- "unitName": "百分比",
- "step": "0.1"
+ "min": 0.0,
+ "max": 100.0,
+ "step": 0.1,
+ "unit": "%"
}
- }
+ },
+ "description": "当前湿度值"
+ },
+ {
+ "identifier": "GeoLocation",
+ "name": "地理位置",
+ "accessMode": "r",
+ "required": false,
+ "dataType": {
+ "type": "struct",
+ "specs": [
+ {
+ "identifier": "Longitude",
+ "name": "经度",
+ "dataType": {
+ "type": "double",
+ "specs": {
+ "min": -180.0,
+ "max": 180.0,
+ "step": 0.000001,
+ "unit": "°"
+ }
+ },
+ "description": "设备所在位置的经度"
+ },
+ {
+ "identifier": "Latitude",
+ "name": "纬度",
+ "dataType": {
+ "type": "double",
+ "specs": {
+ "min": -90.0,
+ "max": 90.0,
+ "step": 0.000001,
+ "unit": "°"
+ }
+ },
+ "description": "设备所在位置的纬度"
+ }
+ ]
+ },
+ "description": "设备的地理位置信息"
}
],
- "services": "{}",
- "events": "{}"
+ "services": [
+ {
+ "identifier": "Reboot",
+ "name": "重启设备",
+ "callType": "async",
+ "inputData": [],
+ "description": "远程重启设备"
+ },
+ {
+ "identifier": "SetThreshold",
+ "name": "设置温度阈值",
+ "callType": "sync",
+ "inputData": [
+ {
+ "identifier": "Threshold",
+ "name": "阈值",
+ "dataType": {
+ "type": "float",
+ "specs": {
+ "min": -40.0,
+ "max": 125.0,
+ "step": 0.1,
+ "unit": "℃"
+ }
+ },
+ "description": "报警温度阈值"
+ }
+ ],
+ "description": "设置设备的温度报警阈值"
+ }
+ ],
+ "events": [
+ {
+ "identifier": "HighTemperatureAlert",
+ "name": "高温报警",
+ "type": "alert",
+ "outputData": [
+ {
+ "identifier": "CurrentTemperature",
+ "name": "当前温度",
+ "dataType": {
+ "type": "float",
+ "specs": {
+ "unit": "℃"
+ }
+ },
+ "description": "触发报警时的温度值"
+ }
+ ],
+ "description": "当温度超过阈值时触发高温报警事件"
+ }
+ ]
}
+
### 请求 /iot/think-model-function/get-by-product-key 接口 => 成功
GET {{baseUrl}}/iot/think-model-function/get-by-product-key?productKey=123456
tenant-id: {{adminTenentId}}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArgument.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArgument.java
new file mode 100644
index 000000000..909d63459
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArgument.java
@@ -0,0 +1,12 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+
+import lombok.Data;
+
+@Data
+public class ThingModelArgument {
+ private String identifier;
+ private String name;
+ private ThingModelDataType dataType;
+ private String direction; // 用于区分输入或输出参数,"input" 或 "output"
+ private String description;
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java
new file mode 100644
index 000000000..3ea23e8db
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java
@@ -0,0 +1,9 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+
+import lombok.Data;
+
+@Data
+public class ThingModelArraySpecs {
+ private int size; // 数组长度
+ private ThingModelDataType item; // 数组元素的类型
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArrayType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArrayType.java
new file mode 100644
index 000000000..114add210
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArrayType.java
@@ -0,0 +1,11 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ThingModelArrayType extends ThingModelDataType {
+ private ThingModelArraySpecs specs;
+}
+
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelBoolType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelBoolType.java
new file mode 100644
index 000000000..f7e7e456b
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelBoolType.java
@@ -0,0 +1,10 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ThingModelBoolType extends ThingModelDataType {
+ // Bool 类型一般不需要额外的 specs
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDataType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDataType.java
new file mode 100644
index 000000000..613cbd766
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDataType.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import lombok.Data;
+
+@Data
+@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true)
+@JsonSubTypes({
+ @JsonSubTypes.Type(value = ThingModelIntType.class, name = "int"),
+ @JsonSubTypes.Type(value = ThingModelFloatType.class, name = "float"),
+ @JsonSubTypes.Type(value = ThingModelDoubleType.class, name = "double"),
+ @JsonSubTypes.Type(value = ThingModelTextType.class, name = "text"),
+ @JsonSubTypes.Type(value = ThingModelDateType.class, name = "date"),
+ @JsonSubTypes.Type(value = ThingModelBoolType.class, name = "bool"),
+ @JsonSubTypes.Type(value = ThingModelEnumType.class, name = "enum"),
+ @JsonSubTypes.Type(value = ThingModelStructType.class, name = "struct"),
+ @JsonSubTypes.Type(value = ThingModelArrayType.class, name = "array")
+})
+public abstract class ThingModelDataType {
+ private String type;
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDateType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDateType.java
new file mode 100644
index 000000000..11cb3a729
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDateType.java
@@ -0,0 +1,10 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ThingModelDateType extends ThingModelDataType {
+ // Date 类型一般不需要额外的 specs
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDoubleType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDoubleType.java
new file mode 100644
index 000000000..d60302179
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDoubleType.java
@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ThingModelDoubleType extends ThingModelDataType {
+ private ThingModelDoubleSpecs specs;
+}
+
+@Data
+class ThingModelDoubleSpecs {
+ private Double min;
+ private Double max;
+ private Double step;
+ private String unit;
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEnumType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEnumType.java
new file mode 100644
index 000000000..f76962661
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEnumType.java
@@ -0,0 +1,11 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import java.util.Map;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ThingModelEnumType extends ThingModelDataType {
+ private Map specs; // 枚举值和描述的键值对
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java
new file mode 100644
index 000000000..857f688e9
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java
@@ -0,0 +1,14 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+
+import lombok.Data;
+import java.util.List;
+
+@Data
+public class ThingModelEvent {
+ private String identifier;
+ private String name;
+ private String type; // "info"、"alert"、"error"
+ private List outputData;
+ private String description;
+ private String method;
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelFloatType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelFloatType.java
new file mode 100644
index 000000000..c9d5516ad
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelFloatType.java
@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ThingModelFloatType extends ThingModelDataType {
+ private ThingModelFloatSpecs specs;
+}
+
+@Data
+class ThingModelFloatSpecs {
+ private Float min;
+ private Float max;
+ private Float step;
+ private String unit;
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelIntType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelIntType.java
new file mode 100644
index 000000000..d48f50e47
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelIntType.java
@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ThingModelIntType extends ThingModelDataType {
+ private ThingModelIntSpecs specs;
+}
+
+@Data
+class ThingModelIntSpecs {
+ private Integer min;
+ private Integer max;
+ private Integer step;
+ private String unit;
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java
new file mode 100644
index 000000000..f82198152
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java
@@ -0,0 +1,13 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+
+import lombok.Data;
+
+@Data
+public class ThingModelProperty {
+ private String identifier;
+ private String name;
+ private String accessMode; // "rw"、"r"、"w"
+ private boolean required;
+ private ThingModelDataType dataType;
+ private String description;
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java
new file mode 100644
index 000000000..521e9ab08
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java
@@ -0,0 +1,15 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+
+import lombok.Data;
+import java.util.List;
+
+@Data
+public class ThingModelService {
+ private String identifier;
+ private String name;
+ private String callType; // "sync"、"async"
+ private List inputData;
+ private List outputData;
+ private String description;
+ private String method;
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructField.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructField.java
new file mode 100644
index 000000000..449db55c2
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructField.java
@@ -0,0 +1,11 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+
+import lombok.Data;
+
+@Data
+public class ThingModelStructField {
+ private String identifier;
+ private String name;
+ private ThingModelDataType dataType;
+ private String description;
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructType.java
new file mode 100644
index 000000000..d3d35f16c
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructType.java
@@ -0,0 +1,13 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import java.util.List;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ThingModelStructType extends ThingModelDataType {
+ private List specs;
+}
+
+
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelTextType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelTextType.java
new file mode 100644
index 000000000..0f6ea2bcb
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelTextType.java
@@ -0,0 +1,15 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ThingModelTextType extends ThingModelDataType {
+ private ThingModelTextSpecs specs;
+}
+
+@Data
+class ThingModelTextSpecs {
+ private Integer length; // 最大长度
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java
deleted file mode 100644
index 0187ae514..000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.util.List;
-
-@Schema(description = "管理后台 - IoT 产品物模型属性")
-@Data
-public class IotThingModelProperty {
-
- @Schema(description = "属性标识符")
- private String identifier;
-
- @Schema(description = "属性名称")
- private String name;
-
- @Schema(description = "访问模式 (r/rw)")
- private String accessMode;
-
- @Schema(description = "是否必需")
- private boolean required;
-
- @Schema(description = "数据类型")
- private DataType dataType;
-
- @Schema(description = "数据类型")
- @Data
- public static class DataType {
-
- @Schema(description = "数据类型(float, double, struct, enum等)")
- private String type;
-
- @Schema(description = "单一类型的规格(适用于float, double等)")
- private Specs specs;
-
- @Schema(description = "结构体字段(适用于struct类型)")
- private List structSpecs;
-
- @Schema(description = "规格")
- @Data
- public static class Specs {
-
- @Schema(description = "最小值")
- private String min;
-
- @Schema(description = "最大值")
- private String max;
-
- @Schema(description = "单位符号")
- private String unit;
-
- @Schema(description = "单位名称")
- private String unitName;
-
- @Schema(description = "步进值")
- private String step;
- }
-
- @Schema(description = "结构体字段")
- @Data
- public static class StructField {
-
- @Schema(description = "字段标识符")
- private String identifier;
-
- @Schema(description = "字段名称")
- private String name;
-
- @Schema(description = "字段的数据类型")
- private DataType dataType;
- }
- }
-
- @Schema(description = "枚举规格")
- @Data
- public static class EnumSpecs {
-
- @Schema(description = "枚举值")
- private int value;
-
- @Schema(description = "枚举名称")
- private String name;
-
- public EnumSpecs(int value, String name) {
- this.value = value;
- this.name = name;
- }
- }
-}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java
index 5d525e5b5..42ac727a4 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java
@@ -1,5 +1,8 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -23,15 +26,15 @@ public class IotThinkModelFunctionRespVO {
@Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("属性列表")
- private List properties;
+ private List properties;
@Schema(description = "服务列表")
@ExcelProperty("服务列表")
- private String services;
+ private List services;
@Schema(description = "事件列表")
@ExcelProperty("事件列表")
- private String events;
+ private List events;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java
index 705846210..00132fa8b 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java
@@ -1,9 +1,14 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.*;
-import java.util.*;
-import jakarta.validation.constraints.*;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.List;
@Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO")
@Data
@@ -22,12 +27,12 @@ public class IotThinkModelFunctionSaveReqVO {
@Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "属性列表不能为空")
- private List properties;
+ private List properties;
@Schema(description = "服务列表")
- private String services;
+ private List services;
@Schema(description = "事件列表")
- private String events;
+ private List events;
}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java
index 783ef658a..41e0c583b 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java
@@ -1,16 +1,17 @@
package cn.iocoder.yudao.module.iot.convert.thinkmodelfunction;
import cn.hutool.json.JSONUtil;
-import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThingModelProperty;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
-import org.mapstruct.AfterMapping;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
-import org.mapstruct.MappingTarget;
import org.mapstruct.factory.Mappers;
+import java.util.ArrayList;
import java.util.List;
@Mapper
@@ -18,34 +19,43 @@ public interface IotThinkModelFunctionConvert {
IotThinkModelFunctionConvert INSTANCE = Mappers.getMapper(IotThinkModelFunctionConvert.class);
- // 将 SaveReqVO 转换为 DO
- @Mapping(target = "properties", ignore = true)
+ // 将 SaveReqVO 转换为 DO 对象,处理 properties, services, events 字段
+ @Mapping(target = "properties", expression = "java(convertPropertiesToJson(bean.getProperties()))")
+ @Mapping(target = "services", expression = "java(convertServicesToJson(bean.getServices()))")
+ @Mapping(target = "events", expression = "java(convertEventsToJson(bean.getEvents()))")
IotThinkModelFunctionDO convert(IotThinkModelFunctionSaveReqVO bean);
- // 将 DO 转换为 RespVO
- @Mapping(target = "properties", ignore = true)
- IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean);
-
- // 处理 properties 字段的转换,从 VO 到 DO
- @AfterMapping
- default void convertPropertiesToDO(IotThinkModelFunctionSaveReqVO source, @MappingTarget IotThinkModelFunctionDO target) {
- target.setProperties(JSONUtil.toJsonStr(source.getProperties()));
+ default String convertPropertiesToJson(List properties) {
+ return properties != null ? JSONUtil.toJsonStr(properties) : "[]";
}
- // 处理 properties 字段的转换,从 DO 到 VO
- @AfterMapping
- default void convertPropertiesToVO(IotThinkModelFunctionDO source, @MappingTarget IotThinkModelFunctionRespVO target) {
- target.setProperties(JSONUtil.toList(source.getProperties(), IotThingModelProperty.class));
+ default String convertServicesToJson(List services) {
+ return services != null ? JSONUtil.toJsonStr(services) : "[]";
+ }
+
+ default String convertEventsToJson(List events) {
+ return events != null ? JSONUtil.toJsonStr(events) : "[]";
+ }
+
+ // 将 DO 转换为 RespVO 对象,处理 properties, services, events 字段
+ @Mapping(target = "properties", expression = "java(convertJsonToProperties(bean.getProperties()))")
+ @Mapping(target = "services", expression = "java(convertJsonToServices(bean.getServices()))")
+ @Mapping(target = "events", expression = "java(convertJsonToEvents(bean.getEvents()))")
+ IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean);
+
+ default List convertJsonToProperties(String propertiesJson) {
+ return propertiesJson != null ? JSONUtil.toList(propertiesJson, ThingModelProperty.class) : new ArrayList<>();
+ }
+
+ default List convertJsonToServices(String servicesJson) {
+ return servicesJson != null ? JSONUtil.toList(servicesJson, ThingModelService.class) : new ArrayList<>();
+ }
+
+ default List convertJsonToEvents(String eventsJson) {
+ return eventsJson != null ? JSONUtil.toList(eventsJson, ThingModelEvent.class) : new ArrayList<>();
}
// 批量转换 DO 列表到 RespVO 列表
List convertList(List list);
-
- // 批量转换处理 properties 字段
- @AfterMapping
- default void convertPropertiesListToVO(List sourceList, @MappingTarget List targetList) {
- for (int i = 0; i < sourceList.size(); i++) {
- convertPropertiesToVO(sourceList.get(i), targetList.get(i));
- }
- }
}
+
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
index 89c5f6b98..66fc01779 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.iot.service.thinkmodelfunction;
-import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.hutool.json.JSONUtil;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.*;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert;
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
@@ -10,6 +11,10 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS;
@@ -27,10 +32,13 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
log.info("创建物模型,参数:{}", createReqVO);
// 验证 ProductKey 对应的产品物模型是否已存在
validateThinkModelFunctionNotExistsByProductKey(createReqVO.getProductKey());
- // 插入
+ // 转换请求对象为数据对象
IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO);
+ // 自动生成属性上报事件和属性设置、获取服务
+ generateDefaultEventsAndServices(createReqVO, thinkModelFunction);
+ // 插入数据库
thinkModelFunctionMapper.insert(thinkModelFunction);
- // 返回
+ // 返回生成的 ID
return thinkModelFunction.getId();
}
@@ -43,9 +51,9 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
@Override
public void deleteThinkModelFunction(Long id) {
log.info("删除物模型,id:{}", id);
- // 校验存在
+ // 校验物模型是否存在
validateThinkModelFunctionExists(id);
- // 删除
+ // 删除物模型
thinkModelFunctionMapper.deleteById(id);
}
@@ -68,12 +76,15 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
@Override
public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) {
log.info("更新物模型,参数:{}", updateReqVO);
- // 校验存在
+ // 校验物模型是否存在
validateThinkModelFunctionExists(updateReqVO.getId());
- // 校验 productKey 是否重复
+ // 校验 ProductKey 是否唯一
validateProductKeyUnique(updateReqVO.getId(), updateReqVO.getProductKey());
- // 更新
+ // 转换请求对象为数据对象
IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO);
+ // 自动生成或更新属性上报事件和属性设置、获取服务
+ generateDefaultEventsAndServices(updateReqVO, thinkModelFunction);
+ // 更新数据库
thinkModelFunctionMapper.updateById(thinkModelFunction);
}
@@ -83,4 +94,151 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY);
}
}
-}
\ No newline at end of file
+
+ /**
+ * @ TODO 还要再优化
+ * 根据属性列表,自动生成属性上报事件和属性设置、获取服务
+ */
+ private void generateDefaultEventsAndServices(IotThinkModelFunctionSaveReqVO reqVO, IotThinkModelFunctionDO thinkModelFunction) {
+ // 获取属性列表
+ List properties = reqVO.getProperties();
+ if (properties == null) {
+ properties = new ArrayList<>();
+ }
+
+ // 生成属性上报事件
+ List events = reqVO.getEvents() != null ? new ArrayList<>(reqVO.getEvents()) : new ArrayList<>();
+ ThingModelEvent propertyPostEvent = generatePropertyPostEvent(properties);
+ events.add(propertyPostEvent);
+
+ // 生成属性设置和获取服务
+ List services = reqVO.getServices() != null ? new ArrayList<>(reqVO.getServices()) : new ArrayList<>();
+ ThingModelService propertySetService = generatePropertySetService(properties);
+ if (propertySetService != null) {
+ services.add(propertySetService);
+ }
+ ThingModelService propertyGetService = generatePropertyGetService(properties);
+ if (propertyGetService != null) {
+ services.add(propertyGetService);
+ }
+
+ // 更新 thinkModelFunction 对象的 events 和 services 字段
+ thinkModelFunction.setEvents(JSONUtil.toJsonStr(events));
+ thinkModelFunction.setServices(JSONUtil.toJsonStr(services));
+ }
+
+ /**
+ * 生成属性上报事件
+ */
+ private ThingModelEvent generatePropertyPostEvent(List properties) {
+ ThingModelEvent event = new ThingModelEvent();
+ event.setIdentifier("post");
+ event.setName("属性上报");
+ event.setType("info");
+ event.setDescription("属性上报事件");
+ event.setMethod("thing.event.property.post");
+
+ // 将属性列表转换为事件的输出参数
+ List outputData = new ArrayList<>();
+ for (ThingModelProperty property : properties) {
+ ThingModelArgument arg = new ThingModelArgument();
+ arg.setIdentifier(property.getIdentifier());
+ arg.setName(property.getName());
+ arg.setDataType(property.getDataType());
+ arg.setDescription(property.getDescription());
+ arg.setDirection("output"); // 设置为输出参数
+ outputData.add(arg);
+ }
+ event.setOutputData(outputData);
+
+ return event;
+ }
+
+ /**
+ * 生成属性设置服务
+ */
+ private ThingModelService generatePropertySetService(List properties) {
+ List inputData = new ArrayList<>();
+ for (ThingModelProperty property : properties) {
+ if ("w".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) {
+ ThingModelArgument arg = new ThingModelArgument();
+ arg.setIdentifier(property.getIdentifier());
+ arg.setName(property.getName());
+ arg.setDataType(property.getDataType());
+ arg.setDescription(property.getDescription());
+ arg.setDirection("input"); // 设置为输入参数
+ inputData.add(arg);
+ }
+ }
+ if (inputData.isEmpty()) {
+ // 如果没有可写属性,不生成属性设置服务
+ return null;
+ }
+
+ ThingModelService service = new ThingModelService();
+ service.setIdentifier("set");
+ service.setName("属性设置");
+ service.setCallType("async");
+ service.setDescription("属性设置服务");
+ service.setMethod("thing.service.property.set");
+ service.setInputData(inputData);
+ // 属性设置服务一般不需要输出参数
+ service.setOutputData(new ArrayList<>());
+
+ return service;
+ }
+
+ /**
+ * 生成属性获取服务
+ */
+ private ThingModelService generatePropertyGetService(List properties) {
+ List outputData = new ArrayList<>();
+ for (ThingModelProperty property : properties) {
+ if ("r".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) {
+ ThingModelArgument arg = new ThingModelArgument();
+ arg.setIdentifier(property.getIdentifier());
+ arg.setName(property.getName());
+ arg.setDataType(property.getDataType());
+ arg.setDescription(property.getDescription());
+ arg.setDirection("output"); // 设置为输出参数
+ outputData.add(arg);
+ }
+ }
+ if (outputData.isEmpty()) {
+ // 如果没有可读属性,不生成属性获取服务
+ return null;
+ }
+
+ ThingModelService service = new ThingModelService();
+ service.setIdentifier("get");
+ service.setName("属性获取");
+ service.setCallType("async");
+ service.setDescription("属性获取服务");
+ service.setMethod("thing.service.property.get");
+
+ // 定义输入参数:属性标识符列表
+ ThingModelArgument inputArg = new ThingModelArgument();
+ inputArg.setIdentifier("properties");
+ inputArg.setName("属性标识符列表");
+ inputArg.setDescription("需要获取的属性标识符列表");
+ inputArg.setDirection("input"); // 设置为输入参数
+
+ // 创建数组类型,元素类型为文本类型(字符串)
+ ThingModelArrayType arrayType = new ThingModelArrayType();
+ arrayType.setType("array");
+ ThingModelArraySpecs arraySpecs = new ThingModelArraySpecs();
+ // 不指定数组长度,size 可以为 0 或者省略
+ ThingModelTextType textType = new ThingModelTextType();
+ textType.setType("text");
+ // 如果有需要,可以设置 TextType 的 specs,如长度限制
+ arraySpecs.setItem(textType);
+ arrayType.setSpecs(arraySpecs);
+
+ inputArg.setDataType(arrayType);
+
+ service.setInputData(Collections.singletonList(inputArg));
+ service.setOutputData(outputData);
+
+ return service;
+ }
+}
From 061819f25b16275b2ef97915f821dbf66cd673dd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com>
Date: Sat, 14 Sep 2024 08:32:04 +0800
Subject: [PATCH 15/31] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9AIOT=20?=
=?UTF-8?q?=E4=BC=98=E5=8C=96=E6=A0=B9=E6=8D=AE=E5=B1=9E=E6=80=A7=E5=88=97?=
=?UTF-8?q?=E8=A1=A8=EF=BC=8C=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90=E5=B1=9E?=
=?UTF-8?q?=E6=80=A7=E4=B8=8A=E6=8A=A5=E4=BA=8B=E4=BB=B6=E5=92=8C=E5=B1=9E?=
=?UTF-8?q?=E6=80=A7=E8=AE=BE=E7=BD=AE=E3=80=81=E8=8E=B7=E5=8F=96=E6=9C=8D?=
=?UTF-8?q?=E5=8A=A1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../IotThinkModelFunctionServiceImpl.java | 67 ++++++++++++++-----
1 file changed, 52 insertions(+), 15 deletions(-)
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
index 66fc01779..a2943a77b 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
@@ -96,7 +96,6 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
}
/**
- * @ TODO 还要再优化
* 根据属性列表,自动生成属性上报事件和属性设置、获取服务
*/
private void generateDefaultEventsAndServices(IotThinkModelFunctionSaveReqVO reqVO, IotThinkModelFunctionDO thinkModelFunction) {
@@ -106,27 +105,65 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
properties = new ArrayList<>();
}
- // 生成属性上报事件
- List events = reqVO.getEvents() != null ? new ArrayList<>(reqVO.getEvents()) : new ArrayList<>();
- ThingModelEvent propertyPostEvent = generatePropertyPostEvent(properties);
- events.add(propertyPostEvent);
+ // 获取现有的事件和服务
+ List existingEvents = reqVO.getEvents() != null ? new ArrayList<>(reqVO.getEvents()) : new ArrayList<>();
+ List existingServices = reqVO.getServices() != null ? new ArrayList<>(reqVO.getServices()) : new ArrayList<>();
- // 生成属性设置和获取服务
- List services = reqVO.getServices() != null ? new ArrayList<>(reqVO.getServices()) : new ArrayList<>();
+ // 生成或更新属性上报事件
+ ThingModelEvent propertyPostEvent = generatePropertyPostEvent(properties);
+ updateEventInList(existingEvents, propertyPostEvent);
+
+ // 生成或更新属性设置和获取服务
ThingModelService propertySetService = generatePropertySetService(properties);
- if (propertySetService != null) {
- services.add(propertySetService);
- }
+ updateServiceInList(existingServices, propertySetService);
+
ThingModelService propertyGetService = generatePropertyGetService(properties);
- if (propertyGetService != null) {
- services.add(propertyGetService);
- }
+ updateServiceInList(existingServices, propertyGetService);
// 更新 thinkModelFunction 对象的 events 和 services 字段
- thinkModelFunction.setEvents(JSONUtil.toJsonStr(events));
- thinkModelFunction.setServices(JSONUtil.toJsonStr(services));
+ thinkModelFunction.setEvents(JSONUtil.toJsonStr(existingEvents));
+ thinkModelFunction.setServices(JSONUtil.toJsonStr(existingServices));
}
+ /**
+ * 在事件列表中更新或添加事件
+ */
+ private void updateEventInList(List events, ThingModelEvent newEvent) {
+ if (newEvent == null) {
+ return;
+ }
+ for (int i = 0; i < events.size(); i++) {
+ ThingModelEvent event = events.get(i);
+ if (event.getIdentifier().equals(newEvent.getIdentifier())) {
+ // 更新已有的事件
+ events.set(i, newEvent);
+ return;
+ }
+ }
+ // 如果不存在,则添加新的事件
+ events.add(newEvent);
+ }
+
+ /**
+ * 在服务列表中更新或添加服务
+ */
+ private void updateServiceInList(List services, ThingModelService newService) {
+ if (newService == null) {
+ return;
+ }
+ for (int i = 0; i < services.size(); i++) {
+ ThingModelService service = services.get(i);
+ if (service.getIdentifier().equals(newService.getIdentifier())) {
+ // 更新已有的服务
+ services.set(i, newService);
+ return;
+ }
+ }
+ // 如果不存在,则添加新的服务
+ services.add(newService);
+ }
+
+
/**
* 生成属性上报事件
*/
From 64fefaa6305027762e4836ae06dae3ebac961429 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com>
Date: Sat, 14 Sep 2024 08:59:55 +0800
Subject: [PATCH 16/31] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9AIOT=20?=
=?UTF-8?q?=E5=BA=8F=E5=88=97=E5=8C=96=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?=
=?UTF-8?q?=E5=A4=84=E7=90=86=E3=80=81=E8=AF=B7=E6=B1=82=E7=A4=BA=E4=BE=8B?=
=?UTF-8?q?=E4=BF=AE=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../IotThinkModelFunctionController.http | 21 +++++----
.../IotThinkModelFunctionConvert.java | 44 +++++++++++++++----
.../IotThinkModelFunctionServiceImpl.java | 12 ++++-
3 files changed, 57 insertions(+), 20 deletions(-)
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
index e31540710..34a4054f6 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
@@ -146,9 +146,9 @@ tenant-id: {{adminTenentId}}
Authorization: Bearer {{token}}
{
- "id": 1,
- "productId": 1001,
- "productKey": "smart-sensor-001",
+ "id": 3,
+ "productId": 1002,
+ "productKey": "smart-sensor-002",
"properties": [
{
"identifier": "Temperature",
@@ -158,8 +158,8 @@ Authorization: Bearer {{token}}
"dataType": {
"type": "float",
"specs": {
- "min": -40.0,
- "max": 125.0,
+ "min": -100.0,
+ "max": 200.0,
"step": 0.1,
"unit": "℃"
}
@@ -229,7 +229,8 @@ Authorization: Bearer {{token}}
"name": "重启设备",
"callType": "async",
"inputData": [],
- "description": "远程重启设备"
+ "description": "远程重启设备",
+ "method": "thing.service.reboot"
},
{
"identifier": "SetThreshold",
@@ -251,7 +252,8 @@ Authorization: Bearer {{token}}
"description": "报警温度阈值"
}
],
- "description": "设置设备的温度报警阈值"
+ "description": "设置设备的温度报警阈值",
+ "method": "thing.service.setThreshold"
}
],
"events": [
@@ -272,13 +274,14 @@ Authorization: Bearer {{token}}
"description": "触发报警时的温度值"
}
],
- "description": "当温度超过阈值时触发高温报警事件"
+ "description": "当温度超过阈值时触发高温报警事件",
+ "method": "thing.event.highTemperatureAlert"
}
]
}
### 请求 /iot/think-model-function/get-by-product-key 接口 => 成功
-GET {{baseUrl}}/iot/think-model-function/get-by-product-key?productKey=123456
+GET {{baseUrl}}/iot/think-model-function/get-by-product-key?productKey=smart-sensor-002
tenant-id: {{adminTenentId}}
Authorization: Bearer {{token}}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java
index 41e0c583b..aa7322eb3 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java
@@ -1,12 +1,13 @@
package cn.iocoder.yudao.module.iot.convert.thinkmodelfunction;
-import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@@ -19,6 +20,8 @@ public interface IotThinkModelFunctionConvert {
IotThinkModelFunctionConvert INSTANCE = Mappers.getMapper(IotThinkModelFunctionConvert.class);
+ ObjectMapper objectMapper = new ObjectMapper();
+
// 将 SaveReqVO 转换为 DO 对象,处理 properties, services, events 字段
@Mapping(target = "properties", expression = "java(convertPropertiesToJson(bean.getProperties()))")
@Mapping(target = "services", expression = "java(convertServicesToJson(bean.getServices()))")
@@ -26,15 +29,27 @@ public interface IotThinkModelFunctionConvert {
IotThinkModelFunctionDO convert(IotThinkModelFunctionSaveReqVO bean);
default String convertPropertiesToJson(List properties) {
- return properties != null ? JSONUtil.toJsonStr(properties) : "[]";
+ try {
+ return properties != null ? objectMapper.writeValueAsString(properties) : "[]";
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException("序列化 properties 时发生错误", e);
+ }
}
default String convertServicesToJson(List services) {
- return services != null ? JSONUtil.toJsonStr(services) : "[]";
+ try {
+ return services != null ? objectMapper.writeValueAsString(services) : "[]";
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException("序列化 services 时发生错误", e);
+ }
}
default String convertEventsToJson(List events) {
- return events != null ? JSONUtil.toJsonStr(events) : "[]";
+ try {
+ return events != null ? objectMapper.writeValueAsString(events) : "[]";
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException("序列化 events 时发生错误", e);
+ }
}
// 将 DO 转换为 RespVO 对象,处理 properties, services, events 字段
@@ -44,18 +59,29 @@ public interface IotThinkModelFunctionConvert {
IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean);
default List convertJsonToProperties(String propertiesJson) {
- return propertiesJson != null ? JSONUtil.toList(propertiesJson, ThingModelProperty.class) : new ArrayList<>();
+ try {
+ return propertiesJson != null ? objectMapper.readValue(propertiesJson, objectMapper.getTypeFactory().constructCollectionType(List.class, ThingModelProperty.class)) : new ArrayList<>();
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException("反序列化 properties 时发生错误", e);
+ }
}
default List convertJsonToServices(String servicesJson) {
- return servicesJson != null ? JSONUtil.toList(servicesJson, ThingModelService.class) : new ArrayList<>();
+ try {
+ return servicesJson != null ? objectMapper.readValue(servicesJson, objectMapper.getTypeFactory().constructCollectionType(List.class, ThingModelService.class)) : new ArrayList<>();
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException("反序列化 services 时发生错误", e);
+ }
}
default List convertJsonToEvents(String eventsJson) {
- return eventsJson != null ? JSONUtil.toList(eventsJson, ThingModelEvent.class) : new ArrayList<>();
+ try {
+ return eventsJson != null ? objectMapper.readValue(eventsJson, objectMapper.getTypeFactory().constructCollectionType(List.class, ThingModelEvent.class)) : new ArrayList<>();
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException("反序列化 events 时发生错误", e);
+ }
}
// 批量转换 DO 列表到 RespVO 列表
List convertList(List list);
-}
-
+}
\ 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/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
index a2943a77b..559e0bed7 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
@@ -6,6 +6,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThi
import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert;
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -27,6 +29,8 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
@Resource
private IotThinkModelFunctionMapper thinkModelFunctionMapper;
+ private ObjectMapper objectMapper = new ObjectMapper();
+
@Override
public Long createThinkModelFunction(IotThinkModelFunctionSaveReqVO createReqVO) {
log.info("创建物模型,参数:{}", createReqVO);
@@ -121,8 +125,12 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
updateServiceInList(existingServices, propertyGetService);
// 更新 thinkModelFunction 对象的 events 和 services 字段
- thinkModelFunction.setEvents(JSONUtil.toJsonStr(existingEvents));
- thinkModelFunction.setServices(JSONUtil.toJsonStr(existingServices));
+ try {
+ thinkModelFunction.setEvents(objectMapper.writeValueAsString(existingEvents));
+ thinkModelFunction.setServices(objectMapper.writeValueAsString(existingServices));
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException("序列化事件和服务时发生错误", e);
+ }
}
/**
From 07b3ac20f613e4b1e7fd7442f802fbba72bf3d30 Mon Sep 17 00:00:00 2001
From: YunaiV
Date: Sat, 14 Sep 2024 09:44:09 +0800
Subject: [PATCH 17/31] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?=
=?UTF-8?q?=E5=AE=A1=E3=80=91IOT=EF=BC=9A=E7=89=A9=E6=A8=A1=E5=9E=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../thingModel/ThingModelArraySpecs.java | 9 ---------
.../thingModel/ThingModelEvent.java | 10 +++++++++-
.../thingModel/ThingModelProperty.java | 5 ++++-
.../thingModel/ThingModelService.java | 10 +++++++++-
.../{ => dataType}/ThingModelArgument.java | 9 +++++++--
.../dataType/ThingModelArraySpecs.java | 17 +++++++++++++++++
.../{ => dataType}/ThingModelArrayType.java | 7 ++++---
.../{ => dataType}/ThingModelBoolType.java | 4 +++-
.../{ => dataType}/ThingModelDataType.java | 4 +++-
.../{ => dataType}/ThingModelDateType.java | 6 +++---
.../{ => dataType}/ThingModelDoubleType.java | 6 +++---
.../{ => dataType}/ThingModelEnumType.java | 12 ++++++++----
.../{ => dataType}/ThingModelFloatType.java | 4 +++-
.../{ => dataType}/ThingModelIntType.java | 6 +++---
.../{ => dataType}/ThingModelStructField.java | 4 +++-
.../{ => dataType}/ThingModelStructType.java | 7 ++++---
.../{ => dataType}/ThingModelTextType.java | 13 +++++++++----
.../IotThinkModelFunctionDO.java | 18 ++++++++++++------
.../IotThinkModelFunctionServiceImpl.java | 5 ++++-
19 files changed, 108 insertions(+), 48 deletions(-)
delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java
rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelArgument.java (64%)
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArraySpecs.java
rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelArrayType.java (67%)
rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelBoolType.java (89%)
rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelDataType.java (97%)
rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelDateType.java (69%)
rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelDoubleType.java (78%)
rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelEnumType.java (52%)
rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelFloatType.java (92%)
rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelIntType.java (78%)
rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelStructField.java (89%)
rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelStructType.java (71%)
rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelTextType.java (63%)
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java
deleted file mode 100644
index 3ea23e8db..000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
-
-import lombok.Data;
-
-@Data
-public class ThingModelArraySpecs {
- private int size; // 数组长度
- private ThingModelDataType item; // 数组元素的类型
-}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java
index 857f688e9..96dff1adf 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java
@@ -1,14 +1,22 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArgument;
import lombok.Data;
import java.util.List;
@Data
public class ThingModelEvent {
+
private String identifier;
private String name;
- private String type; // "info"、"alert"、"error"
+ /**
+ * 事件类型
+ *
+ * "info"、"alert"、"error"
+ */
+ private String type;
private List outputData;
private String description;
private String method;
+
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java
index f82198152..4f9e32c59 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java
@@ -1,13 +1,16 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelDataType;
import lombok.Data;
@Data
public class ThingModelProperty {
+
private String identifier;
private String name;
private String accessMode; // "rw"、"r"、"w"
- private boolean required;
+ private Boolean required;
private ThingModelDataType dataType;
private String description;
+
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java
index 521e9ab08..839ceff47 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java
@@ -1,15 +1,23 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArgument;
import lombok.Data;
import java.util.List;
@Data
public class ThingModelService {
+
private String identifier;
private String name;
- private String callType; // "sync"、"async"
+ /**
+ * 调用类型
+ *
+ * "sync"、"async"
+ */
+ private String callType;
private List inputData;
private List outputData;
private String description;
private String method;
+
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArgument.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArgument.java
similarity index 64%
rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArgument.java
rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArgument.java
index 909d63459..2be24004e 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArgument.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArgument.java
@@ -1,12 +1,17 @@
-package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
import lombok.Data;
@Data
public class ThingModelArgument {
+
private String identifier;
private String name;
private ThingModelDataType dataType;
- private String direction; // 用于区分输入或输出参数,"input" 或 "output"
+ /**
+ * 用于区分输入或输出参数,"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/thinkmodelfunction/thingModel/dataType/ThingModelArraySpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArraySpecs.java
new file mode 100644
index 000000000..c3faf6161
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArraySpecs.java
@@ -0,0 +1,17 @@
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
+
+import lombok.Data;
+
+@Data
+public class ThingModelArraySpecs {
+
+ /**
+ * 数组长度
+ */
+ private int size;
+ /**
+ * 数组元素的类型
+ */
+ private ThingModelDataType item;
+
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArrayType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArrayType.java
similarity index 67%
rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArrayType.java
rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArrayType.java
index 114add210..bab87be0a 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArrayType.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArrayType.java
@@ -1,11 +1,12 @@
-package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
import lombok.Data;
-import lombok.EqualsAndHashCode;
+// TODO @haohao:这个是不是和别的类,不太统一哈
@Data
-@EqualsAndHashCode(callSuper = true)
public class ThingModelArrayType extends ThingModelDataType {
+
private ThingModelArraySpecs specs;
+
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelBoolType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelBoolType.java
similarity index 89%
rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelBoolType.java
rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelBoolType.java
index f7e7e456b..b8ca64195 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelBoolType.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelBoolType.java
@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -6,5 +6,7 @@ import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class ThingModelBoolType extends ThingModelDataType {
+
// Bool 类型一般不需要额外的 specs
+
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDataType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDataType.java
similarity index 97%
rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDataType.java
rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDataType.java
index 613cbd766..ec5f04bbb 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDataType.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDataType.java
@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
@@ -18,5 +18,7 @@ import lombok.Data;
@JsonSubTypes.Type(value = ThingModelArrayType.class, name = "array")
})
public abstract class ThingModelDataType {
+
private String type;
+
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDateType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDateType.java
similarity index 69%
rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDateType.java
rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDateType.java
index 11cb3a729..854229339 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDateType.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDateType.java
@@ -1,10 +1,10 @@
-package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
import lombok.Data;
-import lombok.EqualsAndHashCode;
@Data
-@EqualsAndHashCode(callSuper = true)
public class ThingModelDateType extends ThingModelDataType {
+
// Date 类型一般不需要额外的 specs
+
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDoubleType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDoubleType.java
similarity index 78%
rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDoubleType.java
rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDoubleType.java
index d60302179..e5f3ad268 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDoubleType.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDoubleType.java
@@ -1,18 +1,18 @@
-package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
import lombok.Data;
-import lombok.EqualsAndHashCode;
@Data
-@EqualsAndHashCode(callSuper = true)
public class ThingModelDoubleType extends ThingModelDataType {
private ThingModelDoubleSpecs specs;
}
@Data
class ThingModelDoubleSpecs {
+
private Double min;
private Double max;
private Double step;
private String unit;
+
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEnumType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelEnumType.java
similarity index 52%
rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEnumType.java
rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelEnumType.java
index f76962661..3dcb068e9 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEnumType.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelEnumType.java
@@ -1,11 +1,15 @@
-package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
import lombok.Data;
-import lombok.EqualsAndHashCode;
+
import java.util.Map;
@Data
-@EqualsAndHashCode(callSuper = true)
public class ThingModelEnumType extends ThingModelDataType {
- private Map specs; // 枚举值和描述的键值对
+
+ /**
+ * 枚举值和描述的键值对
+ */
+ private Map specs;
+
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelFloatType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelFloatType.java
similarity index 92%
rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelFloatType.java
rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelFloatType.java
index c9d5516ad..27926fa49 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelFloatType.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelFloatType.java
@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -11,8 +11,10 @@ public class ThingModelFloatType extends ThingModelDataType {
@Data
class ThingModelFloatSpecs {
+
private Float min;
private Float max;
private Float step;
private String unit;
+
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelIntType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelIntType.java
similarity index 78%
rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelIntType.java
rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelIntType.java
index d48f50e47..a126eb749 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelIntType.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelIntType.java
@@ -1,18 +1,18 @@
-package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
import lombok.Data;
-import lombok.EqualsAndHashCode;
@Data
-@EqualsAndHashCode(callSuper = true)
public class ThingModelIntType extends ThingModelDataType {
private ThingModelIntSpecs specs;
}
@Data
class ThingModelIntSpecs {
+
private Integer min;
private Integer max;
private Integer step;
private String unit;
+
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructField.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructField.java
similarity index 89%
rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructField.java
rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructField.java
index 449db55c2..5e079f22b 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructField.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructField.java
@@ -1,11 +1,13 @@
-package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
import lombok.Data;
@Data
public class ThingModelStructField {
+
private String identifier;
private String name;
private ThingModelDataType dataType;
private String description;
+
}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructType.java
similarity index 71%
rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructType.java
rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructType.java
index d3d35f16c..f0996513c 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructType.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructType.java
@@ -1,13 +1,14 @@
-package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
import lombok.Data;
-import lombok.EqualsAndHashCode;
+
import java.util.List;
@Data
-@EqualsAndHashCode(callSuper = true)
public class ThingModelStructType extends ThingModelDataType {
+
private List specs;
+
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelTextType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelTextType.java
similarity index 63%
rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelTextType.java
rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelTextType.java
index 0f6ea2bcb..16d1e402e 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelTextType.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelTextType.java
@@ -1,15 +1,20 @@
-package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
+package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
import lombok.Data;
-import lombok.EqualsAndHashCode;
@Data
-@EqualsAndHashCode(callSuper = true)
public class ThingModelTextType extends ThingModelDataType {
+
private ThingModelTextSpecs specs;
+
}
@Data
class ThingModelTextSpecs {
- private Integer length; // 最大长度
+
+ /**
+ * 最大长度
+ */
+ private Integer length;
+
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java
index 564eefb2b..80fe0a65b 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java
@@ -1,42 +1,48 @@
package cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
/**
- * IoT 产品物模型 DO
+ * IoT 产品物模型功能 DO
+ *
+ * 每个 {@link IotProductDO} 和 {@link IotThinkModelFunctionDO} 是“一对多”的关系,它的每个属性、事件、服务都对应一条记录
*
* @author 芋道源码
*/
@TableName("iot_think_model_function")
@KeySequence("iot_think_model_function_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class IotThinkModelFunctionDO extends BaseDO {
/**
- * 产品ID
+ * 物模型功能编号
*/
@TableId
private Long id;
-
+ // TODO @haohao:是不是有一个 identifier,需要要有哈
+ // TODO @haohao:name、description 属性,还有个类型
/**
* 产品标识
+ *
+ * 关联 {@link IotProductDO#getId()}
*/
private Long productId;
-
/**
* 产品标识
+ *
+ * 关联 {@link IotProductDO#getProductKey()}
*/
private String productKey;
+ // TODO @haohao:是不是可以搞成 ThingModelProperty、ThingModelEvent、ThingModelService 进行存储
/**
* 属性列表
*/
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
index 559e0bed7..6c8afe15f 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
@@ -1,7 +1,10 @@
package cn.iocoder.yudao.module.iot.service.thinkmodelfunction;
-import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.*;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArgument;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArraySpecs;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArrayType;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelTextType;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert;
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
From 84bc5aec1ec67a18654ba5ecb8cfea6bc41b1c94 Mon Sep 17 00:00:00 2001
From: YunaiV
Date: Sat, 14 Sep 2024 22:39:14 +0800
Subject: [PATCH 18/31] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?=
=?UTF-8?q?=E5=AE=A1=E3=80=91IOT=EF=BC=9A=E7=89=A9=E6=A8=A1=E5=9E=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../thingModel/ThingModelEvent.java | 12 ++-
.../thingModel/ThingModelProperty.java | 17 +++-
.../thingModel/ThingModelService.java | 12 ++-
.../IotThinkModelFunctionDO2.java | 85 +++++++++++++++++++
4 files changed, 121 insertions(+), 5 deletions(-)
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO2.java
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java
index 96dff1adf..d7fa68758 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java
@@ -7,8 +7,19 @@ import java.util.List;
@Data
public class ThingModelEvent {
+ /**
+ * 事件标识符
+ */
private String identifier;
+ /**
+ * 事件名称
+ */
private String name;
+ /**
+ * 事件描述
+ */
+ private String description;
+
/**
* 事件类型
*
@@ -16,7 +27,6 @@ public class ThingModelEvent {
*/
private String type;
private List outputData;
- private String description;
private String method;
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java
index 4f9e32c59..025d37e76 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java
@@ -6,11 +6,22 @@ import lombok.Data;
@Data
public class ThingModelProperty {
+ /**
+ * 属性标识符
+ */
private String identifier;
+ /**
+ * 属性名称
+ */
private String name;
- private String accessMode; // "rw"、"r"、"w"
- private Boolean required;
- private ThingModelDataType dataType;
+ /**
+ * 属性描述
+ */
private String description;
+ private String accessMode; // "rw"、"r"、"w"
+ private Boolean required;
+ // TODO @haohao:这个是不是 dataSpecs 和 dataSpecsList?https://help.aliyun.com/zh/iot/developer-reference/api-a99t11
+ private ThingModelDataType dataType;
+
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java
index 839ceff47..d97e05e9c 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java
@@ -7,8 +7,19 @@ import java.util.List;
@Data
public class ThingModelService {
+ /**
+ * 服务标识符
+ */
private String identifier;
+ /**
+ * 服务名称
+ */
private String name;
+ /**
+ * 服务描述
+ */
+ private String description;
+
/**
* 调用类型
*
@@ -17,7 +28,6 @@ public class ThingModelService {
private String callType;
private List inputData;
private List outputData;
- private String description;
private String method;
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO2.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO2.java
new file mode 100644
index 000000000..ece631c77
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO2.java
@@ -0,0 +1,85 @@
+package cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
+import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * IoT 产品物模型功能 DO
+ *
+ * 每个 {@link IotProductDO} 和 {@link IotThinkModelFunctionDO2} 是“一对多”的关系,它的每个属性、事件、服务都对应一条记录
+ *
+ * @author 芋道源码
+ */
+@TableName("iot_think_model_function")
+@KeySequence("iot_think_model_function_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class IotThinkModelFunctionDO2 extends BaseDO {
+
+ /**
+ * 物模型功能编号
+ */
+ @TableId
+ private Long id;
+
+ /**
+ * 功能标识
+ */
+ private String identifier;
+ /**
+ * 功能名称
+ */
+ private String name;
+ /**
+ * 功能描述
+ */
+ private String description;
+
+ /**
+ * 产品标识
+ *
+ * 关联 {@link IotProductDO#getId()}
+ */
+ private Long productId;
+ /**
+ * 产品标识
+ *
+ * 关联 {@link IotProductDO#getProductKey()}
+ */
+ private String productKey;
+
+ /**
+ * 功能类型
+ *
+ * 1 - 属性
+ * 2 - 服务
+ * 3 - 事件
+ */
+ // TODO @haohao:枚举
+ private Integer type;
+
+ /**
+ * 属性
+ */
+ private ThingModelProperty property;
+ /**
+ * 事件
+ */
+ private ThingModelEvent event;
+ /**
+ * 服务
+ */
+ private String service;
+
+}
\ No newline at end of file
From 2932314ee0b838a822e63e3c225efc0fa41ca6a1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com>
Date: Sun, 15 Sep 2024 20:09:18 +0800
Subject: [PATCH 19/31] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9AIOT=20?=
=?UTF-8?q?=E7=89=A9=E6=A8=A1=E5=9E=8B=E6=8E=A5=E5=8F=A3=E4=BC=98=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../module/iot/enums/ErrorCodeConstants.java | 1 +
.../enums/product/IotThingModelTypeEnum.java | 47 +++
.../IotThinkModelFunctionController.http | 311 +++---------------
.../IotThinkModelFunctionController.java | 18 +-
.../vo/IotThinkModelFunctionRespVO.java | 30 +-
.../vo/IotThinkModelFunctionSaveReqVO.java | 33 +-
.../IotThinkModelFunctionConvert.java | 78 ++---
.../IotThinkModelFunctionDO.java | 57 +++-
.../IotThinkModelFunctionDO2.java | 85 -----
.../IotThinkModelFunctionMapper.java | 15 +-
.../IotThinkModelFunctionService.java | 31 +-
.../IotThinkModelFunctionServiceImpl.java | 281 +++++++++-------
12 files changed, 409 insertions(+), 578 deletions(-)
create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotThingModelTypeEnum.java
delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO2.java
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
index d26e5f2ec..e586d4535 100644
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
+++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
@@ -17,4 +17,5 @@ public interface ErrorCodeConstants {
// ========== IoT 产品物模型 1-050-002-000 ============
ErrorCode THINK_MODEL_FUNCTION_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在");
ErrorCode THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY = new ErrorCode(1_050_002_001, "ProductKey 对应的产品物模型已存在");
+ ErrorCode THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER = new ErrorCode(1_050_002_002, "产品物模型标识已存在");
}
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotThingModelTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotThingModelTypeEnum.java
new file mode 100644
index 000000000..872dda6a3
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotThingModelTypeEnum.java
@@ -0,0 +1,47 @@
+package cn.iocoder.yudao.module.iot.enums.product;
+
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * IOT 物模型功能类型枚举类
+ *
+ * @author ahh
+ */
+@AllArgsConstructor
+@Getter
+public enum IotThingModelTypeEnum implements IntArrayValuable {
+
+ /**
+ * 属性
+ */
+ PROPERTY(1, "属性"),
+ /**
+ * 服务
+ */
+ SERVICE(2, "服务"),
+ /**
+ * 事件
+ */
+ EVENT(3, "事件");
+
+ public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotThingModelTypeEnum::getType).toArray();
+
+ /**
+ * 类型
+ */
+ private final Integer type;
+ /**
+ * 描述
+ */
+ private final String description;
+
+ @Override
+ public int[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
index 34a4054f6..febf01014 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
@@ -5,137 +5,28 @@ tenant-id: {{adminTenentId}}
Authorization: Bearer {{token}}
{
- "productId": 1002,
- "productKey": "smart-sensor-002",
- "properties": [
- {
- "identifier": "Temperature",
- "name": "温度",
- "accessMode": "r",
- "required": true,
- "dataType": {
- "type": "float",
- "specs": {
- "min": -40.0,
- "max": 125.0,
- "step": 0.1,
- "unit": "℃"
- }
- },
- "description": "当前温度值"
+ "productId": 1001,
+ "productKey": "smart-sensor-001",
+ "identifier": "Temperature",
+ "name": "温度",
+ "description": "当前温度值",
+ "type": 1,
+ "property": {
+ "identifier": "Temperature",
+ "name": "温度",
+ "accessMode": "r",
+ "required": true,
+ "dataType": {
+ "type": "float",
+ "specs": {
+ "min": -40.0,
+ "max": 125.0,
+ "step": 0.1,
+ "unit": "℃"
+ }
},
- {
- "identifier": "Humidity",
- "name": "湿度",
- "accessMode": "r",
- "required": true,
- "dataType": {
- "type": "float",
- "specs": {
- "min": 0.0,
- "max": 100.0,
- "step": 0.1,
- "unit": "%"
- }
- },
- "description": "当前湿度值"
- },
- {
- "identifier": "GeoLocation",
- "name": "地理位置",
- "accessMode": "r",
- "required": false,
- "dataType": {
- "type": "struct",
- "specs": [
- {
- "identifier": "Longitude",
- "name": "经度",
- "dataType": {
- "type": "double",
- "specs": {
- "min": -180.0,
- "max": 180.0,
- "step": 0.000001,
- "unit": "°"
- }
- },
- "description": "设备所在位置的经度"
- },
- {
- "identifier": "Latitude",
- "name": "纬度",
- "dataType": {
- "type": "double",
- "specs": {
- "min": -90.0,
- "max": 90.0,
- "step": 0.000001,
- "unit": "°"
- }
- },
- "description": "设备所在位置的纬度"
- }
- ]
- },
- "description": "设备的地理位置信息"
- }
- ],
- "services": [
- {
- "identifier": "Reboot",
- "name": "重启设备",
- "callType": "async",
- "inputData": [],
- "description": "远程重启设备",
- "method": "thing.service.reboot"
- },
- {
- "identifier": "SetThreshold",
- "name": "设置温度阈值",
- "callType": "sync",
- "inputData": [
- {
- "identifier": "Threshold",
- "name": "阈值",
- "dataType": {
- "type": "float",
- "specs": {
- "min": -40.0,
- "max": 125.0,
- "step": 0.1,
- "unit": "℃"
- }
- },
- "description": "报警温度阈值"
- }
- ],
- "description": "设置设备的温度报警阈值",
- "method": "thing.service.setThreshold"
- }
- ],
- "events": [
- {
- "identifier": "HighTemperatureAlert",
- "name": "高温报警",
- "type": "alert",
- "outputData": [
- {
- "identifier": "CurrentTemperature",
- "name": "当前温度",
- "dataType": {
- "type": "float",
- "specs": {
- "unit": "℃"
- }
- },
- "description": "触发报警时的温度值"
- }
- ],
- "description": "当温度超过阈值时触发高温报警事件",
- "method": "thing.event.highTemperatureAlert"
- }
- ]
+ "description": "当前温度值"
+ }
}
@@ -147,141 +38,37 @@ Authorization: Bearer {{token}}
{
"id": 3,
- "productId": 1002,
- "productKey": "smart-sensor-002",
- "properties": [
- {
- "identifier": "Temperature",
- "name": "温度",
- "accessMode": "r",
- "required": true,
- "dataType": {
- "type": "float",
- "specs": {
- "min": -100.0,
- "max": 200.0,
- "step": 0.1,
- "unit": "℃"
- }
- },
- "description": "当前温度值"
+ "productId": 1001,
+ "productKey": "smart-sensor-001",
+ "identifier": "Temperature",
+ "name": "温度",
+ "description": "当前温度值",
+ "type": 1,
+ "property": {
+ "identifier": "Temperature",
+ "name": "温度",
+ "accessMode": "r",
+ "required": true,
+ "dataType": {
+ "type": "float",
+ "specs": {
+ "min": -10.0,
+ "max": 100.0,
+ "step": 0.1,
+ "unit": "℃"
+ }
},
- {
- "identifier": "Humidity",
- "name": "湿度",
- "accessMode": "r",
- "required": true,
- "dataType": {
- "type": "float",
- "specs": {
- "min": 0.0,
- "max": 100.0,
- "step": 0.1,
- "unit": "%"
- }
- },
- "description": "当前湿度值"
- },
- {
- "identifier": "GeoLocation",
- "name": "地理位置",
- "accessMode": "r",
- "required": false,
- "dataType": {
- "type": "struct",
- "specs": [
- {
- "identifier": "Longitude",
- "name": "经度",
- "dataType": {
- "type": "double",
- "specs": {
- "min": -180.0,
- "max": 180.0,
- "step": 0.000001,
- "unit": "°"
- }
- },
- "description": "设备所在位置的经度"
- },
- {
- "identifier": "Latitude",
- "name": "纬度",
- "dataType": {
- "type": "double",
- "specs": {
- "min": -90.0,
- "max": 90.0,
- "step": 0.000001,
- "unit": "°"
- }
- },
- "description": "设备所在位置的纬度"
- }
- ]
- },
- "description": "设备的地理位置信息"
- }
- ],
- "services": [
- {
- "identifier": "Reboot",
- "name": "重启设备",
- "callType": "async",
- "inputData": [],
- "description": "远程重启设备",
- "method": "thing.service.reboot"
- },
- {
- "identifier": "SetThreshold",
- "name": "设置温度阈值",
- "callType": "sync",
- "inputData": [
- {
- "identifier": "Threshold",
- "name": "阈值",
- "dataType": {
- "type": "float",
- "specs": {
- "min": -40.0,
- "max": 125.0,
- "step": 0.1,
- "unit": "℃"
- }
- },
- "description": "报警温度阈值"
- }
- ],
- "description": "设置设备的温度报警阈值",
- "method": "thing.service.setThreshold"
- }
- ],
- "events": [
- {
- "identifier": "HighTemperatureAlert",
- "name": "高温报警",
- "type": "alert",
- "outputData": [
- {
- "identifier": "CurrentTemperature",
- "name": "当前温度",
- "dataType": {
- "type": "float",
- "specs": {
- "unit": "℃"
- }
- },
- "description": "触发报警时的温度值"
- }
- ],
- "description": "当温度超过阈值时触发高温报警事件",
- "method": "thing.event.highTemperatureAlert"
- }
- ]
+ "description": "当前温度值"
+ }
}
+### 请求 /iot/think-model-function/get 接口 => 成功
+GET {{baseUrl}}/iot/think-model-function/get?id=3
+tenant-id: {{adminTenentId}}
+Authorization: Bearer {{token}}
-### 请求 /iot/think-model-function/get-by-product-key 接口 => 成功
-GET {{baseUrl}}/iot/think-model-function/get-by-product-key?productKey=smart-sensor-002
+
+### 请求 /iot/think-model-function/list-by-product-id 接口 => 成功
+GET {{baseUrl}}/iot/think-model-function/list-by-product-id?productId=1001
tenant-id: {{adminTenentId}}
Authorization: Bearer {{token}}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java
index a0051d9eb..36b91e85b 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java
@@ -15,6 +15,8 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
+import java.util.List;
+
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - IoT 产品物模型")
@@ -50,23 +52,23 @@ public class IotThinkModelFunctionController {
return success(true);
}
- @GetMapping("/get-by-product-key")
+ @GetMapping("/get")
@Operation(summary = "获得IoT 产品物模型")
- @Parameter(name = "productKey", description = "产品Key", required = true, example = "1024")
+ @Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('iot:think-model-function:query')")
- public CommonResult getThinkModelFunctionByProductKey(@RequestParam("productKey") String productKey) {
- IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionService.getThinkModelFunctionByProductKey(productKey);
+ public CommonResult getThinkModelFunction(@RequestParam("id") Long id) {
+ IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionService.getThinkModelFunction(id);
IotThinkModelFunctionRespVO respVO = IotThinkModelFunctionConvert.INSTANCE.convert(thinkModelFunction);
return success(respVO);
}
- @GetMapping("/get-by-product-id")
+ @GetMapping("/list-by-product-id")
@Operation(summary = "获得IoT 产品物模型")
@Parameter(name = "productId", description = "产品ID", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('iot:think-model-function:query')")
- public CommonResult getThinkModelFunctionByProductId(@RequestParam("productId") Long productId) {
- IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionService.getThinkModelFunctionByProductId(productId);
- IotThinkModelFunctionRespVO respVO = IotThinkModelFunctionConvert.INSTANCE.convert(thinkModelFunction);
+ public CommonResult> getThinkModelFunctionListByProductId(@RequestParam("productId") Long productId) {
+ List thinkModelFunctionListByProductId = thinkModelFunctionService.getThinkModelFunctionListByProductId(productId);
+ List respVO = IotThinkModelFunctionConvert.INSTANCE.convertList(thinkModelFunctionListByProductId);
return success(respVO);
}
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java
index 42ac727a4..9ef3f58d8 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java
@@ -20,21 +20,33 @@ public class IotThinkModelFunctionRespVO {
@ExcelProperty("产品ID")
private Long id;
+ @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED)
+ private Long productId;
+
@Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("产品标识")
private String productKey;
- @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
- @ExcelProperty("属性列表")
- private List properties;
+ @Schema(description = "功能标识", requiredMode = Schema.RequiredMode.REQUIRED)
+ private String identifier;
- @Schema(description = "服务列表")
- @ExcelProperty("服务列表")
- private List services;
+ @Schema(description = "功能名称", requiredMode = Schema.RequiredMode.REQUIRED)
+ private String name;
- @Schema(description = "事件列表")
- @ExcelProperty("事件列表")
- private List events;
+ @Schema(description = "功能描述", requiredMode = Schema.RequiredMode.REQUIRED)
+ private String description;
+
+ @Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED)
+ private Integer type;
+
+ @Schema(description = "属性", requiredMode = Schema.RequiredMode.REQUIRED)
+ private ThingModelProperty property;
+
+ @Schema(description = "服务", requiredMode = Schema.RequiredMode.REQUIRED)
+ private ThingModelEvent event;
+
+ @Schema(description = "事件", requiredMode = Schema.RequiredMode.REQUIRED)
+ private ThingModelService service;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java
index 00132fa8b..106972fe3 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java
@@ -1,15 +1,15 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
+import cn.iocoder.yudao.module.iot.enums.product.IotThingModelTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
-import java.util.List;
-
@Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO")
@Data
public class IotThinkModelFunctionSaveReqVO {
@@ -25,14 +25,29 @@ public class IotThinkModelFunctionSaveReqVO {
@NotEmpty(message = "产品标识不能为空")
private String productKey;
- @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
- @NotEmpty(message = "属性列表不能为空")
- private List properties;
+ @Schema(description = "功能标识", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotEmpty(message = "功能标识不能为空")
+ private String identifier;
- @Schema(description = "服务列表")
- private List services;
+ @Schema(description = "功能名称", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotEmpty(message = "功能名称不能为空")
+ private String name;
- @Schema(description = "事件列表")
- private List events;
+ @Schema(description = "功能描述", requiredMode = Schema.RequiredMode.REQUIRED)
+ private String description;
+
+ @Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotNull(message = "功能类型不能为空")
+ @InEnum(IotThingModelTypeEnum.class)
+ private Integer type;
+
+ @Schema(description = "属性", requiredMode = Schema.RequiredMode.REQUIRED)
+ private ThingModelProperty property;
+
+ @Schema(description = "服务", requiredMode = Schema.RequiredMode.REQUIRED)
+ private ThingModelService service;
+
+ @Schema(description = "事件", requiredMode = Schema.RequiredMode.REQUIRED)
+ private ThingModelEvent event;
}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java
index aa7322eb3..08dabd5d6 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java
@@ -6,82 +6,52 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingMode
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
+import cn.iocoder.yudao.module.iot.enums.product.IotThingModelTypeEnum;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
-import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
@Mapper
public interface IotThinkModelFunctionConvert {
IotThinkModelFunctionConvert INSTANCE = Mappers.getMapper(IotThinkModelFunctionConvert.class);
- ObjectMapper objectMapper = new ObjectMapper();
-
- // 将 SaveReqVO 转换为 DO 对象,处理 properties, services, events 字段
- @Mapping(target = "properties", expression = "java(convertPropertiesToJson(bean.getProperties()))")
- @Mapping(target = "services", expression = "java(convertServicesToJson(bean.getServices()))")
- @Mapping(target = "events", expression = "java(convertEventsToJson(bean.getEvents()))")
+ // 将 SaveReqVO 转换为 DO
+ @Mapping(target = "property", expression = "java(convertToProperty(bean))")
+ @Mapping(target = "event", expression = "java(convertToEvent(bean))")
+ @Mapping(target = "service", expression = "java(convertToService(bean))")
IotThinkModelFunctionDO convert(IotThinkModelFunctionSaveReqVO bean);
- default String convertPropertiesToJson(List properties) {
- try {
- return properties != null ? objectMapper.writeValueAsString(properties) : "[]";
- } catch (JsonProcessingException e) {
- throw new RuntimeException("序列化 properties 时发生错误", e);
+ default ThingModelProperty convertToProperty(IotThinkModelFunctionSaveReqVO bean) {
+ if (Objects.equals(bean.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
+ return bean.getProperty();
}
+ return null;
}
- default String convertServicesToJson(List services) {
- try {
- return services != null ? objectMapper.writeValueAsString(services) : "[]";
- } catch (JsonProcessingException e) {
- throw new RuntimeException("序列化 services 时发生错误", e);
+ default ThingModelEvent convertToEvent(IotThinkModelFunctionSaveReqVO bean) {
+ if (Objects.equals(bean.getType(), IotThingModelTypeEnum.EVENT.getType())) {
+ return bean.getEvent();
}
+ return null;
}
- default String convertEventsToJson(List events) {
- try {
- return events != null ? objectMapper.writeValueAsString(events) : "[]";
- } catch (JsonProcessingException e) {
- throw new RuntimeException("序列化 events 时发生错误", e);
+ default ThingModelService convertToService(IotThinkModelFunctionSaveReqVO bean) {
+ if (Objects.equals(bean.getType(), IotThingModelTypeEnum.SERVICE.getType())) {
+ return bean.getService();
}
+ return null;
}
- // 将 DO 转换为 RespVO 对象,处理 properties, services, events 字段
- @Mapping(target = "properties", expression = "java(convertJsonToProperties(bean.getProperties()))")
- @Mapping(target = "services", expression = "java(convertJsonToServices(bean.getServices()))")
- @Mapping(target = "events", expression = "java(convertJsonToEvents(bean.getEvents()))")
+ // 将 DO 转换为 RespVO
+ @Mapping(target = "property", source = "property")
+ @Mapping(target = "event", source = "event")
+ @Mapping(target = "service", source = "service")
IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean);
- default List convertJsonToProperties(String propertiesJson) {
- try {
- return propertiesJson != null ? objectMapper.readValue(propertiesJson, objectMapper.getTypeFactory().constructCollectionType(List.class, ThingModelProperty.class)) : new ArrayList<>();
- } catch (JsonProcessingException e) {
- throw new RuntimeException("反序列化 properties 时发生错误", e);
- }
- }
-
- default List convertJsonToServices(String servicesJson) {
- try {
- return servicesJson != null ? objectMapper.readValue(servicesJson, objectMapper.getTypeFactory().constructCollectionType(List.class, ThingModelService.class)) : new ArrayList<>();
- } catch (JsonProcessingException e) {
- throw new RuntimeException("反序列化 services 时发生错误", e);
- }
- }
-
- default List convertJsonToEvents(String eventsJson) {
- try {
- return eventsJson != null ? objectMapper.readValue(eventsJson, objectMapper.getTypeFactory().constructCollectionType(List.class, ThingModelEvent.class)) : new ArrayList<>();
- } catch (JsonProcessingException e) {
- throw new RuntimeException("反序列化 events 时发生错误", e);
- }
- }
-
- // 批量转换 DO 列表到 RespVO 列表
+ // 批量转换
List convertList(List list);
-}
\ No newline at end of file
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java
index 80fe0a65b..f05562452 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java
@@ -1,20 +1,28 @@
package cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.*;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
/**
* IoT 产品物模型功能 DO
- *
+ *
* 每个 {@link IotProductDO} 和 {@link IotThinkModelFunctionDO} 是“一对多”的关系,它的每个属性、事件、服务都对应一条记录
*
* @author 芋道源码
*/
-@TableName("iot_think_model_function")
+@TableName(value = "iot_think_model_function", autoResultMap = true)
@KeySequence("iot_think_model_function_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@Builder
@@ -27,35 +35,56 @@ public class IotThinkModelFunctionDO extends BaseDO {
*/
@TableId
private Long id;
- // TODO @haohao:是不是有一个 identifier,需要要有哈
- // TODO @haohao:name、description 属性,还有个类型
+
+ /**
+ * 功能标识
+ */
+ private String identifier;
+ /**
+ * 功能名称
+ */
+ private String name;
+ /**
+ * 功能描述
+ */
+ private String description;
+
/**
* 产品标识
- *
+ *
* 关联 {@link IotProductDO#getId()}
*/
private Long productId;
/**
* 产品标识
- *
+ *
* 关联 {@link IotProductDO#getProductKey()}
*/
private String productKey;
- // TODO @haohao:是不是可以搞成 ThingModelProperty、ThingModelEvent、ThingModelService 进行存储
/**
- * 属性列表
+ * 功能类型
+ *
+ * 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotThingModelTypeEnum}
*/
- private String properties;
+ private Integer type;
/**
- * 服务列表
+ * 属性
*/
- private String services;
+ @TableField(typeHandler = JacksonTypeHandler.class)
+ private ThingModelProperty property;
/**
- * 事件列表
+ * 事件
*/
- private String events;
+ @TableField(typeHandler = JacksonTypeHandler.class)
+ private ThingModelEvent event;
+
+ /**
+ * 服务
+ */
+ @TableField(typeHandler = JacksonTypeHandler.class)
+ private ThingModelService service;
}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO2.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO2.java
deleted file mode 100644
index ece631c77..000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO2.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction;
-
-import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
-import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
-import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
-import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
-import com.baomidou.mybatisplus.annotation.KeySequence;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-/**
- * IoT 产品物模型功能 DO
- *
- * 每个 {@link IotProductDO} 和 {@link IotThinkModelFunctionDO2} 是“一对多”的关系,它的每个属性、事件、服务都对应一条记录
- *
- * @author 芋道源码
- */
-@TableName("iot_think_model_function")
-@KeySequence("iot_think_model_function_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
-@Data
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class IotThinkModelFunctionDO2 extends BaseDO {
-
- /**
- * 物模型功能编号
- */
- @TableId
- private Long id;
-
- /**
- * 功能标识
- */
- private String identifier;
- /**
- * 功能名称
- */
- private String name;
- /**
- * 功能描述
- */
- private String description;
-
- /**
- * 产品标识
- *
- * 关联 {@link IotProductDO#getId()}
- */
- private Long productId;
- /**
- * 产品标识
- *
- * 关联 {@link IotProductDO#getProductKey()}
- */
- private String productKey;
-
- /**
- * 功能类型
- *
- * 1 - 属性
- * 2 - 服务
- * 3 - 事件
- */
- // TODO @haohao:枚举
- private Integer type;
-
- /**
- * 属性
- */
- private ThingModelProperty property;
- /**
- * 事件
- */
- private ThingModelEvent event;
- /**
- * 服务
- */
- private String service;
-
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
index 21ae1967a..dbd4cb359 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
@@ -5,6 +5,8 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
import org.apache.ibatis.annotations.Mapper;
+import java.util.List;
+
/**
* IoT 产品物模型 Mapper
*
@@ -13,12 +15,17 @@ import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface IotThinkModelFunctionMapper extends BaseMapperX {
- default IotThinkModelFunctionDO selectByProductKey(String productKey) {
- return selectOne(new LambdaQueryWrapperX().eq(IotThinkModelFunctionDO::getProductKey, productKey));
+ default IotThinkModelFunctionDO selectByProductIdAndIdentifier(Long productId, String identifier) {
+ return selectOne(new LambdaQueryWrapperX().eq(IotThinkModelFunctionDO::getProductId, productId)
+ .eq(IotThinkModelFunctionDO::getIdentifier, identifier));
}
- default IotThinkModelFunctionDO selectByProductId(Long productId){
- return selectOne(new LambdaQueryWrapperX().eq(IotThinkModelFunctionDO::getProductId, productId));
+ default List selectListByProductId(Long productId) {
+ return selectList(new LambdaQueryWrapperX().eq(IotThinkModelFunctionDO::getProductId, productId));
}
+ default List selectListByProductIdAndType(Long productId, Integer type) {
+ return selectList(new LambdaQueryWrapperX().eq(IotThinkModelFunctionDO::getProductId, productId)
+ .eq(IotThinkModelFunctionDO::getType, type));
+ }
}
\ 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/thinkmodelfunction/IotThinkModelFunctionService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java
index d24ce0031..664df4fb9 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java
@@ -4,6 +4,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThi
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
import jakarta.validation.Valid;
+import java.util.List;
+
/**
* IoT 产品物模型 Service 接口
*
@@ -19,6 +21,14 @@ public interface IotThinkModelFunctionService {
*/
Long createThinkModelFunction(@Valid IotThinkModelFunctionSaveReqVO createReqVO);
+
+ /**
+ * 更新IoT 产品物模型
+ *
+ * @param updateReqVO 更新信息
+ */
+ void updateThinkModelFunction(@Valid IotThinkModelFunctionSaveReqVO updateReqVO);
+
/**
* 删除IoT 产品物模型
*
@@ -27,25 +37,18 @@ public interface IotThinkModelFunctionService {
void deleteThinkModelFunction(Long id);
/**
- * 获得IoT 产品物模型,通过产品Key
+ * 获得IoT 产品物模型
*
- * @param productKey 产品Key
+ * @param id 编号
* @return IoT 产品物模型
*/
- IotThinkModelFunctionDO getThinkModelFunctionByProductKey(String productKey);
+ IotThinkModelFunctionDO getThinkModelFunction(Long id);
/**
- * 获得IoT 产品物模型,通过产品ID
+ * 获得IoT 产品物模型列表
*
- * @param productId 产品ID
- * @return IoT 产品物模型
+ * @param productId 产品编号
+ * @return IoT 产品物模型列表
*/
- IotThinkModelFunctionDO getThinkModelFunctionByProductId(Long productId);
-
- /**
- * 更新IoT 产品物模型
- *
- * @param updateReqVO 更新信息
- */
- void updateThinkModelFunction(@Valid IotThinkModelFunctionSaveReqVO updateReqVO);
+ List getThinkModelFunctionListByProductId(Long productId);
}
\ 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/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
index 6c8afe15f..92ed900cc 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
@@ -1,6 +1,9 @@
package cn.iocoder.yudao.module.iot.service.thinkmodelfunction;
-import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.*;
+import cn.iocoder.yudao.framework.common.validation.Telephone;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
+import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArgument;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArraySpecs;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArrayType;
@@ -9,19 +12,20 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThi
import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert;
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
+import cn.iocoder.yudao.module.iot.enums.product.IotThingModelTypeEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY;
+import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS;
@Slf4j
@@ -32,38 +36,83 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
@Resource
private IotThinkModelFunctionMapper thinkModelFunctionMapper;
- private ObjectMapper objectMapper = new ObjectMapper();
-
@Override
public Long createThinkModelFunction(IotThinkModelFunctionSaveReqVO createReqVO) {
- log.info("创建物模型,参数:{}", createReqVO);
- // 验证 ProductKey 对应的产品物模型是否已存在
- validateThinkModelFunctionNotExistsByProductKey(createReqVO.getProductKey());
+ // 校验功能标识符在同一产品下是否唯一
+ validateIdentifierUnique(createReqVO.getProductId(), createReqVO.getIdentifier());
+
// 转换请求对象为数据对象
IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO);
- // 自动生成属性上报事件和属性设置、获取服务
- generateDefaultEventsAndServices(createReqVO, thinkModelFunction);
+
// 插入数据库
thinkModelFunctionMapper.insert(thinkModelFunction);
+
+ // 如果创建的是属性,需要更新默认的事件和服务
+ if (Objects.equals(createReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
+ generateDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey());
+ }
+
// 返回生成的 ID
return thinkModelFunction.getId();
}
- private void validateThinkModelFunctionNotExistsByProductKey(String productKey) {
- if (thinkModelFunctionMapper.selectByProductKey(productKey) != null) {
- throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY);
+ private void validateIdentifierUnique(Long productId, String identifier) {
+ IotThinkModelFunctionDO existingFunction = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier);
+ if (existingFunction != null) {
+ throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER);
}
}
@Override
- public void deleteThinkModelFunction(Long id) {
- log.info("删除物模型,id:{}", id);
- // 校验物模型是否存在
- validateThinkModelFunctionExists(id);
- // 删除物模型
- thinkModelFunctionMapper.deleteById(id);
+ public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) {
+ // 校验功能是否存在
+ validateThinkModelFunctionExists(updateReqVO.getId());
+
+ // 校验功能标识符是否唯一
+ validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier());
+
+ // 转换请求对象为数据对象
+ IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO);
+
+ // 更新数据库
+ thinkModelFunctionMapper.updateById(thinkModelFunction);
+
+ // 如果更新的是属性,需要更新默认的事件和服务
+ if (Objects.equals(updateReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
+ generateDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey());
+ }
}
+ private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) {
+ IotThinkModelFunctionDO existingFunction = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier);
+ if (existingFunction != null && !existingFunction.getId().equals(id)) {
+ throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER);
+ }
+ }
+
+
+ @Override
+ public void deleteThinkModelFunction(Long id) {
+ // 校验功能是否存在
+ IotThinkModelFunctionDO functionDO = thinkModelFunctionMapper.selectById(id);
+ if (functionDO == null) {
+ throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS);
+ }
+
+ // 删除功能
+ thinkModelFunctionMapper.deleteById(id);
+
+ // 如果删除的是属性,需要更新默认的事件和服务
+ if (Objects.equals(functionDO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
+ generateDefaultEventsAndServices(functionDO.getProductId(), functionDO.getProductKey());
+ }
+ }
+
+ /**
+ * 校验功能是否存在
+ *
+ * @param id 功能编号
+ */
private void validateThinkModelFunctionExists(Long id) {
if (thinkModelFunctionMapper.selectById(id) == null) {
throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS);
@@ -71,114 +120,49 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
}
@Override
- public IotThinkModelFunctionDO getThinkModelFunctionByProductKey(String productKey) {
- return thinkModelFunctionMapper.selectByProductKey(productKey);
+ public IotThinkModelFunctionDO getThinkModelFunction(Long id) {
+ return thinkModelFunctionMapper.selectById(id);
}
@Override
- public IotThinkModelFunctionDO getThinkModelFunctionByProductId(Long productId) {
- return thinkModelFunctionMapper.selectByProductId(productId);
- }
-
- @Override
- public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) {
- log.info("更新物模型,参数:{}", updateReqVO);
- // 校验物模型是否存在
- validateThinkModelFunctionExists(updateReqVO.getId());
- // 校验 ProductKey 是否唯一
- validateProductKeyUnique(updateReqVO.getId(), updateReqVO.getProductKey());
- // 转换请求对象为数据对象
- IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO);
- // 自动生成或更新属性上报事件和属性设置、获取服务
- generateDefaultEventsAndServices(updateReqVO, thinkModelFunction);
- // 更新数据库
- thinkModelFunctionMapper.updateById(thinkModelFunction);
- }
-
- private void validateProductKeyUnique(Long id, String productKey) {
- IotThinkModelFunctionDO existingFunction = thinkModelFunctionMapper.selectByProductKey(productKey);
- if (existingFunction != null && !existingFunction.getId().equals(id)) {
- throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY);
- }
+ public List getThinkModelFunctionListByProductId(Long productId) {
+ return thinkModelFunctionMapper.selectListByProductId(productId);
}
/**
- * 根据属性列表,自动生成属性上报事件和属性设置、获取服务
+ * 生成默认的事件和服务
*/
- private void generateDefaultEventsAndServices(IotThinkModelFunctionSaveReqVO reqVO, IotThinkModelFunctionDO thinkModelFunction) {
- // 获取属性列表
- List properties = reqVO.getProperties();
- if (properties == null) {
- properties = new ArrayList<>();
+ public void generateDefaultEventsAndServices(Long productId, String productKey) {
+ // 获取当前产品的所有属性列表
+ List propertyList = thinkModelFunctionMapper.selectListByProductIdAndType(productId, IotThingModelTypeEnum.PROPERTY.getType());
+
+ // 生成属性上报事件
+ ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList);
+ if (propertyPostEvent != null) {
+ saveOrUpdateEvent(productId, productKey, propertyPostEvent);
}
- // 获取现有的事件和服务
- List existingEvents = reqVO.getEvents() != null ? new ArrayList<>(reqVO.getEvents()) : new ArrayList<>();
- List existingServices = reqVO.getServices() != null ? new ArrayList<>(reqVO.getServices()) : new ArrayList<>();
+ // 生成属性设置服务
+ ThingModelService propertySetService = generatePropertySetService(propertyList);
+ if (propertySetService != null) {
+ saveOrUpdateService(productId, productKey, propertySetService);
+ }
- // 生成或更新属性上报事件
- ThingModelEvent propertyPostEvent = generatePropertyPostEvent(properties);
- updateEventInList(existingEvents, propertyPostEvent);
-
- // 生成或更新属性设置和获取服务
- ThingModelService propertySetService = generatePropertySetService(properties);
- updateServiceInList(existingServices, propertySetService);
-
- ThingModelService propertyGetService = generatePropertyGetService(properties);
- updateServiceInList(existingServices, propertyGetService);
-
- // 更新 thinkModelFunction 对象的 events 和 services 字段
- try {
- thinkModelFunction.setEvents(objectMapper.writeValueAsString(existingEvents));
- thinkModelFunction.setServices(objectMapper.writeValueAsString(existingServices));
- } catch (JsonProcessingException e) {
- throw new RuntimeException("序列化事件和服务时发生错误", e);
+ // 生成属性获取服务
+ ThingModelService propertyGetService = generatePropertyGetService(propertyList);
+ if (propertyGetService != null) {
+ saveOrUpdateService(productId, productKey, propertyGetService);
}
}
- /**
- * 在事件列表中更新或添加事件
- */
- private void updateEventInList(List events, ThingModelEvent newEvent) {
- if (newEvent == null) {
- return;
- }
- for (int i = 0; i < events.size(); i++) {
- ThingModelEvent event = events.get(i);
- if (event.getIdentifier().equals(newEvent.getIdentifier())) {
- // 更新已有的事件
- events.set(i, newEvent);
- return;
- }
- }
- // 如果不存在,则添加新的事件
- events.add(newEvent);
- }
-
- /**
- * 在服务列表中更新或添加服务
- */
- private void updateServiceInList(List services, ThingModelService newService) {
- if (newService == null) {
- return;
- }
- for (int i = 0; i < services.size(); i++) {
- ThingModelService service = services.get(i);
- if (service.getIdentifier().equals(newService.getIdentifier())) {
- // 更新已有的服务
- services.set(i, newService);
- return;
- }
- }
- // 如果不存在,则添加新的服务
- services.add(newService);
- }
-
-
/**
* 生成属性上报事件
*/
- private ThingModelEvent generatePropertyPostEvent(List properties) {
+ private ThingModelEvent generatePropertyPostEvent(List propertyList) {
+ if (propertyList == null || propertyList.isEmpty()) {
+ return null;
+ }
+
ThingModelEvent event = new ThingModelEvent();
event.setIdentifier("post");
event.setName("属性上报");
@@ -188,7 +172,8 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
// 将属性列表转换为事件的输出参数
List outputData = new ArrayList<>();
- for (ThingModelProperty property : properties) {
+ for (IotThinkModelFunctionDO functionDO : propertyList) {
+ ThingModelProperty property = functionDO.getProperty();
ThingModelArgument arg = new ThingModelArgument();
arg.setIdentifier(property.getIdentifier());
arg.setName(property.getName());
@@ -205,9 +190,14 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
/**
* 生成属性设置服务
*/
- private ThingModelService generatePropertySetService(List properties) {
+ private ThingModelService generatePropertySetService(List propertyList) {
+ if (propertyList == null || propertyList.isEmpty()) {
+ return null;
+ }
+
List inputData = new ArrayList<>();
- for (ThingModelProperty property : properties) {
+ for (IotThinkModelFunctionDO functionDO : propertyList) {
+ ThingModelProperty property = functionDO.getProperty();
if ("w".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) {
ThingModelArgument arg = new ThingModelArgument();
arg.setIdentifier(property.getIdentifier());
@@ -239,9 +229,14 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
/**
* 生成属性获取服务
*/
- private ThingModelService generatePropertyGetService(List properties) {
+ private ThingModelService generatePropertyGetService(List propertyList) {
+ if (propertyList == null || propertyList.isEmpty()) {
+ return null;
+ }
+
List outputData = new ArrayList<>();
- for (ThingModelProperty property : properties) {
+ for (IotThinkModelFunctionDO functionDO : propertyList) {
+ ThingModelProperty property = functionDO.getProperty();
if ("r".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) {
ThingModelArgument arg = new ThingModelArgument();
arg.setIdentifier(property.getIdentifier());
@@ -275,10 +270,8 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
ThingModelArrayType arrayType = new ThingModelArrayType();
arrayType.setType("array");
ThingModelArraySpecs arraySpecs = new ThingModelArraySpecs();
- // 不指定数组长度,size 可以为 0 或者省略
ThingModelTextType textType = new ThingModelTextType();
textType.setType("text");
- // 如果有需要,可以设置 TextType 的 specs,如长度限制
arraySpecs.setItem(textType);
arrayType.setSpecs(arraySpecs);
@@ -289,4 +282,54 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
return service;
}
+
+ /**
+ * 保存或更新事件
+ */
+ private void saveOrUpdateEvent(Long productId, String productKey, ThingModelEvent event) {
+ // 检查是否已存在相同的事件
+ IotThinkModelFunctionDO existingEvent = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, event.getIdentifier());
+ IotThinkModelFunctionDO functionDO = new IotThinkModelFunctionDO();
+ functionDO.setProductId(productId);
+ functionDO.setProductKey(productKey);
+ functionDO.setIdentifier(event.getIdentifier());
+ functionDO.setName(event.getName());
+ functionDO.setDescription(event.getDescription());
+ functionDO.setType(IotThingModelTypeEnum.EVENT.getType());
+ functionDO.setEvent(event);
+
+ if (existingEvent != null) {
+ // 更新事件
+ functionDO.setId(existingEvent.getId());
+ thinkModelFunctionMapper.updateById(functionDO);
+ } else {
+ // 创建新的事件
+ thinkModelFunctionMapper.insert(functionDO);
+ }
+ }
+
+ /**
+ * 保存或更新事服务
+ */
+ private void saveOrUpdateService(Long productId, String productKey, ThingModelService service) {
+ // 检查是否已存在相同的服务
+ IotThinkModelFunctionDO existingService = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, service.getIdentifier());
+ IotThinkModelFunctionDO functionDO = new IotThinkModelFunctionDO();
+ functionDO.setProductId(productId);
+ functionDO.setProductKey(productKey);
+ functionDO.setIdentifier(service.getIdentifier());
+ functionDO.setName(service.getName());
+ functionDO.setDescription(service.getDescription());
+ functionDO.setType(IotThingModelTypeEnum.SERVICE.getType());
+ functionDO.setService(service);
+
+ if (existingService != null) {
+ // 更新服务
+ functionDO.setId(existingService.getId());
+ thinkModelFunctionMapper.updateById(functionDO);
+ } else {
+ // 创建新的服务
+ thinkModelFunctionMapper.insert(functionDO);
+ }
+ }
}
From c0e2bdbdd48c4f8554724776dcb9149294c433a7 Mon Sep 17 00:00:00 2001
From: YunaiV
Date: Mon, 16 Sep 2024 20:00:47 +0800
Subject: [PATCH 20/31] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?=
=?UTF-8?q?=E5=AE=A1=E3=80=91IOT=EF=BC=9A=E7=89=A9=E6=A8=A1=E5=9E=8B?=
=?UTF-8?q?=E7=9A=84=20review?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../core/db/TenantDatabaseInterceptor.java | 2 +-
.../IotThinkModelFunctionMapper.java | 12 ++--
.../IotThinkModelFunctionService.java | 14 ++---
.../IotThinkModelFunctionServiceImpl.java | 63 ++++++++++---------
4 files changed, 46 insertions(+), 45 deletions(-)
diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java
index 8ea1a96b8..e220f8bcf 100644
--- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java
+++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java
@@ -13,7 +13,7 @@ import java.util.Set;
/**
* 基于 MyBatis Plus 多租户的功能,实现 DB 层面的多租户的功能
*
- * @author 芋道源码
+ * @author
*/
public class TenantDatabaseInterceptor implements TenantLineHandler {
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
index dbd4cb359..214d5c167 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
@@ -1,7 +1,6 @@
package cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
-import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
import org.apache.ibatis.annotations.Mapper;
@@ -16,16 +15,17 @@ import java.util.List;
public interface IotThinkModelFunctionMapper extends BaseMapperX {
default IotThinkModelFunctionDO selectByProductIdAndIdentifier(Long productId, String identifier) {
- return selectOne(new LambdaQueryWrapperX().eq(IotThinkModelFunctionDO::getProductId, productId)
- .eq(IotThinkModelFunctionDO::getIdentifier, identifier));
+ return selectOne(IotThinkModelFunctionDO::getProductId, productId,
+ IotThinkModelFunctionDO::getIdentifier, identifier);
}
default List selectListByProductId(Long productId) {
- return selectList(new LambdaQueryWrapperX().eq(IotThinkModelFunctionDO::getProductId, productId));
+ return selectList(IotThinkModelFunctionDO::getProductId, productId);
}
default List selectListByProductIdAndType(Long productId, Integer type) {
- return selectList(new LambdaQueryWrapperX().eq(IotThinkModelFunctionDO::getProductId, productId)
- .eq(IotThinkModelFunctionDO::getType, type));
+ return selectList(IotThinkModelFunctionDO::getProductId, productId,
+ IotThinkModelFunctionDO::getType, type);
}
+
}
\ 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/thinkmodelfunction/IotThinkModelFunctionService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java
index 664df4fb9..e2a5ad38d 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java
@@ -14,7 +14,7 @@ import java.util.List;
public interface IotThinkModelFunctionService {
/**
- * 创建IoT 产品物模型
+ * 创建产品物模型
*
* @param createReqVO 创建信息
* @return 编号
@@ -23,32 +23,32 @@ public interface IotThinkModelFunctionService {
/**
- * 更新IoT 产品物模型
+ * 更新产品物模型
*
* @param updateReqVO 更新信息
*/
void updateThinkModelFunction(@Valid IotThinkModelFunctionSaveReqVO updateReqVO);
/**
- * 删除IoT 产品物模型
+ * 删除产品物模型
*
* @param id 编号
*/
void deleteThinkModelFunction(Long id);
/**
- * 获得IoT 产品物模型
+ * 获得产品物模型
*
* @param id 编号
- * @return IoT 产品物模型
+ * @return 产品物模型
*/
IotThinkModelFunctionDO getThinkModelFunction(Long id);
/**
- * 获得IoT 产品物模型列表
+ * 获得产品物模型列表
*
* @param productId 产品编号
- * @return IoT 产品物模型列表
+ * @return 产品物模型列表
*/
List getThinkModelFunctionListByProductId(Long productId);
}
\ 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/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
index 92ed900cc..bc90cff24 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
@@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.iot.service.thinkmodelfunction;
-import cn.iocoder.yudao.framework.common.validation.Telephone;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
@@ -16,7 +15,6 @@ import cn.iocoder.yudao.module.iot.enums.product.IotThingModelTypeEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.util.ArrayList;
@@ -28,81 +26,83 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS;
-@Slf4j
+/**
+ * IoT 产品物模型 Service 实现类
+ *
+ * @author 芋道源码
+ */
@Service
@Validated
+@Slf4j
public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionService {
@Resource
private IotThinkModelFunctionMapper thinkModelFunctionMapper;
@Override
+ // TODO @haohao:事务
public Long createThinkModelFunction(IotThinkModelFunctionSaveReqVO createReqVO) {
- // 校验功能标识符在同一产品下是否唯一
+ // 1. 校验功能标识符在同一产品下是否唯一
validateIdentifierUnique(createReqVO.getProductId(), createReqVO.getIdentifier());
- // 转换请求对象为数据对象
- IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO);
+ // 2. 插入数据库
+ IotThinkModelFunctionDO function = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO);
+ thinkModelFunctionMapper.insert(function);
- // 插入数据库
- thinkModelFunctionMapper.insert(thinkModelFunction);
-
- // 如果创建的是属性,需要更新默认的事件和服务
+ // 3. 如果创建的是属性,需要更新默认的事件和服务
if (Objects.equals(createReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
+ // TODO @haohao:最好使用 createDefaultEventsAndServices。原因是:generate 更多在目前项目里,是创建对象,不涉及到 insert db。
generateDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey());
}
-
- // 返回生成的 ID
- return thinkModelFunction.getId();
+ return function.getId();
}
private void validateIdentifierUnique(Long productId, String identifier) {
- IotThinkModelFunctionDO existingFunction = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier);
- if (existingFunction != null) {
+ IotThinkModelFunctionDO function = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier);
+ if (function != null) {
throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER);
}
}
@Override
+ // TODO @haohao:事务
public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) {
- // 校验功能是否存在
+ // 1.1 校验功能是否存在
validateThinkModelFunctionExists(updateReqVO.getId());
-
- // 校验功能标识符是否唯一
+ // 1.2 校验功能标识符是否唯一
validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier());
- // 转换请求对象为数据对象
+ // 2. 更新数据库
IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO);
-
- // 更新数据库
thinkModelFunctionMapper.updateById(thinkModelFunction);
- // 如果更新的是属性,需要更新默认的事件和服务
+ // 3. 如果更新的是属性,需要更新默认的事件和服务
if (Objects.equals(updateReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
generateDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey());
}
}
private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) {
- IotThinkModelFunctionDO existingFunction = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier);
- if (existingFunction != null && !existingFunction.getId().equals(id)) {
+ IotThinkModelFunctionDO function = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier);
+ // TODO !function.getId().equals(id) 使用 ObjectUtil.notEquals 。逻辑里,尽量避免 ! 取反。用不等于会比 ! 更容易理解
+ if (function != null && !function.getId().equals(id)) {
throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER);
}
}
-
@Override
+ // TODO @haohao:事务
public void deleteThinkModelFunction(Long id) {
- // 校验功能是否存在
+ // 1. 校验功能是否存在
IotThinkModelFunctionDO functionDO = thinkModelFunctionMapper.selectById(id);
if (functionDO == null) {
throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS);
}
- // 删除功能
+ // 2. 删除功能
thinkModelFunctionMapper.deleteById(id);
- // 如果删除的是属性,需要更新默认的事件和服务
+ // 3. 如果删除的是属性,需要更新默认的事件和服务
if (Objects.equals(functionDO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
generateDefaultEventsAndServices(functionDO.getProductId(), functionDO.getProductKey());
}
@@ -159,10 +159,12 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
* 生成属性上报事件
*/
private ThingModelEvent generatePropertyPostEvent(List propertyList) {
+ // TODO @haohao:用 CollUtil.isNotEmpty 会更容易哈
if (propertyList == null || propertyList.isEmpty()) {
return null;
}
+ // TODO @haohao:可以考虑链式调用,简化整个方法的长度;然后,把相同类型的户型,尽量再放同一行,看起来轻松点;其它类似的,也可以试试看哈
ThingModelEvent event = new ThingModelEvent();
event.setIdentifier("post");
event.setName("属性上报");
@@ -183,7 +185,6 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
outputData.add(arg);
}
event.setOutputData(outputData);
-
return event;
}
@@ -222,7 +223,6 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
service.setInputData(inputData);
// 属性设置服务一般不需要输出参数
service.setOutputData(new ArrayList<>());
-
return service;
}
@@ -237,6 +237,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
List outputData = new ArrayList<>();
for (IotThinkModelFunctionDO functionDO : propertyList) {
ThingModelProperty property = functionDO.getProperty();
+ // TODO @haohao:r、rw 是不是枚举起来
if ("r".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) {
ThingModelArgument arg = new ThingModelArgument();
arg.setIdentifier(property.getIdentifier());
@@ -279,7 +280,6 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
service.setInputData(Collections.singletonList(inputArg));
service.setOutputData(outputData);
-
return service;
}
@@ -298,6 +298,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
functionDO.setType(IotThingModelTypeEnum.EVENT.getType());
functionDO.setEvent(event);
+ // TODO @haohao:会不会存在删除的情况哈?另外,项目里有 diffList 方法,看看是不是可以方便的,适合这个场景。具体怎么用,可以全局搜
if (existingEvent != null) {
// 更新事件
functionDO.setId(existingEvent.getId());
From edc6a8ad4a77b122b88da4db31525aea4ae3d369 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com>
Date: Mon, 16 Sep 2024 21:42:10 +0800
Subject: [PATCH 21/31] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9AIOT=20?=
=?UTF-8?q?=E7=89=A9=E6=A8=A1=E5=9E=8B=E6=8E=A5=E5=8F=A3=E5=A2=9E=E5=8A=A0?=
=?UTF-8?q?=E4=BA=8B=E7=89=A9=EF=BC=8C=E4=BC=98=E5=8C=96=E5=88=9B=E5=BB=BA?=
=?UTF-8?q?=E9=BB=98=E8=AE=A4=E7=9A=84=E4=BA=8B=E4=BB=B6=E5=92=8C=E6=9C=8D?=
=?UTF-8?q?=E5=8A=A1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../module/iot/enums/ErrorCodeConstants.java | 3 +
.../iot/enums/product/IotAccessModeEnum.java | 25 ++
.../IotThinkModelFunctionController.http | 9 +-
.../IotThinkModelFunctionMapper.java | 6 +
.../iot/emq/service/EmqxServiceImpl.java | 2 +-
.../IotThinkModelFunctionServiceImpl.java | 294 ++++++++++--------
6 files changed, 212 insertions(+), 127 deletions(-)
create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
index e586d4535..7677ef89d 100644
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
+++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
@@ -18,4 +18,7 @@ public interface ErrorCodeConstants {
ErrorCode THINK_MODEL_FUNCTION_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在");
ErrorCode THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY = new ErrorCode(1_050_002_001, "ProductKey 对应的产品物模型已存在");
ErrorCode THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER = new ErrorCode(1_050_002_002, "产品物模型标识已存在");
+
+ // ========== IoT 设备 1-050-003-000 ============
+ ErrorCode DEVICE_NOT_EXISTS = new ErrorCode(1_050_003_000, "设备不存在");
}
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java
new file mode 100644
index 000000000..630240b86
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java
@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.iot.enums.product;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * IOT 访问方式枚举类
+ *
+ * @author ahh
+ */
+@AllArgsConstructor
+@Getter
+public enum IotAccessModeEnum {
+
+ READ("r"),
+ WRITE("w"),
+ READ_WRITE("rw");
+
+ private final String mode;
+
+ public String getMode() {
+ return mode;
+ }
+
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
index febf01014..6b9032fc6 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
@@ -37,7 +37,7 @@ tenant-id: {{adminTenentId}}
Authorization: Bearer {{token}}
{
- "id": 3,
+ "id": 1,
"productId": 1001,
"productKey": "smart-sensor-001",
"identifier": "Temperature",
@@ -62,8 +62,13 @@ Authorization: Bearer {{token}}
}
}
+### 请求 /iot/think-model-function/delete 接口 => 成功
+DELETE {{baseUrl}}/iot/think-model-function/delete?id=1
+tenant-id: {{adminTenentId}}
+Authorization: Bearer {{token}}
+
### 请求 /iot/think-model-function/get 接口 => 成功
-GET {{baseUrl}}/iot/think-model-function/get?id=3
+GET {{baseUrl}}/iot/think-model-function/get?id=4
tenant-id: {{adminTenentId}}
Authorization: Bearer {{token}}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
index 214d5c167..8c29c7eab 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
import org.apache.ibatis.annotations.Mapper;
@@ -28,4 +29,9 @@ public interface IotThinkModelFunctionMapper extends BaseMapperX selectListByProductIdAndTypes(Long productId, List list) {
+ return selectList(new LambdaQueryWrapperX()
+ .eq(IotThinkModelFunctionDO::getProductId, productId)
+ .in(IotThinkModelFunctionDO::getType, list));
+ }
}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java
index 0f1a53cd0..0c1a87f7f 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java
@@ -30,7 +30,7 @@ public class EmqxServiceImpl implements EmqxService {
public void subscribe(MqttClient client) {
try {
// 订阅默认主题,可以根据需要修改
- client.subscribe("$share/yudao/+/+/#", 1);
+// client.subscribe("$share/yudao/+/+/#", 1);
log.info("订阅默认主题成功");
} catch (Exception e) {
log.error("订阅默认主题失败", e);
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
index bc90cff24..9d5d1e650 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
@@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.iot.service.thinkmodelfunction;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
@@ -11,18 +13,19 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThi
import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert;
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper;
+import cn.iocoder.yudao.module.iot.enums.product.IotAccessModeEnum;
import cn.iocoder.yudao.module.iot.enums.product.IotThingModelTypeEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
+import java.util.*;
+import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS;
@@ -40,7 +43,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
private IotThinkModelFunctionMapper thinkModelFunctionMapper;
@Override
- // TODO @haohao:事务
+ @Transactional(rollbackFor = Exception.class)
public Long createThinkModelFunction(IotThinkModelFunctionSaveReqVO createReqVO) {
// 1. 校验功能标识符在同一产品下是否唯一
validateIdentifierUnique(createReqVO.getProductId(), createReqVO.getIdentifier());
@@ -51,8 +54,11 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
// 3. 如果创建的是属性,需要更新默认的事件和服务
if (Objects.equals(createReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
- // TODO @haohao:最好使用 createDefaultEventsAndServices。原因是:generate 更多在目前项目里,是创建对象,不涉及到 insert db。
- generateDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey());
+ // 获取当前属性列表,并添加新插入的属性
+ List propertyList = thinkModelFunctionMapper
+ .selectListByProductIdAndType(createReqVO.getProductId(), IotThingModelTypeEnum.PROPERTY.getType());
+ propertyList.add(function);
+ createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey(), propertyList);
}
return function.getId();
}
@@ -65,33 +71,41 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
}
@Override
- // TODO @haohao:事务
+ @Transactional(rollbackFor = Exception.class)
public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) {
- // 1.1 校验功能是否存在
+ // 1. 校验功能是否存在
validateThinkModelFunctionExists(updateReqVO.getId());
- // 1.2 校验功能标识符是否唯一
+ // 2. 校验功能标识符是否唯一
validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier());
- // 2. 更新数据库
+ // 3. 更新数据库
IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO);
thinkModelFunctionMapper.updateById(thinkModelFunction);
- // 3. 如果更新的是属性,需要更新默认的事件和服务
+ // 4. 如果更新的是属性,需要更新默认的事件和服务
if (Objects.equals(updateReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
- generateDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey());
+ // 获取当前属性列表,更新其中的属性
+ List propertyList = thinkModelFunctionMapper
+ .selectListByProductIdAndType(updateReqVO.getProductId(), IotThingModelTypeEnum.PROPERTY.getType());
+ for (int i = 0; i < propertyList.size(); i++) {
+ if (propertyList.get(i).getId().equals(thinkModelFunction.getId())) {
+ propertyList.set(i, thinkModelFunction);
+ break;
+ }
+ }
+ createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey(), propertyList);
}
}
private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) {
IotThinkModelFunctionDO function = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier);
- // TODO !function.getId().equals(id) 使用 ObjectUtil.notEquals 。逻辑里,尽量避免 ! 取反。用不等于会比 ! 更容易理解
- if (function != null && !function.getId().equals(id)) {
+ if (function != null && ObjectUtil.notEqual(function.getId(), id)) {
throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER);
}
}
@Override
- // TODO @haohao:事务
+ @Transactional(rollbackFor = Exception.class)
public void deleteThinkModelFunction(Long id) {
// 1. 校验功能是否存在
IotThinkModelFunctionDO functionDO = thinkModelFunctionMapper.selectById(id);
@@ -104,7 +118,11 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
// 3. 如果删除的是属性,需要更新默认的事件和服务
if (Objects.equals(functionDO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
- generateDefaultEventsAndServices(functionDO.getProductId(), functionDO.getProductKey());
+ // 获取当前属性列表,移除已删除的属性
+ List propertyList = thinkModelFunctionMapper
+ .selectListByProductIdAndType(functionDO.getProductId(), IotThingModelTypeEnum.PROPERTY.getType());
+ propertyList.removeIf(property -> property.getId().equals(id));
+ createDefaultEventsAndServices(functionDO.getProductId(), functionDO.getProductKey(), propertyList);
}
}
@@ -130,58 +148,137 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
}
/**
- * 生成默认的事件和服务
+ * 创建默认的事件和服务
*/
- public void generateDefaultEventsAndServices(Long productId, String productKey) {
- // 获取当前产品的所有属性列表
- List propertyList = thinkModelFunctionMapper.selectListByProductIdAndType(productId, IotThingModelTypeEnum.PROPERTY.getType());
+ public void createDefaultEventsAndServices(Long productId, String productKey, List propertyList) {
+ // 1. 生成新的事件和服务列表
+ List newFunctionList = new ArrayList<>();
// 生成属性上报事件
ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList);
if (propertyPostEvent != null) {
- saveOrUpdateEvent(productId, productKey, propertyPostEvent);
+ IotThinkModelFunctionDO eventFunction = buildEventFunctionDO(productId, productKey, propertyPostEvent);
+ newFunctionList.add(eventFunction);
}
// 生成属性设置服务
ThingModelService propertySetService = generatePropertySetService(propertyList);
if (propertySetService != null) {
- saveOrUpdateService(productId, productKey, propertySetService);
+ IotThinkModelFunctionDO setServiceFunction = buildServiceFunctionDO(productId, productKey, propertySetService);
+ newFunctionList.add(setServiceFunction);
}
// 生成属性获取服务
ThingModelService propertyGetService = generatePropertyGetService(propertyList);
if (propertyGetService != null) {
- saveOrUpdateService(productId, productKey, propertyGetService);
+ IotThinkModelFunctionDO getServiceFunction = buildServiceFunctionDO(productId, productKey, propertyGetService);
+ newFunctionList.add(getServiceFunction);
}
+
+ // 2. 获取数据库中的旧事件和服务列表
+ List oldFunctionList = thinkModelFunctionMapper.selectListByProductIdAndTypes(
+ productId,
+ Arrays.asList(IotThingModelTypeEnum.EVENT.getType(), IotThingModelTypeEnum.SERVICE.getType())
+ );
+
+ // 3. 使用 diffList 方法比较新旧列表
+ List> diffResult = diffList(
+ oldFunctionList,
+ newFunctionList,
+ (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); // 需要删除的
+
+ // 4. 批量执行数据库操作
+ if (CollUtil.isNotEmpty(createList)) {
+ thinkModelFunctionMapper.insertBatch(createList);
+ }
+ if (CollUtil.isNotEmpty(updateList)) {
+ for (IotThinkModelFunctionDO updateFunc : updateList) {
+ // 设置 ID,以便更新
+ IotThinkModelFunctionDO oldFunc = findFunctionByIdentifierAndType(
+ oldFunctionList, updateFunc.getIdentifier(), updateFunc.getType()
+ );
+ if (oldFunc != null) {
+ updateFunc.setId(oldFunc.getId());
+ thinkModelFunctionMapper.updateById(updateFunc);
+ }
+ }
+ }
+ if (CollUtil.isNotEmpty(deleteList)) {
+ List idsToDelete = deleteList.stream().map(IotThinkModelFunctionDO::getId).collect(Collectors.toList());
+ thinkModelFunctionMapper.deleteByIds(idsToDelete);
+ }
+ }
+
+ /**
+ * 根据标识符和类型查找功能对象
+ */
+ private IotThinkModelFunctionDO findFunctionByIdentifierAndType(List functionList,
+ String identifier, Integer type) {
+ return functionList.stream()
+ .filter(func -> Objects.equals(func.getIdentifier(), identifier) && Objects.equals(func.getType(), type))
+ .findFirst()
+ .orElse(null);
+ }
+
+ /**
+ * 构建事件功能对象
+ */
+ private IotThinkModelFunctionDO buildEventFunctionDO(Long productId, String productKey, ThingModelEvent event) {
+ return new IotThinkModelFunctionDO()
+ .setProductId(productId)
+ .setProductKey(productKey)
+ .setIdentifier(event.getIdentifier())
+ .setName(event.getName())
+ .setDescription(event.getDescription())
+ .setType(IotThingModelTypeEnum.EVENT.getType())
+ .setEvent(event);
+ }
+
+ /**
+ * 构建服务功能对象
+ */
+ private IotThinkModelFunctionDO buildServiceFunctionDO(Long productId, String productKey, ThingModelService service) {
+ return new IotThinkModelFunctionDO()
+ .setProductId(productId)
+ .setProductKey(productKey)
+ .setIdentifier(service.getIdentifier())
+ .setName(service.getName())
+ .setDescription(service.getDescription())
+ .setType(IotThingModelTypeEnum.SERVICE.getType())
+ .setService(service);
}
/**
* 生成属性上报事件
*/
private ThingModelEvent generatePropertyPostEvent(List propertyList) {
- // TODO @haohao:用 CollUtil.isNotEmpty 会更容易哈
- if (propertyList == null || propertyList.isEmpty()) {
+ if (CollUtil.isEmpty(propertyList)) {
return null;
}
- // TODO @haohao:可以考虑链式调用,简化整个方法的长度;然后,把相同类型的户型,尽量再放同一行,看起来轻松点;其它类似的,也可以试试看哈
- ThingModelEvent event = new ThingModelEvent();
- event.setIdentifier("post");
- event.setName("属性上报");
- event.setType("info");
- event.setDescription("属性上报事件");
- event.setMethod("thing.event.property.post");
+ ThingModelEvent event = new ThingModelEvent()
+ .setIdentifier("post")
+ .setName("属性上报")
+ .setType("info")
+ .setDescription("属性上报事件")
+ .setMethod("thing.event.property.post");
// 将属性列表转换为事件的输出参数
List outputData = new ArrayList<>();
for (IotThinkModelFunctionDO functionDO : propertyList) {
ThingModelProperty property = functionDO.getProperty();
- ThingModelArgument arg = new ThingModelArgument();
- arg.setIdentifier(property.getIdentifier());
- arg.setName(property.getName());
- arg.setDataType(property.getDataType());
- arg.setDescription(property.getDescription());
- arg.setDirection("output"); // 设置为输出参数
+ ThingModelArgument arg = new ThingModelArgument()
+ .setIdentifier(property.getIdentifier())
+ .setName(property.getName())
+ .setDataType(property.getDataType())
+ .setDescription(property.getDescription())
+ .setDirection("output"); // 设置为输出参数
outputData.add(arg);
}
event.setOutputData(outputData);
@@ -199,13 +296,13 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
List inputData = new ArrayList<>();
for (IotThinkModelFunctionDO functionDO : propertyList) {
ThingModelProperty property = functionDO.getProperty();
- if ("w".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) {
- ThingModelArgument arg = new ThingModelArgument();
- arg.setIdentifier(property.getIdentifier());
- arg.setName(property.getName());
- arg.setDataType(property.getDataType());
- arg.setDescription(property.getDescription());
- arg.setDirection("input"); // 设置为输入参数
+ if (IotAccessModeEnum.WRITE.getMode().equals(property.getAccessMode()) || IotAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) {
+ ThingModelArgument arg = new ThingModelArgument()
+ .setIdentifier(property.getIdentifier())
+ .setName(property.getName())
+ .setDataType(property.getDataType())
+ .setDescription(property.getDescription())
+ .setDirection("input"); // 设置为输入参数
inputData.add(arg);
}
}
@@ -214,16 +311,16 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
return null;
}
- ThingModelService service = new ThingModelService();
- service.setIdentifier("set");
- service.setName("属性设置");
- service.setCallType("async");
- service.setDescription("属性设置服务");
- service.setMethod("thing.service.property.set");
- service.setInputData(inputData);
// 属性设置服务一般不需要输出参数
- service.setOutputData(new ArrayList<>());
- return service;
+ return new ThingModelService()
+ .setIdentifier("set")
+ .setName("属性设置")
+ .setCallType("async")
+ .setDescription("属性设置服务")
+ .setMethod("thing.service.property.set")
+ .setInputData(inputData)
+ // 属性设置服务一般不需要输出参数
+ .setOutputData(new ArrayList<>());
}
/**
@@ -237,14 +334,13 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
List outputData = new ArrayList<>();
for (IotThinkModelFunctionDO functionDO : propertyList) {
ThingModelProperty property = functionDO.getProperty();
- // TODO @haohao:r、rw 是不是枚举起来
- if ("r".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) {
- ThingModelArgument arg = new ThingModelArgument();
- arg.setIdentifier(property.getIdentifier());
- arg.setName(property.getName());
- arg.setDataType(property.getDataType());
- arg.setDescription(property.getDescription());
- arg.setDirection("output"); // 设置为输出参数
+ if (IotAccessModeEnum.READ.getMode().equals(property.getAccessMode()) || IotAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) {
+ ThingModelArgument arg = new ThingModelArgument()
+ .setIdentifier(property.getIdentifier())
+ .setName(property.getName())
+ .setDataType(property.getDataType())
+ .setDescription(property.getDescription())
+ .setDirection("output"); // 设置为输出参数
outputData.add(arg);
}
}
@@ -253,19 +349,19 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
return null;
}
- ThingModelService service = new ThingModelService();
- service.setIdentifier("get");
- service.setName("属性获取");
- service.setCallType("async");
- service.setDescription("属性获取服务");
- service.setMethod("thing.service.property.get");
+ ThingModelService service = new ThingModelService()
+ .setIdentifier("get")
+ .setName("属性获取")
+ .setCallType("async")
+ .setDescription("属性获取服务")
+ .setMethod("thing.service.property.get");
// 定义输入参数:属性标识符列表
- ThingModelArgument inputArg = new ThingModelArgument();
- inputArg.setIdentifier("properties");
- inputArg.setName("属性标识符列表");
- inputArg.setDescription("需要获取的属性标识符列表");
- inputArg.setDirection("input"); // 设置为输入参数
+ ThingModelArgument inputArg = new ThingModelArgument()
+ .setIdentifier("properties")
+ .setName("属性标识符列表")
+ .setDescription("需要获取的属性标识符列表")
+ .setDirection("input"); // 设置为输入参数
// 创建数组类型,元素类型为文本类型(字符串)
ThingModelArrayType arrayType = new ThingModelArrayType();
@@ -283,54 +379,4 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
return service;
}
- /**
- * 保存或更新事件
- */
- private void saveOrUpdateEvent(Long productId, String productKey, ThingModelEvent event) {
- // 检查是否已存在相同的事件
- IotThinkModelFunctionDO existingEvent = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, event.getIdentifier());
- IotThinkModelFunctionDO functionDO = new IotThinkModelFunctionDO();
- functionDO.setProductId(productId);
- functionDO.setProductKey(productKey);
- functionDO.setIdentifier(event.getIdentifier());
- functionDO.setName(event.getName());
- functionDO.setDescription(event.getDescription());
- functionDO.setType(IotThingModelTypeEnum.EVENT.getType());
- functionDO.setEvent(event);
-
- // TODO @haohao:会不会存在删除的情况哈?另外,项目里有 diffList 方法,看看是不是可以方便的,适合这个场景。具体怎么用,可以全局搜
- if (existingEvent != null) {
- // 更新事件
- functionDO.setId(existingEvent.getId());
- thinkModelFunctionMapper.updateById(functionDO);
- } else {
- // 创建新的事件
- thinkModelFunctionMapper.insert(functionDO);
- }
- }
-
- /**
- * 保存或更新事服务
- */
- private void saveOrUpdateService(Long productId, String productKey, ThingModelService service) {
- // 检查是否已存在相同的服务
- IotThinkModelFunctionDO existingService = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, service.getIdentifier());
- IotThinkModelFunctionDO functionDO = new IotThinkModelFunctionDO();
- functionDO.setProductId(productId);
- functionDO.setProductKey(productKey);
- functionDO.setIdentifier(service.getIdentifier());
- functionDO.setName(service.getName());
- functionDO.setDescription(service.getDescription());
- functionDO.setType(IotThingModelTypeEnum.SERVICE.getType());
- functionDO.setService(service);
-
- if (existingService != null) {
- // 更新服务
- functionDO.setId(existingService.getId());
- thinkModelFunctionMapper.updateById(functionDO);
- } else {
- // 创建新的服务
- thinkModelFunctionMapper.insert(functionDO);
- }
- }
}
From e4ef1c81902b3bfae136ef70120be092005bc538 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com>
Date: Mon, 16 Sep 2024 21:54:12 +0800
Subject: [PATCH 22/31] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9AIOT=20?=
=?UTF-8?q?=E7=89=A9=E6=A8=A1=E5=9E=8B=E6=8E=A5=E5=8F=A3=E6=8E=A5=E5=8F=A3?=
=?UTF-8?q?=E4=BC=98=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../thinkmodelfunction/IotThinkModelFunctionMapper.java | 5 +++--
.../thinkmodelfunction/IotThinkModelFunctionServiceImpl.java | 5 +++--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
index 8c29c7eab..cd1327461 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
@@ -29,9 +29,10 @@ public interface IotThinkModelFunctionMapper extends BaseMapperX selectListByProductIdAndTypes(Long productId, List list) {
+ default List selectListByProductIdAndIdentifiersAndTypes(Long productId, List list, List list1){
return selectList(new LambdaQueryWrapperX()
.eq(IotThinkModelFunctionDO::getProductId, productId)
- .in(IotThinkModelFunctionDO::getType, list));
+ .in(IotThinkModelFunctionDO::getIdentifier, list)
+ .in(IotThinkModelFunctionDO::getType, list1));
}
}
\ 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/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
index 9d5d1e650..7d4c9ef04 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
@@ -175,9 +175,10 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
newFunctionList.add(getServiceFunction);
}
- // 2. 获取数据库中的旧事件和服务列表
- List oldFunctionList = thinkModelFunctionMapper.selectListByProductIdAndTypes(
+ // 2. 获取数据库中的默认的旧事件和服务列表
+ List oldFunctionList = thinkModelFunctionMapper.selectListByProductIdAndIdentifiersAndTypes(
productId,
+ Arrays.asList("post", "set", "get"),
Arrays.asList(IotThingModelTypeEnum.EVENT.getType(), IotThingModelTypeEnum.SERVICE.getType())
);
From 9658ed1a0d93dd492e3551038c105f540ccda2aa Mon Sep 17 00:00:00 2001
From: YunaiV
Date: Tue, 17 Sep 2024 10:27:33 +0800
Subject: [PATCH 23/31] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?=
=?UTF-8?q?=E5=AE=A1=E3=80=91IOT=EF=BC=9A=E7=89=A9=E6=A8=A1=E5=9E=8B?=
=?UTF-8?q?=E7=9A=84=20review?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../module/iot/enums/ErrorCodeConstants.java | 1 +
.../iot/enums/product/IotAccessModeEnum.java | 6 +---
.../IotThinkModelFunctionMapper.java | 9 ++++--
.../IotThinkModelFunctionServiceImpl.java | 30 +++++++++----------
4 files changed, 22 insertions(+), 24 deletions(-)
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
index 7677ef89d..790bbb40c 100644
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
+++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
@@ -21,4 +21,5 @@ public interface ErrorCodeConstants {
// ========== IoT 设备 1-050-003-000 ============
ErrorCode DEVICE_NOT_EXISTS = new ErrorCode(1_050_003_000, "设备不存在");
+
}
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java
index 630240b86..64ece99ca 100644
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java
+++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java
@@ -10,7 +10,7 @@ import lombok.Getter;
*/
@AllArgsConstructor
@Getter
-public enum IotAccessModeEnum {
+public enum IotAccessModeEnum {
READ("r"),
WRITE("w"),
@@ -18,8 +18,4 @@ public enum IotAccessModeEnum {
private final String mode;
- public String getMode() {
- return mode;
- }
-
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
index cd1327461..7227a0f26 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java
@@ -29,10 +29,13 @@ public interface IotThinkModelFunctionMapper extends BaseMapperX selectListByProductIdAndIdentifiersAndTypes(Long productId, List list, List list1){
+ default List selectListByProductIdAndIdentifiersAndTypes(Long productId,
+ List identifiers,
+ List types){
return selectList(new LambdaQueryWrapperX()
.eq(IotThinkModelFunctionDO::getProductId, productId)
- .in(IotThinkModelFunctionDO::getIdentifier, list)
- .in(IotThinkModelFunctionDO::getType, list1));
+ .in(IotThinkModelFunctionDO::getIdentifier, identifiers)
+ .in(IotThinkModelFunctionDO::getType, types));
}
+
}
\ 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/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
index 7d4c9ef04..0edb96db2 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
@@ -55,6 +55,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
// 3. 如果创建的是属性,需要更新默认的事件和服务
if (Objects.equals(createReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
// 获取当前属性列表,并添加新插入的属性
+ // TODO @haohao:是不是插入后,查询已经包含了 function
List propertyList = thinkModelFunctionMapper
.selectListByProductIdAndType(createReqVO.getProductId(), IotThingModelTypeEnum.PROPERTY.getType());
propertyList.add(function);
@@ -85,6 +86,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
// 4. 如果更新的是属性,需要更新默认的事件和服务
if (Objects.equals(updateReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
// 获取当前属性列表,更新其中的属性
+ // TODO @haohao:是不是更新后,查询出来的,已经是最新的 thinkModelFunction
List propertyList = thinkModelFunctionMapper
.selectListByProductIdAndType(updateReqVO.getProductId(), IotThingModelTypeEnum.PROPERTY.getType());
for (int i = 0; i < propertyList.size(); i++) {
@@ -119,6 +121,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
// 3. 如果删除的是属性,需要更新默认的事件和服务
if (Objects.equals(functionDO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
// 获取当前属性列表,移除已删除的属性
+ // TODO @haohao:是不是删除后,已经没有 id 对应的记录啦?
List propertyList = thinkModelFunctionMapper
.selectListByProductIdAndType(functionDO.getProductId(), IotThingModelTypeEnum.PROPERTY.getType());
propertyList.removeIf(property -> property.getId().equals(id));
@@ -153,21 +156,18 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
public void createDefaultEventsAndServices(Long productId, String productKey, List propertyList) {
// 1. 生成新的事件和服务列表
List newFunctionList = new ArrayList<>();
-
// 生成属性上报事件
ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList);
if (propertyPostEvent != null) {
IotThinkModelFunctionDO eventFunction = buildEventFunctionDO(productId, productKey, propertyPostEvent);
newFunctionList.add(eventFunction);
}
-
// 生成属性设置服务
ThingModelService propertySetService = generatePropertySetService(propertyList);
if (propertySetService != null) {
IotThinkModelFunctionDO setServiceFunction = buildServiceFunctionDO(productId, productKey, propertySetService);
newFunctionList.add(setServiceFunction);
}
-
// 生成属性获取服务
ThingModelService propertyGetService = generatePropertyGetService(propertyList);
if (propertyGetService != null) {
@@ -182,19 +182,15 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
Arrays.asList(IotThingModelTypeEnum.EVENT.getType(), IotThingModelTypeEnum.SERVICE.getType())
);
- // 3. 使用 diffList 方法比较新旧列表
- List> diffResult = diffList(
- oldFunctionList,
- newFunctionList,
+ // 3.1 使用 diffList 方法比较新旧列表
+ List> diffResult = diffList(oldFunctionList, newFunctionList,
+ // TODO @haohao:是不是用 id 比较相同就 ok 哈。如果可以的化,下面的 update 可以更简单
(oldFunc, newFunc) -> Objects.equals(oldFunc.getIdentifier(), newFunc.getIdentifier())
- && Objects.equals(oldFunc.getType(), newFunc.getType())
- );
-
+ && Objects.equals(oldFunc.getType(), newFunc.getType()));
List createList = diffResult.get(0); // 需要新增的
List updateList = diffResult.get(1); // 需要更新的
List deleteList = diffResult.get(2); // 需要删除的
-
- // 4. 批量执行数据库操作
+ // 3.2 批量执行数据库操作
if (CollUtil.isNotEmpty(createList)) {
thinkModelFunctionMapper.insertBatch(createList);
}
@@ -202,8 +198,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
for (IotThinkModelFunctionDO updateFunc : updateList) {
// 设置 ID,以便更新
IotThinkModelFunctionDO oldFunc = findFunctionByIdentifierAndType(
- oldFunctionList, updateFunc.getIdentifier(), updateFunc.getType()
- );
+ oldFunctionList, updateFunc.getIdentifier(), updateFunc.getType());
if (oldFunc != null) {
updateFunc.setId(oldFunc.getId());
thinkModelFunctionMapper.updateById(updateFunc);
@@ -211,6 +206,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
}
}
if (CollUtil.isNotEmpty(deleteList)) {
+ // TODO @haohao:使用 convertSet 简化。
List idsToDelete = deleteList.stream().map(IotThinkModelFunctionDO::getId).collect(Collectors.toList());
thinkModelFunctionMapper.deleteByIds(idsToDelete);
}
@@ -221,6 +217,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
*/
private IotThinkModelFunctionDO findFunctionByIdentifierAndType(List functionList,
String identifier, Integer type) {
+ // TODO @haohao:这个可以使用 CollUtil.findOne 简化只有一行
return functionList.stream()
.filter(func -> Objects.equals(func.getIdentifier(), identifier) && Objects.equals(func.getType(), type))
.findFirst()
@@ -335,7 +332,9 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
List outputData = new ArrayList<>();
for (IotThinkModelFunctionDO functionDO : propertyList) {
ThingModelProperty property = functionDO.getProperty();
- if (IotAccessModeEnum.READ.getMode().equals(property.getAccessMode()) || IotAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) {
+ // TODO @haohao:ObjectUtils.equalsAny(),进一步简化判断
+ if (IotAccessModeEnum.READ.getMode().equals(property.getAccessMode())
+ || IotAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) {
ThingModelArgument arg = new ThingModelArgument()
.setIdentifier(property.getIdentifier())
.setName(property.getName())
@@ -372,7 +371,6 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
textType.setType("text");
arraySpecs.setItem(textType);
arrayType.setSpecs(arraySpecs);
-
inputArg.setDataType(arrayType);
service.setInputData(Collections.singletonList(inputArg));
From d8d37d1bb94b5d141fdfc91a5a6dc8d293807d55 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com>
Date: Wed, 18 Sep 2024 08:22:33 +0800
Subject: [PATCH 24/31] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98?=
=?UTF-8?q?=E5=8C=96=E3=80=91IOT=20=E7=89=A9=E6=A8=A1=E5=9E=8B=E6=8E=A5?=
=?UTF-8?q?=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../IotThinkModelFunctionController.http | 103 ++++++++++++------
.../IotThinkModelFunctionServiceImpl.java | 56 ++++------
2 files changed, 87 insertions(+), 72 deletions(-)
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
index 6b9032fc6..56464dd80 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
@@ -5,39 +5,6 @@ tenant-id: {{adminTenentId}}
Authorization: Bearer {{token}}
{
- "productId": 1001,
- "productKey": "smart-sensor-001",
- "identifier": "Temperature",
- "name": "温度",
- "description": "当前温度值",
- "type": 1,
- "property": {
- "identifier": "Temperature",
- "name": "温度",
- "accessMode": "r",
- "required": true,
- "dataType": {
- "type": "float",
- "specs": {
- "min": -40.0,
- "max": 125.0,
- "step": 0.1,
- "unit": "℃"
- }
- },
- "description": "当前温度值"
- }
-}
-
-
-### 请求 /iot/think-model-function/update 接口 => 成功
-PUT {{baseUrl}}/iot/think-model-function/update
-Content-Type: application/json
-tenant-id: {{adminTenentId}}
-Authorization: Bearer {{token}}
-
-{
- "id": 1,
"productId": 1001,
"productKey": "smart-sensor-001",
"identifier": "Temperature",
@@ -62,13 +29,79 @@ Authorization: Bearer {{token}}
}
}
+### 请求 /iot/think-model-function/create 接口 => 成功
+POST {{baseUrl}}/iot/think-model-function/create
+Content-Type: application/json
+tenant-id: {{adminTenentId}}
+Authorization: Bearer {{token}}
+
+{
+ "productId": 1001,
+ "productKey": "smart-sensor-001",
+ "identifier": "Humidity",
+ "name": "湿度",
+ "description": "当前湿度值",
+ "type": 1,
+ "property": {
+ "identifier": "Humidity",
+ "name": "湿度",
+ "accessMode": "r",
+ "required": true,
+ "dataType": {
+ "type": "float",
+ "specs": {
+ "min": 0.0,
+ "max": 100.0,
+ "step": 0.1,
+ "unit": "%"
+ }
+ },
+ "description": "当前湿度值"
+ }
+}
+
+
+
+
+### 请求 /iot/think-model-function/update 接口 => 成功
+PUT {{baseUrl}}/iot/think-model-function/update
+Content-Type: application/json
+tenant-id: {{adminTenentId}}
+Authorization: Bearer {{token}}
+
+{
+ "id": 11,
+ "productId": 1001,
+ "productKey": "smart-sensor-001",
+ "identifier": "Temperature",
+ "name": "温度",
+ "description": "当前温度值",
+ "type": 1,
+ "property": {
+ "identifier": "Temperature",
+ "name": "温度",
+ "accessMode": "r",
+ "required": true,
+ "dataType": {
+ "type": "float",
+ "specs": {
+ "min": -111.0,
+ "max": 222.0,
+ "step": 0.1,
+ "unit": "℃"
+ }
+ },
+ "description": "当前温度值"
+ }
+}
+
### 请求 /iot/think-model-function/delete 接口 => 成功
-DELETE {{baseUrl}}/iot/think-model-function/delete?id=1
+DELETE {{baseUrl}}/iot/think-model-function/delete?id=7
tenant-id: {{adminTenentId}}
Authorization: Bearer {{token}}
### 请求 /iot/think-model-function/get 接口 => 成功
-GET {{baseUrl}}/iot/think-model-function/get?id=4
+GET {{baseUrl}}/iot/think-model-function/get?id=10
tenant-id: {{adminTenentId}}
Authorization: Bearer {{token}}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
index 0edb96db2..9dc803e66 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
@@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.iot.service.thinkmodelfunction;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
@@ -22,7 +24,6 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.util.*;
-import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
@@ -54,12 +55,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
// 3. 如果创建的是属性,需要更新默认的事件和服务
if (Objects.equals(createReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
- // 获取当前属性列表,并添加新插入的属性
- // TODO @haohao:是不是插入后,查询已经包含了 function
- List propertyList = thinkModelFunctionMapper
- .selectListByProductIdAndType(createReqVO.getProductId(), IotThingModelTypeEnum.PROPERTY.getType());
- propertyList.add(function);
- createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey(), propertyList);
+ createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey());
}
return function.getId();
}
@@ -76,6 +72,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) {
// 1. 校验功能是否存在
validateThinkModelFunctionExists(updateReqVO.getId());
+
// 2. 校验功能标识符是否唯一
validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier());
@@ -85,17 +82,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
// 4. 如果更新的是属性,需要更新默认的事件和服务
if (Objects.equals(updateReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
- // 获取当前属性列表,更新其中的属性
- // TODO @haohao:是不是更新后,查询出来的,已经是最新的 thinkModelFunction
- List propertyList = thinkModelFunctionMapper
- .selectListByProductIdAndType(updateReqVO.getProductId(), IotThingModelTypeEnum.PROPERTY.getType());
- for (int i = 0; i < propertyList.size(); i++) {
- if (propertyList.get(i).getId().equals(thinkModelFunction.getId())) {
- propertyList.set(i, thinkModelFunction);
- break;
- }
- }
- createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey(), propertyList);
+ createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey());
}
}
@@ -120,12 +107,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
// 3. 如果删除的是属性,需要更新默认的事件和服务
if (Objects.equals(functionDO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
- // 获取当前属性列表,移除已删除的属性
- // TODO @haohao:是不是删除后,已经没有 id 对应的记录啦?
- List propertyList = thinkModelFunctionMapper
- .selectListByProductIdAndType(functionDO.getProductId(), IotThingModelTypeEnum.PROPERTY.getType());
- propertyList.removeIf(property -> property.getId().equals(id));
- createDefaultEventsAndServices(functionDO.getProductId(), functionDO.getProductKey(), propertyList);
+ createDefaultEventsAndServices(functionDO.getProductId(), functionDO.getProductKey());
}
}
@@ -153,8 +135,12 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
/**
* 创建默认的事件和服务
*/
- public void createDefaultEventsAndServices(Long productId, String productKey, List propertyList) {
- // 1. 生成新的事件和服务列表
+ public void createDefaultEventsAndServices(Long productId, String productKey) {
+ // 1. 获取当前属性列表
+ List propertyList = thinkModelFunctionMapper
+ .selectListByProductIdAndType(productId, IotThingModelTypeEnum.PROPERTY.getType());
+
+ // 2. 生成新的事件和服务列表
List newFunctionList = new ArrayList<>();
// 生成属性上报事件
ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList);
@@ -175,7 +161,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
newFunctionList.add(getServiceFunction);
}
- // 2. 获取数据库中的默认的旧事件和服务列表
+ // 3. 获取数据库中的默认的旧事件和服务列表
List oldFunctionList = thinkModelFunctionMapper.selectListByProductIdAndIdentifiersAndTypes(
productId,
Arrays.asList("post", "set", "get"),
@@ -185,6 +171,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
// 3.1 使用 diffList 方法比较新旧列表
List> diffResult = diffList(oldFunctionList, newFunctionList,
// TODO @haohao:是不是用 id 比较相同就 ok 哈。如果可以的化,下面的 update 可以更简单
+ // 继续使用 identifier 和 type 进行比较:这样可以准确地匹配对应的功能对象。
(oldFunc, newFunc) -> Objects.equals(oldFunc.getIdentifier(), newFunc.getIdentifier())
&& Objects.equals(oldFunc.getType(), newFunc.getType()));
List createList = diffResult.get(0); // 需要新增的
@@ -206,8 +193,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
}
}
if (CollUtil.isNotEmpty(deleteList)) {
- // TODO @haohao:使用 convertSet 简化。
- List idsToDelete = deleteList.stream().map(IotThinkModelFunctionDO::getId).collect(Collectors.toList());
+ Set idsToDelete = CollectionUtils.convertSet(deleteList, IotThinkModelFunctionDO::getId);
thinkModelFunctionMapper.deleteByIds(idsToDelete);
}
}
@@ -217,11 +203,8 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
*/
private IotThinkModelFunctionDO findFunctionByIdentifierAndType(List functionList,
String identifier, Integer type) {
- // TODO @haohao:这个可以使用 CollUtil.findOne 简化只有一行
- return functionList.stream()
- .filter(func -> Objects.equals(func.getIdentifier(), identifier) && Objects.equals(func.getType(), type))
- .findFirst()
- .orElse(null);
+ return CollUtil.findOne(functionList, func ->
+ Objects.equals(func.getIdentifier(), identifier) && Objects.equals(func.getType(), type));
}
/**
@@ -332,9 +315,8 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
List outputData = new ArrayList<>();
for (IotThinkModelFunctionDO functionDO : propertyList) {
ThingModelProperty property = functionDO.getProperty();
- // TODO @haohao:ObjectUtils.equalsAny(),进一步简化判断
- if (IotAccessModeEnum.READ.getMode().equals(property.getAccessMode())
- || IotAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) {
+ if (ObjectUtils.equalsAny(property.getAccessMode(),
+ IotAccessModeEnum.READ.getMode(), IotAccessModeEnum.READ_WRITE.getMode())) {
ThingModelArgument arg = new ThingModelArgument()
.setIdentifier(property.getIdentifier())
.setName(property.getName())
From bd18e730525671e1286a063d17604db483d41412 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com>
Date: Fri, 20 Sep 2024 23:33:00 +0800
Subject: [PATCH 25/31] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E3=80=91IOT?=
=?UTF-8?q?=20=E8=AE=BE=E5=A4=87=E7=AE=A1=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../module/iot/enums/ErrorCodeConstants.java | 5 +
.../iot/enums/device/IotDeviceStatusEnum.java | 43 +++
.../admin/device/IotDeviceController.java | 104 +++++++
.../admin/device/vo/IotDevicePageReqVO.java | 98 +++++++
.../admin/device/vo/IotDeviceRespVO.java | 119 ++++++++
.../admin/device/vo/IotDeviceSaveReqVO.java | 22 ++
.../module/iot/convert/package-info.java | 1 +
.../dal/dataobject/device/IotDeviceDO.java | 134 +++++++++
.../iot/dal/mysql/device/IotDeviceMapper.java | 56 ++++
.../iot/service/device/DeviceServiceImpl.java | 264 ++++++++++++++++++
.../iot/service/device/IotDeviceService.java | 60 ++++
.../mapper/device/IotDeviceMapper.xml | 12 +
.../service/device/DeviceServiceImplTest.java | 219 +++++++++++++++
13 files changed, 1137 insertions(+)
create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStatusEnum.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/package-info.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImplTest.java
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
index 790bbb40c..0a103b354 100644
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
+++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
@@ -21,5 +21,10 @@ public interface ErrorCodeConstants {
// ========== IoT 设备 1-050-003-000 ============
ErrorCode DEVICE_NOT_EXISTS = new ErrorCode(1_050_003_000, "设备不存在");
+ ErrorCode DEVICE_NAME_EXISTS = new ErrorCode(1_050_003_001, "设备名称在同一产品下必须唯一");
+ ErrorCode DEVICE_HAS_CHILDREN = new ErrorCode(1_050_003_002, "有子设备,不允许删除");
+ ErrorCode DEVICE_NAME_CANNOT_BE_MODIFIED = new ErrorCode(1_050_003_003, "设备名称不能修改");
+ ErrorCode DEVICE_PRODUCT_CANNOT_BE_MODIFIED = new ErrorCode(1_050_003_004, "产品不能修改");
+ ErrorCode DEVICE_INVALID_DEVICE_STATUS = new ErrorCode(1_050_003_005, "无效的设备状态");
}
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStatusEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStatusEnum.java
new file mode 100644
index 000000000..3d0f9fcc5
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStatusEnum.java
@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.iot.enums.device;
+
+import lombok.Getter;
+
+/**
+ * IoT 设备状态枚举
+ * 设备状态:0 - 未激活,1 - 在线,2 - 离线,3 - 已禁用
+ */
+@Getter
+public enum IotDeviceStatusEnum {
+
+ INACTIVE(0, "未激活"),
+ ONLINE(1, "在线"),
+ OFFLINE(2, "离线"),
+ DISABLED(3, "已禁用");
+
+ /**
+ * 状态
+ */
+ private final Integer status;
+ /**
+ * 状态名
+ */
+ private final String name;
+
+ IotDeviceStatusEnum(Integer status, String name) {
+ this.status = status;
+ this.name = name;
+ }
+
+ public static IotDeviceStatusEnum fromStatus(Integer status) {
+ for (IotDeviceStatusEnum value : values()) {
+ if (value.getStatus().equals(status)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+ public static boolean isValidStatus(Integer status) {
+ return fromStatus(status) != null;
+ }
+}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java
new file mode 100644
index 000000000..c809a9059
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java
@@ -0,0 +1,104 @@
+package cn.iocoder.yudao.module.iot.controller.admin.device;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceRespVO;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
+import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - IoT 设备")
+@RestController
+@RequestMapping("/iot/device")
+@Validated
+public class IotDeviceController {
+
+ @Resource
+ private IotDeviceService deviceService;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建IoT 设备")
+ @PreAuthorize("@ss.hasPermission('iot:device:create')")
+ public CommonResult createDevice(@Valid @RequestBody IotDeviceSaveReqVO createReqVO) {
+ return success(deviceService.createDevice(createReqVO));
+ }
+
+ @PutMapping("/update-status")
+ @Operation(summary = "更新IoT 设备状态")
+ @Parameter(name = "id", description = "编号", required = true)
+ @Parameter(name = "status", description = "状态", required = true, example = "1")
+ @PreAuthorize("@ss.hasPermission('iot:device:update')")
+ public CommonResult updateDeviceStatus(@RequestParam("id") Long id,
+ @RequestParam("status") Integer status) {
+ deviceService.updateDeviceStatus(id, status);
+ return success(true);
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新IoT 设备")
+ @PreAuthorize("@ss.hasPermission('iot:device:update')")
+ public CommonResult updateDevice(@Valid @RequestBody IotDeviceSaveReqVO updateReqVO) {
+ deviceService.updateDevice(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除IoT 设备")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('iot:device:delete')")
+ public CommonResult deleteDevice(@RequestParam("id") Long id) {
+ deviceService.deleteDevice(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得IoT 设备")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('iot:device:query')")
+ public CommonResult getDevice(@RequestParam("id") Long id) {
+ IotDeviceDO device = deviceService.getDevice(id);
+ return success(BeanUtils.toBean(device, IotDeviceRespVO.class));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得IoT 设备分页")
+ @PreAuthorize("@ss.hasPermission('iot:device:query')")
+ public CommonResult> getDevicePage(@Valid IotDevicePageReqVO pageReqVO) {
+ PageResult pageResult = deviceService.getDevicePage(pageReqVO);
+ return success(BeanUtils.toBean(pageResult, IotDeviceRespVO.class));
+ }
+
+ @GetMapping("/export-excel")
+ @Operation(summary = "导出IoT 设备 Excel")
+ @PreAuthorize("@ss.hasPermission('iot:device:export')")
+ @ApiAccessLog(operateType = EXPORT)
+ public void exportDeviceExcel(@Valid IotDevicePageReqVO pageReqVO,
+ HttpServletResponse response) throws IOException {
+ pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+ List list = deviceService.getDevicePage(pageReqVO).getList();
+ // 导出 Excel
+ ExcelUtils.write(response, "IoT 设备.xls", "数据", IotDeviceRespVO.class,
+ BeanUtils.toBean(list, IotDeviceRespVO.class));
+ }
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java
new file mode 100644
index 000000000..36a184871
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java
@@ -0,0 +1,98 @@
+package cn.iocoder.yudao.module.iot.controller.admin.device.vo;
+
+import lombok.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import java.math.BigDecimal;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - IoT 设备分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class IotDevicePageReqVO extends PageParam {
+
+ @Schema(description = "设备唯一标识符,全局唯一,用于识别设备")
+ private String deviceKey;
+
+ @Schema(description = "设备名称,在产品内唯一,用于标识设备", example = "王五")
+ private String deviceName;
+
+ @Schema(description = "产品 ID,关联 iot_product 表的 id", example = "26202")
+ private Long productId;
+
+ @Schema(description = "产品 Key,关联 iot_product 表的 product_key")
+ private String productKey;
+
+ @Schema(description = "设备类型:0 - 直连设备,1 - 网关子设备,2 - 网关设备", example = "1")
+ private Integer deviceType;
+
+ @Schema(description = "设备备注名称,供用户自定义备注", example = "张三")
+ private String nickname;
+
+ @Schema(description = "网关设备 ID,子设备需要关联的网关设备 ID", example = "16380")
+ private Long gatewayId;
+
+ @Schema(description = "设备状态:0 - 未激活,1 - 在线,2 - 离线,3 - 已禁用", example = "1")
+ private Integer status;
+
+ @Schema(description = "设备状态最后更新时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] statusLastUpdateTime;
+
+ @Schema(description = "最后上线时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] lastOnlineTime;
+
+ @Schema(description = "最后离线时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] lastOfflineTime;
+
+ @Schema(description = "设备激活时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] activeTime;
+
+ @Schema(description = "设备的 IP 地址")
+ private String ip;
+
+ @Schema(description = "设备的固件版本")
+ private String firmwareVersion;
+
+ @Schema(description = "设备密钥,用于设备认证,需安全存储")
+ private String deviceSecret;
+
+ @Schema(description = "MQTT 客户端 ID", example = "24602")
+ private String mqttClientId;
+
+ @Schema(description = "MQTT 用户名", example = "芋艿")
+ private String mqttUsername;
+
+ @Schema(description = "MQTT 密码")
+ private String mqttPassword;
+
+ @Schema(description = "认证类型(如一机一密、动态注册)", example = "2")
+ private String authType;
+
+ @Schema(description = "设备位置的纬度,范围 -90.000000 ~ 90.000000")
+ private BigDecimal latitude;
+
+ @Schema(description = "设备位置的经度,范围 -180.000000 ~ 180.000000")
+ private BigDecimal longitude;
+
+ @Schema(description = "地区编码,符合国家地区编码标准,关联地区表", example = "16995")
+ private Integer areaId;
+
+ @Schema(description = "设备详细地址")
+ private String address;
+
+ @Schema(description = "设备序列号")
+ private String serialNumber;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java
new file mode 100644
index 000000000..7cf592fc0
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java
@@ -0,0 +1,119 @@
+package cn.iocoder.yudao.module.iot.controller.admin.device.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - IoT 设备 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class IotDeviceRespVO {
+
+ @Schema(description = "设备 ID,主键,自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
+ private Long id;
+
+ @Schema(description = "设备唯一标识符", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("设备唯一标识符")
+ private String deviceKey;
+
+ @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
+ @ExcelProperty("设备名称备")
+ private String deviceName;
+
+ @Schema(description = "产品 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202")
+ @ExcelProperty("产品 ID")
+ private Long productId;
+
+ @Schema(description = "产品 Key", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("产品 Key")
+ private String productKey;
+
+ @Schema(description = "设备类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @ExcelProperty("设备类型")
+ private Integer deviceType;
+
+ @Schema(description = "设备备注名称", example = "张三")
+ @ExcelProperty("设备备注名称")
+ private String nickname;
+
+ @Schema(description = "网关设备 ID", example = "16380")
+ @ExcelProperty("网关设备 ID")
+ private Long gatewayId;
+
+ @Schema(description = "设备状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @ExcelProperty("设备状态")
+ private Integer status;
+
+ @Schema(description = "设备状态最后更新时间")
+ @ExcelProperty("设备状态最后更新时间")
+ private LocalDateTime statusLastUpdateTime;
+
+ @Schema(description = "最后上线时间")
+ @ExcelProperty("最后上线时间")
+ private LocalDateTime lastOnlineTime;
+
+ @Schema(description = "最后离线时间")
+ @ExcelProperty("最后离线时间")
+ private LocalDateTime lastOfflineTime;
+
+ @Schema(description = "设备激活时间")
+ @ExcelProperty("设备激活时间")
+ private LocalDateTime activeTime;
+
+ @Schema(description = "设备的 IP 地址")
+ @ExcelProperty("设备的 IP 地址")
+ private String ip;
+
+ @Schema(description = "设备的固件版本")
+ @ExcelProperty("设备的固件版本")
+ private String firmwareVersion;
+
+ @Schema(description = "设备密钥,用于设备认证,需安全存储")
+ @ExcelProperty("设备密钥")
+ private String deviceSecret;
+
+ @Schema(description = "MQTT 客户端 ID", example = "24602")
+ @ExcelProperty("MQTT 客户端 ID")
+ private String mqttClientId;
+
+ @Schema(description = "MQTT 用户名", example = "芋艿")
+ @ExcelProperty("MQTT 用户名")
+ private String mqttUsername;
+
+ @Schema(description = "MQTT 密码")
+ @ExcelProperty("MQTT 密码")
+ private String mqttPassword;
+
+ @Schema(description = "认证类型(如一机一密、动态注册)", example = "2")
+ @ExcelProperty("认证类型(如一机一密、动态注册)")
+ private String authType;
+
+ @Schema(description = "设备位置的纬度,范围 -90.000000 ~ 90.000000")
+ @ExcelProperty("设备位置的纬度,范围 -90.000000 ~ 90.000000")
+ private BigDecimal latitude;
+
+ @Schema(description = "设备位置的经度,范围 -180.000000 ~ 180.000000")
+ @ExcelProperty("设备位置的经度,范围 -180.000000 ~ 180.000000")
+ private BigDecimal longitude;
+
+ @Schema(description = "地区编码,符合国家地区编码标准,关联地区表", example = "16995")
+ @ExcelProperty("地区编码,符合国家地区编码标准,关联地区表")
+ private Integer areaId;
+
+ @Schema(description = "设备详细地址")
+ @ExcelProperty("设备详细地址")
+ private String address;
+
+ @Schema(description = "设备序列号")
+ @ExcelProperty("设备序列号")
+ private String serialNumber;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("创建时间")
+ private LocalDateTime createTime;
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java
new file mode 100644
index 000000000..f52d8db92
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.iot.controller.admin.device.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - IoT 设备新增/修改 Request VO")
+@Data
+public class IotDeviceSaveReqVO {
+
+ @Schema(description = "设备 ID,主键,自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
+ private Long id;
+
+ @Schema(description = "设备名称,在产品内唯一,用于标识设备", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
+ private String deviceName;
+
+ @Schema(description = "设备备注名称,供用户自定义备注", example = "张三")
+ private String nickname;
+
+ @Schema(description = "产品 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202")
+ private Long productId;
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/package-info.java
new file mode 100644
index 000000000..c196c25c3
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/package-info.java
@@ -0,0 +1 @@
+package cn.iocoder.yudao.module.iot.convert;
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java
new file mode 100644
index 000000000..138913f73
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java
@@ -0,0 +1,134 @@
+package cn.iocoder.yudao.module.iot.dal.dataobject.device;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * IoT 设备 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("iot_device")
+@KeySequence("iot_device_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class IotDeviceDO extends BaseDO {
+
+ /**
+ * 设备 ID,主键,自增
+ */
+ @TableId
+ private Long id;
+ /**
+ * 设备唯一标识符,全局唯一,用于识别设备
+ */
+ private String deviceKey;
+ /**
+ * 设备名称,在产品内唯一,用于标识设备
+ */
+ private String deviceName;
+ /**
+ * 产品 ID,关联 iot_product 表的 id
+ * 关联 {@link IotProductDO#getId()}
+ */
+ private Long productId;
+ /**
+ * 产品 Key,关联 iot_product 表的 product_key
+ * 关联 {@link IotProductDO#getProductKey()}
+ */
+ private String productKey;
+ /**
+ * 设备类型:0 - 直连设备,1 - 网关子设备,2 - 网关设备
+ * 关联 {@link IotProductDO#getDeviceType()}
+ */
+ private Integer deviceType;
+ /**
+ * 设备备注名称,供用户自定义备注
+ */
+ private String nickname;
+ /**
+ * 网关设备 ID,子设备需要关联的网关设备 ID
+ */
+ private Long gatewayId;
+ /**
+ * 设备状态:0 - 未激活,1 - 在线,2 - 离线,3 - 已禁用
+ * 关联 {@link cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum}
+ */
+ private Integer status;
+ /**
+ * 设备状态最后更新时间
+ */
+ private LocalDateTime statusLastUpdateTime;
+ /**
+ * 最后上线时间
+ */
+ private LocalDateTime lastOnlineTime;
+ /**
+ * 最后离线时间
+ */
+ private LocalDateTime lastOfflineTime;
+ /**
+ * 设备激活时间
+ */
+ private LocalDateTime activeTime;
+ /**
+ * 设备的 IP 地址
+ */
+ private String ip;
+ /**
+ * 设备的固件版本
+ */
+ private String firmwareVersion;
+ /**
+ * 设备密钥,用于设备认证,需安全存储
+ */
+ private String deviceSecret;
+ /**
+ * MQTT 客户端 ID
+ */
+ private String mqttClientId;
+ /**
+ * MQTT 用户名
+ */
+ private String mqttUsername;
+ /**
+ * MQTT 密码
+ */
+ private String mqttPassword;
+ /**
+ * 认证类型(如一机一密、动态注册)
+ */
+ private String authType;
+ /**
+ * 设备位置的纬度,范围 -90.000000 ~ 90.000000
+ */
+ private BigDecimal latitude;
+ /**
+ * 设备位置的经度,范围 -180.000000 ~ 180.000000
+ */
+ private BigDecimal longitude;
+ /**
+ * 地区编码,符合国家地区编码标准,关联地区表
+ */
+ private Integer areaId;
+ /**
+ * 设备详细地址
+ */
+ private String address;
+ /**
+ * 设备序列号
+ */
+ private String serialNumber;
+
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java
new file mode 100644
index 000000000..fc7d0a71f
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java
@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.module.iot.dal.mysql.device;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * IoT 设备 Mapper
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface IotDeviceMapper extends BaseMapperX {
+
+ default PageResult selectPage(IotDevicePageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX()
+ .eqIfPresent(IotDeviceDO::getDeviceKey, reqVO.getDeviceKey())
+ .likeIfPresent(IotDeviceDO::getDeviceName, reqVO.getDeviceName())
+ .eqIfPresent(IotDeviceDO::getProductId, reqVO.getProductId())
+ .eqIfPresent(IotDeviceDO::getProductKey, reqVO.getProductKey())
+ .eqIfPresent(IotDeviceDO::getDeviceType, reqVO.getDeviceType())
+ .likeIfPresent(IotDeviceDO::getNickname, reqVO.getNickname())
+ .eqIfPresent(IotDeviceDO::getGatewayId, reqVO.getGatewayId())
+ .eqIfPresent(IotDeviceDO::getStatus, reqVO.getStatus())
+ .betweenIfPresent(IotDeviceDO::getStatusLastUpdateTime, reqVO.getStatusLastUpdateTime())
+ .betweenIfPresent(IotDeviceDO::getLastOnlineTime, reqVO.getLastOnlineTime())
+ .betweenIfPresent(IotDeviceDO::getLastOfflineTime, reqVO.getLastOfflineTime())
+ .betweenIfPresent(IotDeviceDO::getActiveTime, reqVO.getActiveTime())
+ .eqIfPresent(IotDeviceDO::getIp, reqVO.getIp())
+ .eqIfPresent(IotDeviceDO::getFirmwareVersion, reqVO.getFirmwareVersion())
+ .eqIfPresent(IotDeviceDO::getDeviceSecret, reqVO.getDeviceSecret())
+ .eqIfPresent(IotDeviceDO::getMqttClientId, reqVO.getMqttClientId())
+ .likeIfPresent(IotDeviceDO::getMqttUsername, reqVO.getMqttUsername())
+ .eqIfPresent(IotDeviceDO::getMqttPassword, reqVO.getMqttPassword())
+ .eqIfPresent(IotDeviceDO::getAuthType, reqVO.getAuthType())
+ .eqIfPresent(IotDeviceDO::getLatitude, reqVO.getLatitude())
+ .eqIfPresent(IotDeviceDO::getLongitude, reqVO.getLongitude())
+ .eqIfPresent(IotDeviceDO::getAreaId, reqVO.getAreaId())
+ .eqIfPresent(IotDeviceDO::getAddress, reqVO.getAddress())
+ .eqIfPresent(IotDeviceDO::getSerialNumber, reqVO.getSerialNumber())
+ .betweenIfPresent(IotDeviceDO::getCreateTime, reqVO.getCreateTime())
+ .orderByDesc(IotDeviceDO::getId));
+ }
+
+ default IotDeviceDO selectByProductKeyAndDeviceName(String productKey, String deviceName) {
+ return selectOne(IotDeviceDO::getProductKey, productKey,
+ IotDeviceDO::getDeviceName, deviceName);
+ }
+
+ default long selectCountByGatewayId(Long id) {
+ return selectCount(IotDeviceDO::getGatewayId, id);
+ }
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java
new file mode 100644
index 000000000..b1e7ffbdd
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java
@@ -0,0 +1,264 @@
+package cn.iocoder.yudao.module.iot.service.device;
+
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
+import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper;
+import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper;
+import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import java.time.LocalDateTime;
+import java.util.UUID;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
+
+/**
+ * IoT 设备 Service 实现类
+ *
+ * @author 芋道源码
+ */
+@Service
+@Validated
+@Slf4j
+public class DeviceServiceImpl implements IotDeviceService {
+
+ @Resource
+ private IotDeviceMapper deviceMapper;
+ @Resource
+ private IotProductMapper productMapper;
+
+ /**
+ * 创建 IoT 设备
+ *
+ * @param createReqVO 创建请求 VO
+ * @return 设备 ID
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Long createDevice(IotDeviceSaveReqVO createReqVO) {
+ // 1. 转换 VO 为 DO
+ IotDeviceDO device = BeanUtils.toBean(createReqVO, IotDeviceDO.class);
+
+ // 2. 根据产品 ID 查询产品信息
+ IotProductDO product = productMapper.selectById(createReqVO.getProductId());
+ if (product == null) {
+ throw exception(PRODUCT_NOT_EXISTS);
+ }
+ device.setProductKey(product.getProductKey());
+ device.setDeviceType(product.getDeviceType());
+
+ // 3. DeviceName 可以为空,当为空时,自动生成产品下的唯一标识符作为 DeviceName
+ if (StrUtil.isBlank(device.getDeviceName())) {
+ device.setDeviceName(generateUniqueDeviceName(createReqVO.getProductId()));
+ }
+
+ // 4. 校验设备名称在同一产品下是否唯一
+ validateDeviceNameUnique(device.getProductKey(), device.getDeviceName());
+
+ // 5. 生成并设置必要的字段
+ device.setDeviceKey(generateUniqueDeviceKey());
+ device.setDeviceSecret(generateDeviceSecret());
+ device.setMqttClientId(generateMqttClientId());
+ device.setMqttUsername(generateMqttUsername(device.getDeviceName(), device.getProductKey()));
+ device.setMqttPassword(generateMqttPassword());
+
+ // 6. 设置设备状态为未激活
+ device.setStatus(IotDeviceStatusEnum.INACTIVE.getStatus());
+ device.setStatusLastUpdateTime(LocalDateTime.now());
+
+ // 7. 插入到数据库
+ deviceMapper.insert(device);
+
+ // 8. 返回生成的设备 ID
+ return device.getId();
+ }
+
+ /**
+ * 校验设备名称在同一产品下是否唯一
+ *
+ * @param productKey 产品 Key
+ * @param deviceName 设备名称
+ */
+ private void validateDeviceNameUnique(String productKey, String deviceName) {
+ IotDeviceDO existingDevice = deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName);
+ if (existingDevice != null) {
+ throw exception(DEVICE_NAME_EXISTS);
+ }
+ }
+
+ /**
+ * 生成唯一的 deviceKey
+ *
+ * @return 生成的 deviceKey
+ */
+ private String generateUniqueDeviceKey() {
+ return UUID.randomUUID().toString();
+ }
+
+ /**
+ * 生成 deviceSecret
+ *
+ * @return 生成的 deviceSecret
+ */
+ private String generateDeviceSecret() {
+ // 32 位随机字符串
+ return UUID.randomUUID().toString().replace("-", "");
+ }
+
+ /**
+ * 生成 MQTT Client ID
+ *
+ * @return 生成的 MQTT Client ID
+ */
+ private String generateMqttClientId() {
+ return UUID.randomUUID().toString();
+ }
+
+ /**
+ * 生成 MQTT Username
+ *
+ * @param deviceName 设备名称
+ * @param productKey 产品 Key
+ * @return 生成的 MQTT Username
+ */
+ private String generateMqttUsername(String deviceName, String productKey) {
+ return deviceName + "&" + productKey;
+ }
+
+ /**
+ * 生成 MQTT Password
+ *
+ * @return 生成的 MQTT Password
+ */
+ private String generateMqttPassword() {
+ // 在实际应用中,建议使用更安全的方法生成 MQTT Password,如加密或哈希
+ return UUID.randomUUID().toString();
+ }
+
+ /**
+ * 生成唯一的 DeviceName
+ *
+ * @param productId 产品 ID
+ * @return 生成的唯一 DeviceName
+ */
+ private String generateUniqueDeviceName(Long productId) {
+ // 实现逻辑以在产品下生成唯一的设备名称
+ String deviceName;
+ String productKey = getProductKey(productId);
+ do {
+ // 20 位随机字符串
+ deviceName = UUID.randomUUID().toString().replace("-", "").substring(0, 20);
+ } while (deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName) != null);
+ return deviceName;
+ }
+
+ /**
+ * 获取产品 Key
+ *
+ * @param productId 产品 ID
+ * @return 产品 Key
+ */
+ private String getProductKey(Long productId) {
+ IotProductDO product = productMapper.selectById(productId);
+ if (product == null) {
+ throw exception(PRODUCT_NOT_EXISTS);
+ }
+ return product.getProductKey();
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void updateDevice(IotDeviceSaveReqVO updateReqVO) {
+ // 校验存在
+ IotDeviceDO existingDevice = validateDeviceExists(updateReqVO.getId());
+
+ // 设备名称 和 产品 ID 不能修改
+ if (updateReqVO.getDeviceName() != null && !updateReqVO.getDeviceName().equals(existingDevice.getDeviceName())) {
+ throw exception(DEVICE_NAME_CANNOT_BE_MODIFIED);
+ }
+ if (updateReqVO.getProductId() != null && !updateReqVO.getProductId().equals(existingDevice.getProductId())) {
+ throw exception(DEVICE_PRODUCT_CANNOT_BE_MODIFIED);
+ }
+
+ // 更新 DO 对象
+ IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class);
+
+ // 更新到数据库
+ deviceMapper.updateById(updateObj);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void deleteDevice(Long id) {
+ // 校验存在
+ IotDeviceDO iotDeviceDO = validateDeviceExists(id);
+
+ // 如果是网关设备,检查是否有子设备
+ if (iotDeviceDO.getGatewayId() != null) {
+ long childCount = deviceMapper.selectCountByGatewayId(id);
+ if (childCount > 0) {
+ throw exception(DEVICE_HAS_CHILDREN);
+ }
+ }
+
+ // 删除设备
+ deviceMapper.deleteById(id);
+ }
+
+ /**
+ * 校验设备是否存在
+ *
+ * @param id 设备 ID
+ * @return 设备对象
+ */
+ private IotDeviceDO validateDeviceExists(Long id) {
+ IotDeviceDO iotDeviceDO = deviceMapper.selectById(id);
+ if (iotDeviceDO == null) {
+ throw exception(DEVICE_NOT_EXISTS);
+ }
+ return iotDeviceDO;
+ }
+
+ @Override
+ public IotDeviceDO getDevice(Long id) {
+ IotDeviceDO device = deviceMapper.selectById(id);
+ if (device == null) {
+ throw exception(DEVICE_NOT_EXISTS);
+ }
+ return device;
+ }
+
+ @Override
+ public PageResult getDevicePage(IotDevicePageReqVO pageReqVO) {
+ return deviceMapper.selectPage(pageReqVO);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void updateDeviceStatus(Long id, Integer status) {
+ // 校验存在
+ validateDeviceExists(id);
+
+ // 校验状态是否合法
+ if (!IotDeviceStatusEnum.isValidStatus(status)) {
+ throw exception(DEVICE_INVALID_DEVICE_STATUS);
+ }
+
+ // 更新状态和更新时间
+ IotDeviceDO updateObj = new IotDeviceDO()
+ .setId(id)
+ .setStatus(status)
+ .setStatusLastUpdateTime(LocalDateTime.now());
+ deviceMapper.updateById(updateObj);
+ }
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java
new file mode 100644
index 000000000..2802806de
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java
@@ -0,0 +1,60 @@
+package cn.iocoder.yudao.module.iot.service.device;
+
+import jakarta.validation.*;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.*;
+import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+/**
+ * IoT 设备 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface IotDeviceService {
+
+ /**
+ * 创建IoT 设备
+ *
+ * @param createReqVO 创建信息
+ * @return 编号
+ */
+ Long createDevice(@Valid IotDeviceSaveReqVO createReqVO);
+
+ /**
+ * 更新IoT 设备
+ *
+ * @param updateReqVO 更新信息
+ */
+ void updateDevice(@Valid IotDeviceSaveReqVO updateReqVO);
+
+ /**
+ * 删除IoT 设备
+ *
+ * @param id 编号
+ */
+ void deleteDevice(Long id);
+
+ /**
+ * 获得IoT 设备
+ *
+ * @param id 编号
+ * @return IoT 设备
+ */
+ IotDeviceDO getDevice(Long id);
+
+ /**
+ * 获得IoT 设备分页
+ *
+ * @param pageReqVO 分页查询
+ * @return IoT 设备分页
+ */
+ PageResult getDevicePage(IotDevicePageReqVO pageReqVO);
+
+ /**
+ * 更新IoT 设备状态
+ *
+ * @param id 编号
+ * @param status 状态
+ */
+ void updateDeviceStatus(Long id, Integer status);
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml
new file mode 100644
index 000000000..039dbd895
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImplTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImplTest.java
new file mode 100644
index 000000000..a456589cb
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImplTest.java
@@ -0,0 +1,219 @@
+package cn.iocoder.yudao.module.iot.service.device;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import jakarta.annotation.Resource;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.*;
+import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
+import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+import org.springframework.context.annotation.Import;
+
+import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
+import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
+import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
+import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * {@link DeviceServiceImpl} 的单元测试类
+ *
+ * @author 芋道源码
+ */
+@Import(DeviceServiceImpl.class)
+public class DeviceServiceImplTest extends BaseDbUnitTest {
+
+ @Resource
+ private DeviceServiceImpl deviceService;
+
+ @Resource
+ private IotDeviceMapper deviceMapper;
+
+ @Test
+ public void testCreateDevice_success() {
+ // 准备参数
+ IotDeviceSaveReqVO createReqVO = randomPojo(IotDeviceSaveReqVO.class).setId(null);
+
+ // 调用
+ Long deviceId = deviceService.createDevice(createReqVO);
+ // 断言
+ assertNotNull(deviceId);
+ // 校验记录的属性是否正确
+ IotDeviceDO device = deviceMapper.selectById(deviceId);
+ assertPojoEquals(createReqVO, device, "id");
+ }
+
+ @Test
+ public void testUpdateDevice_success() {
+ // mock 数据
+ IotDeviceDO dbDevice = randomPojo(IotDeviceDO.class);
+ deviceMapper.insert(dbDevice);// @Sql: 先插入出一条存在的数据
+ // 准备参数
+ IotDeviceSaveReqVO updateReqVO = randomPojo(IotDeviceSaveReqVO.class, o -> {
+ o.setId(dbDevice.getId()); // 设置更新的 ID
+ });
+
+ // 调用
+ deviceService.updateDevice(updateReqVO);
+ // 校验是否更新正确
+ IotDeviceDO device = deviceMapper.selectById(updateReqVO.getId()); // 获取最新的
+ assertPojoEquals(updateReqVO, device);
+ }
+
+ @Test
+ public void testUpdateDevice_notExists() {
+ // 准备参数
+ IotDeviceSaveReqVO updateReqVO = randomPojo(IotDeviceSaveReqVO.class);
+
+ // 调用, 并断言异常
+ assertServiceException(() -> deviceService.updateDevice(updateReqVO), DEVICE_NOT_EXISTS);
+ }
+
+ @Test
+ public void testDeleteDevice_success() {
+ // mock 数据
+ IotDeviceDO dbDevice = randomPojo(IotDeviceDO.class);
+ deviceMapper.insert(dbDevice);// @Sql: 先插入出一条存在的数据
+ // 准备参数
+ Long id = dbDevice.getId();
+
+ // 调用
+ deviceService.deleteDevice(id);
+ // 校验数据不存在了
+ assertNull(deviceMapper.selectById(id));
+ }
+
+ @Test
+ public void testDeleteDevice_notExists() {
+ // 准备参数
+ Long id = randomLongId();
+
+ // 调用, 并断言异常
+ assertServiceException(() -> deviceService.deleteDevice(id), DEVICE_NOT_EXISTS);
+ }
+
+ @Test
+ @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
+ public void testGetDevicePage() {
+ // mock 数据
+ IotDeviceDO dbDevice = randomPojo(IotDeviceDO.class, o -> { // 等会查询到
+ o.setDeviceKey(null);
+ o.setDeviceName(null);
+ o.setProductId(null);
+ o.setProductKey(null);
+ o.setDeviceType(null);
+ o.setNickname(null);
+ o.setGatewayId(null);
+ o.setStatus(null);
+ o.setStatusLastUpdateTime(null);
+ o.setLastOnlineTime(null);
+ o.setLastOfflineTime(null);
+ o.setActiveTime(null);
+ o.setIp(null);
+ o.setFirmwareVersion(null);
+ o.setDeviceSecret(null);
+ o.setMqttClientId(null);
+ o.setMqttUsername(null);
+ o.setMqttPassword(null);
+ o.setAuthType(null);
+ o.setLatitude(null);
+ o.setLongitude(null);
+ o.setAreaId(null);
+ o.setAddress(null);
+ o.setSerialNumber(null);
+ o.setCreateTime(null);
+ });
+ deviceMapper.insert(dbDevice);
+ // 测试 deviceKey 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setDeviceKey(null)));
+ // 测试 deviceName 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setDeviceName(null)));
+ // 测试 productId 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setProductId(null)));
+ // 测试 productKey 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setProductKey(null)));
+ // 测试 deviceType 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setDeviceType(null)));
+ // 测试 nickname 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setNickname(null)));
+ // 测试 gatewayId 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setGatewayId(null)));
+ // 测试 status 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setStatus(null)));
+ // 测试 statusLastUpdateTime 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setStatusLastUpdateTime(null)));
+ // 测试 lastOnlineTime 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setLastOnlineTime(null)));
+ // 测试 lastOfflineTime 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setLastOfflineTime(null)));
+ // 测试 activeTime 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setActiveTime(null)));
+ // 测试 ip 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setIp(null)));
+ // 测试 firmwareVersion 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setFirmwareVersion(null)));
+ // 测试 deviceSecret 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setDeviceSecret(null)));
+ // 测试 mqttClientId 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setMqttClientId(null)));
+ // 测试 mqttUsername 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setMqttUsername(null)));
+ // 测试 mqttPassword 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setMqttPassword(null)));
+ // 测试 authType 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setAuthType(null)));
+ // 测试 latitude 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setLatitude(null)));
+ // 测试 longitude 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setLongitude(null)));
+ // 测试 areaId 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setAreaId(null)));
+ // 测试 address 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setAddress(null)));
+ // 测试 serialNumber 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setSerialNumber(null)));
+ // 测试 createTime 不匹配
+ deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setCreateTime(null)));
+ // 准备参数
+ IotDevicePageReqVO reqVO = new IotDevicePageReqVO();
+ reqVO.setDeviceKey(null);
+ reqVO.setDeviceName(null);
+ reqVO.setProductId(null);
+ reqVO.setProductKey(null);
+ reqVO.setDeviceType(null);
+ reqVO.setNickname(null);
+ reqVO.setGatewayId(null);
+ reqVO.setStatus(null);
+ reqVO.setStatusLastUpdateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+ reqVO.setLastOnlineTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+ reqVO.setLastOfflineTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+ reqVO.setActiveTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+ reqVO.setIp(null);
+ reqVO.setFirmwareVersion(null);
+ reqVO.setDeviceSecret(null);
+ reqVO.setMqttClientId(null);
+ reqVO.setMqttUsername(null);
+ reqVO.setMqttPassword(null);
+ reqVO.setAuthType(null);
+ reqVO.setLatitude(null);
+ reqVO.setLongitude(null);
+ reqVO.setAreaId(null);
+ reqVO.setAddress(null);
+ reqVO.setSerialNumber(null);
+ reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+
+ // 调用
+ PageResult pageResult = deviceService.getDevicePage(reqVO);
+ // 断言
+ assertEquals(1, pageResult.getTotal());
+ assertEquals(1, pageResult.getList().size());
+ assertPojoEquals(dbDevice, pageResult.getList().get(0));
+ }
+
+}
\ No newline at end of file
From 6b9cca0b79612fc3ca26f04b73b23d9f973dd873 Mon Sep 17 00:00:00 2001
From: YunaiV
Date: Sat, 21 Sep 2024 10:09:30 +0800
Subject: [PATCH 26/31] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?=
=?UTF-8?q?=E5=AE=A1=E3=80=91IOT=EF=BC=9A=E8=AE=BE=E5=A4=87=E7=9A=84=20rev?=
=?UTF-8?q?iew?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../iot/enums/device/IotDeviceStatusEnum.java | 16 +-
.../admin/device/IotDeviceController.java | 14 +-
.../admin/device/vo/IotDevicePageReqVO.java | 31 ++-
.../admin/device/vo/IotDeviceRespVO.java | 21 +-
.../admin/device/vo/IotDeviceSaveReqVO.java | 8 +-
.../dal/dataobject/device/IotDeviceDO.java | 64 +++--
.../iot/dal/mysql/device/IotDeviceMapper.java | 1 +
.../iot/service/device/DeviceServiceImpl.java | 101 ++++----
.../iot/service/device/IotDeviceService.java | 13 +-
.../IotThinkModelFunctionServiceImpl.java | 2 +-
.../mapper/device/IotDeviceMapper.xml | 12 -
.../IotThinkModelFunctionMapper.xml | 12 -
.../service/device/DeviceServiceImplTest.java | 219 ------------------
.../IotThinkModelFunctionServiceImplTest.java | 71 ------
14 files changed, 145 insertions(+), 440 deletions(-)
delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml
delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/thinkmodelfunction/IotThinkModelFunctionMapper.xml
delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImplTest.java
delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImplTest.java
diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStatusEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStatusEnum.java
index 3d0f9fcc5..5fd983dc0 100644
--- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStatusEnum.java
+++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStatusEnum.java
@@ -1,19 +1,25 @@
package cn.iocoder.yudao.module.iot.enums.device;
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.Getter;
+import java.util.Arrays;
+
/**
* IoT 设备状态枚举
- * 设备状态:0 - 未激活,1 - 在线,2 - 离线,3 - 已禁用
+ *
+ * @author haohao
*/
@Getter
-public enum IotDeviceStatusEnum {
+public enum IotDeviceStatusEnum implements IntArrayValuable {
INACTIVE(0, "未激活"),
ONLINE(1, "在线"),
OFFLINE(2, "离线"),
DISABLED(3, "已禁用");
+ public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotDeviceStatusEnum::getStatus).toArray();
+
/**
* 状态
*/
@@ -40,4 +46,10 @@ public enum IotDeviceStatusEnum {
public static boolean isValidStatus(Integer status) {
return fromStatus(status) != null;
}
+
+ @Override
+ public int[] array() {
+ return ARRAYS;
+ }
+
}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java
index c809a9059..e455c78cf 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java
@@ -37,14 +37,14 @@ public class IotDeviceController {
private IotDeviceService deviceService;
@PostMapping("/create")
- @Operation(summary = "创建IoT 设备")
+ @Operation(summary = "创建设备")
@PreAuthorize("@ss.hasPermission('iot:device:create')")
public CommonResult createDevice(@Valid @RequestBody IotDeviceSaveReqVO createReqVO) {
return success(deviceService.createDevice(createReqVO));
}
@PutMapping("/update-status")
- @Operation(summary = "更新IoT 设备状态")
+ @Operation(summary = "更新设备状态")
@Parameter(name = "id", description = "编号", required = true)
@Parameter(name = "status", description = "状态", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('iot:device:update')")
@@ -55,7 +55,7 @@ public class IotDeviceController {
}
@PutMapping("/update")
- @Operation(summary = "更新IoT 设备")
+ @Operation(summary = "更新设备")
@PreAuthorize("@ss.hasPermission('iot:device:update')")
public CommonResult updateDevice(@Valid @RequestBody IotDeviceSaveReqVO updateReqVO) {
deviceService.updateDevice(updateReqVO);
@@ -63,7 +63,7 @@ public class IotDeviceController {
}
@DeleteMapping("/delete")
- @Operation(summary = "删除IoT 设备")
+ @Operation(summary = "删除设备")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('iot:device:delete')")
public CommonResult deleteDevice(@RequestParam("id") Long id) {
@@ -72,7 +72,7 @@ public class IotDeviceController {
}
@GetMapping("/get")
- @Operation(summary = "获得IoT 设备")
+ @Operation(summary = "获得设备")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('iot:device:query')")
public CommonResult getDevice(@RequestParam("id") Long id) {
@@ -81,7 +81,7 @@ public class IotDeviceController {
}
@GetMapping("/page")
- @Operation(summary = "获得IoT 设备分页")
+ @Operation(summary = "获得设备分页")
@PreAuthorize("@ss.hasPermission('iot:device:query')")
public CommonResult> getDevicePage(@Valid IotDevicePageReqVO pageReqVO) {
PageResult pageResult = deviceService.getDevicePage(pageReqVO);
@@ -89,7 +89,7 @@ public class IotDeviceController {
}
@GetMapping("/export-excel")
- @Operation(summary = "导出IoT 设备 Excel")
+ @Operation(summary = "导出设备 Excel")
@PreAuthorize("@ss.hasPermission('iot:device:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportDeviceExcel(@Valid IotDevicePageReqVO pageReqVO,
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java
index 36a184871..c2cd35685 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java
@@ -1,10 +1,15 @@
package cn.iocoder.yudao.module.iot.controller.admin.device.vo;
-import lombok.*;
-import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
-import java.math.BigDecimal;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
+
+import java.math.BigDecimal;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@@ -15,28 +20,32 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
@ToString(callSuper = true)
public class IotDevicePageReqVO extends PageParam {
- @Schema(description = "设备唯一标识符,全局唯一,用于识别设备")
+ // TODO @芋艿:需要去掉一些多余的字段;
+
+ @Schema(description = "设备唯一标识符", example = "24602")
private String deviceKey;
- @Schema(description = "设备名称,在产品内唯一,用于标识设备", example = "王五")
+ @Schema(description = "设备名称", example = "王五")
private String deviceName;
- @Schema(description = "产品 ID,关联 iot_product 表的 id", example = "26202")
+ @Schema(description = "产品编号", example = "26202")
private Long productId;
- @Schema(description = "产品 Key,关联 iot_product 表的 product_key")
+ @Schema(description = "产品标识")
private String productKey;
- @Schema(description = "设备类型:0 - 直连设备,1 - 网关子设备,2 - 网关设备", example = "1")
+ @Schema(description = "设备类型", example = "1")
+ // TODO @haohao:需要有个设备类型的枚举
private Integer deviceType;
- @Schema(description = "设备备注名称,供用户自定义备注", example = "张三")
+ @Schema(description = "备注名称", example = "张三")
private String nickname;
- @Schema(description = "网关设备 ID,子设备需要关联的网关设备 ID", example = "16380")
+ @Schema(description = "网关设备 ID", example = "16380")
private Long gatewayId;
- @Schema(description = "设备状态:0 - 未激活,1 - 在线,2 - 离线,3 - 已禁用", example = "1")
+ @Schema(description = "设备状态", example = "1")
+ @InEnum(IotDeviceStatusEnum.class)
private Integer status;
@Schema(description = "设备状态最后更新时间")
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java
index 7cf592fc0..0423b17a9 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java
@@ -13,7 +13,7 @@ import java.time.LocalDateTime;
@ExcelIgnoreUnannotated
public class IotDeviceRespVO {
- @Schema(description = "设备 ID,主键,自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
+ @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
private Long id;
@Schema(description = "设备唯一标识符", requiredMode = Schema.RequiredMode.REQUIRED)
@@ -24,11 +24,11 @@ public class IotDeviceRespVO {
@ExcelProperty("设备名称备")
private String deviceName;
- @Schema(description = "产品 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202")
+ @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202")
@ExcelProperty("产品 ID")
private Long productId;
- @Schema(description = "产品 Key", requiredMode = Schema.RequiredMode.REQUIRED)
+ @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("产品 Key")
private String productKey;
@@ -72,7 +72,7 @@ public class IotDeviceRespVO {
@ExcelProperty("设备的固件版本")
private String firmwareVersion;
- @Schema(description = "设备密钥,用于设备认证,需安全存储")
+ @Schema(description = "设备密钥,用于设备认证")
@ExcelProperty("设备密钥")
private String deviceSecret;
@@ -92,16 +92,17 @@ public class IotDeviceRespVO {
@ExcelProperty("认证类型(如一机一密、动态注册)")
private String authType;
- @Schema(description = "设备位置的纬度,范围 -90.000000 ~ 90.000000")
- @ExcelProperty("设备位置的纬度,范围 -90.000000 ~ 90.000000")
+ // TODO @haohao:经纬度:可能 double 就够啦
+ @Schema(description = "设备位置的纬度,范围")
+ @ExcelProperty("设备位置的纬度")
private BigDecimal latitude;
- @Schema(description = "设备位置的经度,范围 -180.000000 ~ 180.000000")
- @ExcelProperty("设备位置的经度,范围 -180.000000 ~ 180.000000")
+ @Schema(description = "设备位置的经度")
+ @ExcelProperty("设备位置的经度")
private BigDecimal longitude;
- @Schema(description = "地区编码,符合国家地区编码标准,关联地区表", example = "16995")
- @ExcelProperty("地区编码,符合国家地区编码标准,关联地区表")
+ @Schema(description = "地区编码", example = "16995")
+ @ExcelProperty("地区编码")
private Integer areaId;
@Schema(description = "设备详细地址")
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java
index f52d8db92..620e5310f 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java
@@ -7,16 +7,16 @@ import lombok.Data;
@Data
public class IotDeviceSaveReqVO {
- @Schema(description = "设备 ID,主键,自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
+ @Schema(description = "设备编号", example = "177")
private Long id;
- @Schema(description = "设备名称,在产品内唯一,用于标识设备", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
+ @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
private String deviceName;
- @Schema(description = "设备备注名称,供用户自定义备注", example = "张三")
+ @Schema(description = "备注名称", example = "张三")
private String nickname;
- @Schema(description = "产品 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202")
+ @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202")
private Long productId;
}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java
index 138913f73..d61e640ae 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.device;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
+import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@@ -13,7 +14,7 @@ import java.time.LocalDateTime;
/**
* IoT 设备 DO
*
- * @author 芋道源码
+ * @author haohao
*/
@TableName("iot_device")
@KeySequence("iot_device_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@@ -39,33 +40,48 @@ public class IotDeviceDO extends BaseDO {
*/
private String deviceName;
/**
- * 产品 ID,关联 iot_product 表的 id
+ * 设备备注名称
+ */
+ private String nickname;
+ /**
+ * 设备序列号
+ */
+ private String serialNumber;
+
+ /**
+ * 产品编号
+ *
* 关联 {@link IotProductDO#getId()}
*/
private Long productId;
/**
- * 产品 Key,关联 iot_product 表的 product_key
- * 关联 {@link IotProductDO#getProductKey()}
+ * 产品标识
+ *
+ * 冗余 {@link IotProductDO#getProductKey()}
*/
private String productKey;
/**
- * 设备类型:0 - 直连设备,1 - 网关子设备,2 - 网关设备
- * 关联 {@link IotProductDO#getDeviceType()}
+ * 设备类型
+ *
+ * 冗余 {@link IotProductDO#getDeviceType()}
*/
private Integer deviceType;
+
/**
- * 设备备注名称,供用户自定义备注
- */
- private String nickname;
- /**
- * 网关设备 ID,子设备需要关联的网关设备 ID
- */
- private Long gatewayId;
- /**
- * 设备状态:0 - 未激活,1 - 在线,2 - 离线,3 - 已禁用
- * 关联 {@link cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum}
+ * 设备状态
+ *
+ * 枚举 {@link IotDeviceStatusEnum}
*/
private Integer status;
+ /**
+ * 网关设备编号
+ *
+ * 子设备需要关联的网关设备 ID
+ *
+ * 关联 {@link IotDeviceDO#getId()}
+ */
+ private Long gatewayId;
+
/**
* 设备状态最后更新时间
*/
@@ -82,6 +98,7 @@ public class IotDeviceDO extends BaseDO {
* 设备激活时间
*/
private LocalDateTime activeTime;
+
/**
* 设备的 IP 地址
*/
@@ -90,6 +107,7 @@ public class IotDeviceDO extends BaseDO {
* 设备的固件版本
*/
private String firmwareVersion;
+
/**
* 设备密钥,用于设备认证,需安全存储
*/
@@ -109,26 +127,26 @@ public class IotDeviceDO extends BaseDO {
/**
* 认证类型(如一机一密、动态注册)
*/
+ // TODO @haohao:是不是要枚举哈
private String authType;
+
/**
- * 设备位置的纬度,范围 -90.000000 ~ 90.000000
+ * 设备位置的纬度
*/
private BigDecimal latitude;
/**
- * 设备位置的经度,范围 -180.000000 ~ 180.000000
+ * 设备位置的经度
*/
private BigDecimal longitude;
/**
- * 地区编码,符合国家地区编码标准,关联地区表
+ * 地区编码
+ *
+ * 关联 Area 的 id
*/
private Integer areaId;
/**
* 设备详细地址
*/
private String address;
- /**
- * 设备序列号
- */
- private String serialNumber;
}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java
index fc7d0a71f..0224c6da3 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java
@@ -53,4 +53,5 @@ public interface IotDeviceMapper extends BaseMapperX {
default long selectCountByGatewayId(Long id) {
return selectCount(IotDeviceDO::getGatewayId, id);
}
+
}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java
index b1e7ffbdd..0b4db169f 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.iot.service.device;
+import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
@@ -34,6 +35,7 @@ public class DeviceServiceImpl implements IotDeviceService {
@Resource
private IotDeviceMapper deviceMapper;
+ // TODO @haohao:不直接调用 productmapper,通过 productservice;每一个模型,不直接使用对方的
@Resource
private IotProductMapper productMapper;
@@ -46,40 +48,33 @@ public class DeviceServiceImpl implements IotDeviceService {
@Override
@Transactional(rollbackFor = Exception.class)
public Long createDevice(IotDeviceSaveReqVO createReqVO) {
- // 1. 转换 VO 为 DO
- IotDeviceDO device = BeanUtils.toBean(createReqVO, IotDeviceDO.class);
-
- // 2. 根据产品 ID 查询产品信息
+ // 1.1 校验产品是否存在
IotProductDO product = productMapper.selectById(createReqVO.getProductId());
if (product == null) {
throw exception(PRODUCT_NOT_EXISTS);
}
- device.setProductKey(product.getProductKey());
- device.setDeviceType(product.getDeviceType());
-
- // 3. DeviceName 可以为空,当为空时,自动生成产品下的唯一标识符作为 DeviceName
- if (StrUtil.isBlank(device.getDeviceName())) {
- device.setDeviceName(generateUniqueDeviceName(createReqVO.getProductId()));
+ // 1.2 校验设备名称在同一产品下是否唯一
+ if (StrUtil.isBlank(createReqVO.getDeviceName())) {
+ createReqVO.setDeviceName(generateUniqueDeviceName(product.getProductKey()));
+ } else {
+ validateDeviceNameUnique(product.getProductKey(), createReqVO.getDeviceName());
}
- // 4. 校验设备名称在同一产品下是否唯一
- validateDeviceNameUnique(device.getProductKey(), device.getDeviceName());
-
- // 5. 生成并设置必要的字段
+ // 2.1 转换 VO 为 DO
+ IotDeviceDO device = BeanUtils.toBean(createReqVO, IotDeviceDO.class)
+ .setProductKey(product.getProductKey())
+ .setDeviceType(product.getDeviceType());
+ // 2.2 生成并设置必要的字段
device.setDeviceKey(generateUniqueDeviceKey());
device.setDeviceSecret(generateDeviceSecret());
device.setMqttClientId(generateMqttClientId());
device.setMqttUsername(generateMqttUsername(device.getDeviceName(), device.getProductKey()));
device.setMqttPassword(generateMqttPassword());
-
- // 6. 设置设备状态为未激活
+ // 2.3 设置设备状态为未激活
device.setStatus(IotDeviceStatusEnum.INACTIVE.getStatus());
device.setStatusLastUpdateTime(LocalDateTime.now());
-
- // 7. 插入到数据库
+ // 2.4 插入到数据库
deviceMapper.insert(device);
-
- // 8. 返回生成的设备 ID
return device.getId();
}
@@ -111,7 +106,7 @@ public class DeviceServiceImpl implements IotDeviceService {
* @return 生成的 deviceSecret
*/
private String generateDeviceSecret() {
- // 32 位随机字符串
+ // TODO @haohao:return IdUtil.fastSimpleUUID()
return UUID.randomUUID().toString().replace("-", "");
}
@@ -141,39 +136,25 @@ public class DeviceServiceImpl implements IotDeviceService {
* @return 生成的 MQTT Password
*/
private String generateMqttPassword() {
- // 在实际应用中,建议使用更安全的方法生成 MQTT Password,如加密或哈希
+ // TODO @haohao:【后续优化】在实际应用中,建议使用更安全的方法生成 MQTT Password,如加密或哈希
return UUID.randomUUID().toString();
}
/**
* 生成唯一的 DeviceName
*
- * @param productId 产品 ID
+ * @param productKey 产品标识
* @return 生成的唯一 DeviceName
*/
- private String generateUniqueDeviceName(Long productId) {
- // 实现逻辑以在产品下生成唯一的设备名称
- String deviceName;
- String productKey = getProductKey(productId);
- do {
- // 20 位随机字符串
- deviceName = UUID.randomUUID().toString().replace("-", "").substring(0, 20);
- } while (deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName) != null);
- return deviceName;
- }
-
- /**
- * 获取产品 Key
- *
- * @param productId 产品 ID
- * @return 产品 Key
- */
- private String getProductKey(Long productId) {
- IotProductDO product = productMapper.selectById(productId);
- if (product == null) {
- throw exception(PRODUCT_NOT_EXISTS);
+ private String generateUniqueDeviceName(String productKey) {
+ // TODO @haohao:业务逻辑里,尽量避免 while true。万一 bug = =;虽然这个不会哈。我先改了下
+ for (int i = 0; i < Short.MAX_VALUE; i++) {
+ String deviceName = IdUtil.fastSimpleUUID().substring(0, 20);
+ if (deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName) != null) {
+ return deviceName;
+ }
}
- return product.getProductKey();
+ throw new IllegalArgumentException("生成 DeviceName 失败");
}
@Override
@@ -183,6 +164,7 @@ public class DeviceServiceImpl implements IotDeviceService {
IotDeviceDO existingDevice = validateDeviceExists(updateReqVO.getId());
// 设备名称 和 产品 ID 不能修改
+ // TODO @haohao:这种,直接设置为 null 就不会更新了。忽略前端的传参
if (updateReqVO.getDeviceName() != null && !updateReqVO.getDeviceName().equals(existingDevice.getDeviceName())) {
throw exception(DEVICE_NAME_CANNOT_BE_MODIFIED);
}
@@ -200,18 +182,14 @@ public class DeviceServiceImpl implements IotDeviceService {
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteDevice(Long id) {
- // 校验存在
- IotDeviceDO iotDeviceDO = validateDeviceExists(id);
-
- // 如果是网关设备,检查是否有子设备
- if (iotDeviceDO.getGatewayId() != null) {
- long childCount = deviceMapper.selectCountByGatewayId(id);
- if (childCount > 0) {
- throw exception(DEVICE_HAS_CHILDREN);
- }
+ // 1.1 校验存在
+ IotDeviceDO device = validateDeviceExists(id);
+ // 1.2 如果是网关设备,检查是否有子设备
+ if (device.getGatewayId() != null && deviceMapper.selectCountByGatewayId(id) > 0) {
+ throw exception(DEVICE_HAS_CHILDREN);
}
- // 删除设备
+ // 2. 删除设备
deviceMapper.deleteById(id);
}
@@ -222,11 +200,11 @@ public class DeviceServiceImpl implements IotDeviceService {
* @return 设备对象
*/
private IotDeviceDO validateDeviceExists(Long id) {
- IotDeviceDO iotDeviceDO = deviceMapper.selectById(id);
- if (iotDeviceDO == null) {
+ IotDeviceDO device = deviceMapper.selectById(id);
+ if (device == null) {
throw exception(DEVICE_NOT_EXISTS);
}
- return iotDeviceDO;
+ return device;
}
@Override
@@ -244,21 +222,20 @@ public class DeviceServiceImpl implements IotDeviceService {
}
@Override
- @Transactional(rollbackFor = Exception.class)
public void updateDeviceStatus(Long id, Integer status) {
// 校验存在
validateDeviceExists(id);
+ // TODO @haohao:这个可以直接用 swagger 注解哈
// 校验状态是否合法
if (!IotDeviceStatusEnum.isValidStatus(status)) {
throw exception(DEVICE_INVALID_DEVICE_STATUS);
}
// 更新状态和更新时间
- IotDeviceDO updateObj = new IotDeviceDO()
- .setId(id)
- .setStatus(status)
+ IotDeviceDO updateObj = new IotDeviceDO().setId(id).setStatus(status)
.setStatusLastUpdateTime(LocalDateTime.now());
deviceMapper.updateById(updateObj);
}
+
}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java
index 2802806de..9b6de37bf 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java
@@ -13,7 +13,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
public interface IotDeviceService {
/**
- * 创建IoT 设备
+ * 创建设备
*
* @param createReqVO 创建信息
* @return 编号
@@ -21,21 +21,21 @@ public interface IotDeviceService {
Long createDevice(@Valid IotDeviceSaveReqVO createReqVO);
/**
- * 更新IoT 设备
+ * 更新设备
*
* @param updateReqVO 更新信息
*/
void updateDevice(@Valid IotDeviceSaveReqVO updateReqVO);
/**
- * 删除IoT 设备
+ * 删除设备
*
* @param id 编号
*/
void deleteDevice(Long id);
/**
- * 获得IoT 设备
+ * 获得设备
*
* @param id 编号
* @return IoT 设备
@@ -43,7 +43,7 @@ public interface IotDeviceService {
IotDeviceDO getDevice(Long id);
/**
- * 获得IoT 设备分页
+ * 获得设备分页
*
* @param pageReqVO 分页查询
* @return IoT 设备分页
@@ -51,10 +51,11 @@ public interface IotDeviceService {
PageResult getDevicePage(IotDevicePageReqVO pageReqVO);
/**
- * 更新IoT 设备状态
+ * 更新设备状态
*
* @param id 编号
* @param status 状态
*/
void updateDeviceStatus(Long id, Integer status);
+
}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
index 9dc803e66..64ff3d319 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
@@ -170,7 +170,6 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
// 3.1 使用 diffList 方法比较新旧列表
List> diffResult = diffList(oldFunctionList, newFunctionList,
- // TODO @haohao:是不是用 id 比较相同就 ok 哈。如果可以的化,下面的 update 可以更简单
// 继续使用 identifier 和 type 进行比较:这样可以准确地匹配对应的功能对象。
(oldFunc, newFunc) -> Objects.equals(oldFunc.getIdentifier(), newFunc.getIdentifier())
&& Objects.equals(oldFunc.getType(), newFunc.getType()));
@@ -191,6 +190,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
thinkModelFunctionMapper.updateById(updateFunc);
}
}
+ // TODO @haohao:seckillProductMapper.updateBatch(diffList.get(1)); 可以直接类似这么操作哇?
}
if (CollUtil.isNotEmpty(deleteList)) {
Set idsToDelete = CollectionUtils.convertSet(deleteList, IotThinkModelFunctionDO::getId);
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml
deleted file mode 100644
index 039dbd895..000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/thinkmodelfunction/IotThinkModelFunctionMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/thinkmodelfunction/IotThinkModelFunctionMapper.xml
deleted file mode 100644
index 525a32bd6..000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/thinkmodelfunction/IotThinkModelFunctionMapper.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImplTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImplTest.java
deleted file mode 100644
index a456589cb..000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImplTest.java
+++ /dev/null
@@ -1,219 +0,0 @@
-package cn.iocoder.yudao.module.iot.service.device;
-
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Test;
-
-import jakarta.annotation.Resource;
-
-import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
-
-import cn.iocoder.yudao.module.iot.controller.admin.device.vo.*;
-import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
-import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-
-import org.springframework.context.annotation.Import;
-
-import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
-import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
-import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
-import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
-import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
-import static org.junit.jupiter.api.Assertions.*;
-
-/**
- * {@link DeviceServiceImpl} 的单元测试类
- *
- * @author 芋道源码
- */
-@Import(DeviceServiceImpl.class)
-public class DeviceServiceImplTest extends BaseDbUnitTest {
-
- @Resource
- private DeviceServiceImpl deviceService;
-
- @Resource
- private IotDeviceMapper deviceMapper;
-
- @Test
- public void testCreateDevice_success() {
- // 准备参数
- IotDeviceSaveReqVO createReqVO = randomPojo(IotDeviceSaveReqVO.class).setId(null);
-
- // 调用
- Long deviceId = deviceService.createDevice(createReqVO);
- // 断言
- assertNotNull(deviceId);
- // 校验记录的属性是否正确
- IotDeviceDO device = deviceMapper.selectById(deviceId);
- assertPojoEquals(createReqVO, device, "id");
- }
-
- @Test
- public void testUpdateDevice_success() {
- // mock 数据
- IotDeviceDO dbDevice = randomPojo(IotDeviceDO.class);
- deviceMapper.insert(dbDevice);// @Sql: 先插入出一条存在的数据
- // 准备参数
- IotDeviceSaveReqVO updateReqVO = randomPojo(IotDeviceSaveReqVO.class, o -> {
- o.setId(dbDevice.getId()); // 设置更新的 ID
- });
-
- // 调用
- deviceService.updateDevice(updateReqVO);
- // 校验是否更新正确
- IotDeviceDO device = deviceMapper.selectById(updateReqVO.getId()); // 获取最新的
- assertPojoEquals(updateReqVO, device);
- }
-
- @Test
- public void testUpdateDevice_notExists() {
- // 准备参数
- IotDeviceSaveReqVO updateReqVO = randomPojo(IotDeviceSaveReqVO.class);
-
- // 调用, 并断言异常
- assertServiceException(() -> deviceService.updateDevice(updateReqVO), DEVICE_NOT_EXISTS);
- }
-
- @Test
- public void testDeleteDevice_success() {
- // mock 数据
- IotDeviceDO dbDevice = randomPojo(IotDeviceDO.class);
- deviceMapper.insert(dbDevice);// @Sql: 先插入出一条存在的数据
- // 准备参数
- Long id = dbDevice.getId();
-
- // 调用
- deviceService.deleteDevice(id);
- // 校验数据不存在了
- assertNull(deviceMapper.selectById(id));
- }
-
- @Test
- public void testDeleteDevice_notExists() {
- // 准备参数
- Long id = randomLongId();
-
- // 调用, 并断言异常
- assertServiceException(() -> deviceService.deleteDevice(id), DEVICE_NOT_EXISTS);
- }
-
- @Test
- @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
- public void testGetDevicePage() {
- // mock 数据
- IotDeviceDO dbDevice = randomPojo(IotDeviceDO.class, o -> { // 等会查询到
- o.setDeviceKey(null);
- o.setDeviceName(null);
- o.setProductId(null);
- o.setProductKey(null);
- o.setDeviceType(null);
- o.setNickname(null);
- o.setGatewayId(null);
- o.setStatus(null);
- o.setStatusLastUpdateTime(null);
- o.setLastOnlineTime(null);
- o.setLastOfflineTime(null);
- o.setActiveTime(null);
- o.setIp(null);
- o.setFirmwareVersion(null);
- o.setDeviceSecret(null);
- o.setMqttClientId(null);
- o.setMqttUsername(null);
- o.setMqttPassword(null);
- o.setAuthType(null);
- o.setLatitude(null);
- o.setLongitude(null);
- o.setAreaId(null);
- o.setAddress(null);
- o.setSerialNumber(null);
- o.setCreateTime(null);
- });
- deviceMapper.insert(dbDevice);
- // 测试 deviceKey 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setDeviceKey(null)));
- // 测试 deviceName 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setDeviceName(null)));
- // 测试 productId 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setProductId(null)));
- // 测试 productKey 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setProductKey(null)));
- // 测试 deviceType 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setDeviceType(null)));
- // 测试 nickname 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setNickname(null)));
- // 测试 gatewayId 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setGatewayId(null)));
- // 测试 status 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setStatus(null)));
- // 测试 statusLastUpdateTime 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setStatusLastUpdateTime(null)));
- // 测试 lastOnlineTime 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setLastOnlineTime(null)));
- // 测试 lastOfflineTime 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setLastOfflineTime(null)));
- // 测试 activeTime 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setActiveTime(null)));
- // 测试 ip 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setIp(null)));
- // 测试 firmwareVersion 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setFirmwareVersion(null)));
- // 测试 deviceSecret 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setDeviceSecret(null)));
- // 测试 mqttClientId 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setMqttClientId(null)));
- // 测试 mqttUsername 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setMqttUsername(null)));
- // 测试 mqttPassword 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setMqttPassword(null)));
- // 测试 authType 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setAuthType(null)));
- // 测试 latitude 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setLatitude(null)));
- // 测试 longitude 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setLongitude(null)));
- // 测试 areaId 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setAreaId(null)));
- // 测试 address 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setAddress(null)));
- // 测试 serialNumber 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setSerialNumber(null)));
- // 测试 createTime 不匹配
- deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setCreateTime(null)));
- // 准备参数
- IotDevicePageReqVO reqVO = new IotDevicePageReqVO();
- reqVO.setDeviceKey(null);
- reqVO.setDeviceName(null);
- reqVO.setProductId(null);
- reqVO.setProductKey(null);
- reqVO.setDeviceType(null);
- reqVO.setNickname(null);
- reqVO.setGatewayId(null);
- reqVO.setStatus(null);
- reqVO.setStatusLastUpdateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
- reqVO.setLastOnlineTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
- reqVO.setLastOfflineTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
- reqVO.setActiveTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
- reqVO.setIp(null);
- reqVO.setFirmwareVersion(null);
- reqVO.setDeviceSecret(null);
- reqVO.setMqttClientId(null);
- reqVO.setMqttUsername(null);
- reqVO.setMqttPassword(null);
- reqVO.setAuthType(null);
- reqVO.setLatitude(null);
- reqVO.setLongitude(null);
- reqVO.setAreaId(null);
- reqVO.setAddress(null);
- reqVO.setSerialNumber(null);
- reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
-
- // 调用
- PageResult pageResult = deviceService.getDevicePage(reqVO);
- // 断言
- assertEquals(1, pageResult.getTotal());
- assertEquals(1, pageResult.getList().size());
- assertPojoEquals(dbDevice, pageResult.getList().get(0));
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImplTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImplTest.java
deleted file mode 100644
index 762f6021b..000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImplTest.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package cn.iocoder.yudao.module.iot.service.thinkmodelfunction;
-
-import org.junit.jupiter.api.Test;
-
-import jakarta.annotation.Resource;
-
-import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
-
-import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.*;
-import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
-import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper;
-
-import org.springframework.context.annotation.Import;
-
-import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
-import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
-import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
-import static org.junit.jupiter.api.Assertions.*;
-
-/**
- * {@link IotThinkModelFunctionServiceImpl} 的单元测试类
- *
- * @author 芋道源码
- */
-@Import(IotThinkModelFunctionServiceImpl.class)
-public class IotThinkModelFunctionServiceImplTest extends BaseDbUnitTest {
-
- @Resource
- private IotThinkModelFunctionServiceImpl thinkModelFunctionService;
-
- @Resource
- private IotThinkModelFunctionMapper thinkModelFunctionMapper;
-
- @Test
- public void testCreateThinkModelFunction_success() {
- // 准备参数
- IotThinkModelFunctionSaveReqVO createReqVO = randomPojo(IotThinkModelFunctionSaveReqVO.class);
-
- // 调用
- Long thinkModelFunctionId = thinkModelFunctionService.createThinkModelFunction(createReqVO);
- // 断言
- assertNotNull(thinkModelFunctionId);
- // 校验记录的属性是否正确
- IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionMapper.selectById(thinkModelFunctionId);
- assertPojoEquals(createReqVO, thinkModelFunction, "id");
- }
-
- @Test
- public void testDeleteThinkModelFunction_success() {
- // mock 数据
- IotThinkModelFunctionDO dbThinkModelFunction = randomPojo(IotThinkModelFunctionDO.class);
- thinkModelFunctionMapper.insert(dbThinkModelFunction);// @Sql: 先插入出一条存在的数据
- // 准备参数
- Long id = dbThinkModelFunction.getId();
-
- // 调用
- thinkModelFunctionService.deleteThinkModelFunction(id);
- // 校验数据不存在了
- assertNull(thinkModelFunctionMapper.selectById(id));
- }
-
- @Test
- public void testDeleteThinkModelFunction_notExists() {
- // 准备参数
- Long id = randomLongId();
-
- // 调用, 并断言异常
- assertServiceException(() -> thinkModelFunctionService.deleteThinkModelFunction(id), THINK_MODEL_FUNCTION_NOT_EXISTS);
- }
-
-}
\ No newline at end of file
From 643e28938458a740b5975f99992533c0c10d70e0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com>
Date: Sun, 22 Sep 2024 13:16:32 +0800
Subject: [PATCH 27/31] =?UTF-8?q?=E3=80=90=E4=BC=98=E5=8C=96=E3=80=91IOT?=
=?UTF-8?q?=20=E8=AE=BE=E5=A4=87=E7=AE=A1=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../admin/device/IotDeviceController.java | 21 ++---------
.../admin/device/vo/IotDevicePageReqVO.java | 30 +++-------------
.../admin/device/vo/IotDeviceRespVO.java | 32 +----------------
.../device/vo/IotDeviceStatusUpdateReqVO.java | 21 +++++++++++
.../admin/product/IotProductController.java | 11 ++++++
.../product/vo/IotProductSimpleRespVO.java | 16 +++++++++
.../dal/dataobject/device/IotDeviceDO.java | 14 ++++----
.../iot/dal/mysql/device/IotDeviceMapper.java | 7 ----
.../dal/mysql/product/IotProductMapper.java | 1 +
.../iot/service/device/DeviceServiceImpl.java | 36 ++++++-------------
.../iot/service/device/IotDeviceService.java | 5 ++-
.../service/product/IotProductService.java | 10 ++++++
.../product/IotProductServiceImpl.java | 6 ++++
.../IotThinkModelFunctionServiceImpl.java | 20 ++++++++---
14 files changed, 110 insertions(+), 120 deletions(-)
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceStatusUpdateReqVO.java
create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSimpleRespVO.java
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java
index e455c78cf..15c54b6ab 100644
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java
+++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java
@@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceRespVO;
import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceStatusUpdateReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
import io.swagger.v3.oas.annotations.Operation;
@@ -45,12 +46,9 @@ public class IotDeviceController {
@PutMapping("/update-status")
@Operation(summary = "更新设备状态")
- @Parameter(name = "id", description = "编号", required = true)
- @Parameter(name = "status", description = "状态", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('iot:device:update')")
- public CommonResult updateDeviceStatus(@RequestParam("id") Long id,
- @RequestParam("status") Integer status) {
- deviceService.updateDeviceStatus(id, status);
+ public CommonResult