Commit 4075fde7654f10a03cd87ed5e39ee2890c5ee1a8

Authored by 芋道源码
Committed by Gitee
2 parents 7b64b7fc fae17e91

!1171 【功能完善】IOT: ThingModel 服务和事件

Merge pull request !1171 from puhui999/iot
Showing 13 changed files with 293 additions and 282 deletions
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelAccessModeEnum.java
@@ -4,7 +4,7 @@ import lombok.AllArgsConstructor; @@ -4,7 +4,7 @@ import lombok.AllArgsConstructor;
4 import lombok.Getter; 4 import lombok.Getter;
5 5
6 /** 6 /**
7 - * IOT 访问方式枚举类 7 + * IOT 产品物模型属性读取类型枚举
8 * 8 *
9 * @author ahh 9 * @author ahh
10 */ 10 */
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelParamDirectionEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.thingmodel;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * IOT 产品物模型参数是输入参数还是输出参数枚举
  8 + *
  9 + * @author HUIHUI
  10 + */
  11 +@AllArgsConstructor
  12 +@Getter
  13 +public enum IotProductThingModelParamDirectionEnum {
  14 +
  15 + INPUT("input"), // 输入参数
  16 + OUTPUT("output"); // 输出参数
  17 +
  18 + private final String direction;
  19 +
  20 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceCallTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.thingmodel;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * IOT 产品物模型服务调用方式枚举
  8 + *
  9 + * @author HUIHUI
  10 + */
  11 +@AllArgsConstructor
  12 +@Getter
  13 +public enum IotProductThingModelServiceCallTypeEnum {
  14 +
  15 + ASYNC("async"), // 异步调用
  16 + SYNC("sync"); // 同步调用
  17 +
  18 + private final String type;
  19 +
  20 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotProductThingModelServiceEventTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.thingmodel;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * IOT 产品物模型事件类型枚举
  8 + *
  9 + * @author HUIHUI
  10 + */
  11 +@AllArgsConstructor
  12 +@Getter
  13 +public enum IotProductThingModelServiceEventTypeEnum {
  14 +
  15 + INFO("info"), // 信息
  16 + ALERT("alert"), // 告警
  17 + ERROR("error"); // 故障
  18 +
  19 + private final String type;
  20 +
  21 +}
yudao-module-iot/yudao-module-iot-biz/pom.xml
@@ -27,13 +27,6 @@ @@ -27,13 +27,6 @@
27 27
28 <dependency> 28 <dependency>
29 <groupId>cn.iocoder.boot</groupId> 29 <groupId>cn.iocoder.boot</groupId>
30 - <artifactId>yudao-module-iot-plugin-api</artifactId>  
31 - <version>0.0.1</version>  
32 - <scope>compile</scope>  
33 - </dependency>  
34 -  
35 - <dependency>  
36 - <groupId>cn.iocoder.boot</groupId>  
37 <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId> 30 <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
38 </dependency> 31 </dependency>
39 32
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotProductThingModelController.http
@@ -176,7 +176,7 @@ tenant-id: {{adminTenentId}} @@ -176,7 +176,7 @@ tenant-id: {{adminTenentId}}
176 Authorization: Bearer {{token}} 176 Authorization: Bearer {{token}}
177 177
178 ### 请求 /iot/product-thing-model/get 接口 => 成功 178 ### 请求 /iot/product-thing-model/get 接口 => 成功
179 -GET {{baseUrl}}/iot/product-thing-model/get?id=40 179 +GET {{baseUrl}}/iot/product-thing-model/get?id=67
180 tenant-id: {{adminTenentId}} 180 tenant-id: {{adminTenentId}}
181 Authorization: Bearer {{token}} 181 Authorization: Bearer {{token}}
182 182
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java
1 package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; 1 package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model;
2 2
3 -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelArgument; 3 +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelServiceEventTypeEnum;
4 import lombok.Data; 4 import lombok.Data;
  5 +
5 import java.util.List; 6 import java.util.List;
6 7
  8 +/**
  9 + * 物模型中的事件
  10 + *
  11 + * @author HUIHUI
  12 + */
7 @Data 13 @Data
8 public class ThingModelEvent { 14 public class ThingModelEvent {
9 15
@@ -16,17 +22,27 @@ public class ThingModelEvent { @@ -16,17 +22,27 @@ public class ThingModelEvent {
16 */ 22 */
17 private String name; 23 private String name;
18 /** 24 /**
19 - * 事件描述 25 + * 是否是标准品类的必选事件。
  26 + *
  27 + * - true:是
  28 + * - false:否
20 */ 29 */
21 - private String description;  
22 - 30 + private Boolean required;
23 /** 31 /**
24 * 事件类型 32 * 事件类型
25 * 33 *
26 - * "info"、"alert"、"error" 34 + * 关联枚举 {@link IotProductThingModelServiceEventTypeEnum}
27 */ 35 */
28 private String type; 36 private String type;
29 - private List<ThingModelArgument> outputData; 37 + /**
  38 + * 事件的输出参数
  39 + *
  40 + * 输出参数定义事件调用后返回的结果或反馈信息,用于确认操作结果或提供额外的信息。
  41 + */
  42 + private List<ThingModelInputOutputParam> outputParams;
  43 + /**
  44 + * 标识设备需要执行的具体操作
  45 + */
30 private String method; 46 private String method;
31 47
32 } 48 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelInputOutputParam.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model;
  2 +
  3 +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDataSpecs;
  4 +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelParamDirectionEnum;
  5 +import lombok.Data;
  6 +
  7 +import java.util.List;
  8 +
  9 +/**
  10 + * IOT 产品物模型中的参数 // TODO @puhui999 考虑要不改成 ThingModelParam ?
  11 + *
  12 + * @author HUIHUI
  13 + */
  14 +@Data
  15 +public class ThingModelInputOutputParam {
  16 +
  17 + /**
  18 + * 参数标识符
  19 + */
  20 + private String identifier;
  21 + /**
  22 + * 参数名称
  23 + */
  24 + private String name;
  25 + /**
  26 + * 用于区分输入或输出参数
  27 + *
  28 + * 关联枚举 {@link IotProductThingModelParamDirectionEnum}
  29 + */
  30 + private String direction;
  31 + /**
  32 + * 参数的序号。从 0 开始排序,且不能重复。
  33 + *
  34 + * TODO 考虑要不要序号,感觉是要的, 先留一手看看
  35 + */
  36 + private Integer paraOrder;
  37 + /**
  38 + * 参数值的数据类型,与 dataSpecs 的 dataType 保持一致
  39 + */
  40 + private String dataType;
  41 + /**
  42 + * 参数值的数据类型(dataType)为非列表型(int、float、double、text、date、array)的数据规范存储在 dataSpecs 中
  43 + */
  44 + private ThingModelDataSpecs dataSpecs;
  45 + /**
  46 + * 参数值的数据类型(dataType)为列表型(enum、bool、struct)的数据规范存储在 dataSpecsList 中
  47 + */
  48 + private List<ThingModelDataSpecs> dataSpecsList;
  49 +
  50 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java
@@ -25,10 +25,6 @@ public class ThingModelProperty { @@ -25,10 +25,6 @@ public class ThingModelProperty {
25 */ 25 */
26 private String name; 26 private String name;
27 /** 27 /**
28 - * 属性描述  
29 - */  
30 - private String description;  
31 - /**  
32 * 云端可以对该属性进行的操作类型 28 * 云端可以对该属性进行的操作类型
33 * 29 *
34 * 枚举 {@link IotProductThingModelAccessModeEnum} 30 * 枚举 {@link IotProductThingModelAccessModeEnum}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java
1 package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; 1 package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model;
2 2
3 -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelArgument; 3 +import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelServiceCallTypeEnum;
4 import lombok.Data; 4 import lombok.Data;
  5 +
5 import java.util.List; 6 import java.util.List;
6 7
  8 +/**
  9 + * 物模型中的服务
  10 + *
  11 + * @author HUIHUI
  12 + */
7 @Data 13 @Data
8 public class ThingModelService { 14 public class ThingModelService {
9 15
@@ -16,18 +22,33 @@ public class ThingModelService { @@ -16,18 +22,33 @@ public class ThingModelService {
16 */ 22 */
17 private String name; 23 private String name;
18 /** 24 /**
19 - * 服务描述 25 + * 是否是标准品类的必选服务。
  26 + *
  27 + * - true:是
  28 + * - false:否
20 */ 29 */
21 - private String description;  
22 - 30 + private Boolean required;
23 /** 31 /**
24 * 调用类型 32 * 调用类型
25 * 33 *
26 - * "sync"、"async" 34 + * 关联枚举 {@link IotProductThingModelServiceCallTypeEnum}
27 */ 35 */
28 private String callType; 36 private String callType;
29 - private List<ThingModelArgument> inputData;  
30 - private List<ThingModelArgument> outputData; 37 + /**
  38 + * 服务的输入参数
  39 + *
  40 + * 输入参数定义服务调用时所需提供的信息,用于控制设备行为或执行特定任务
  41 + */
  42 + private List<ThingModelInputOutputParam> inputParams;
  43 + /**
  44 + * 服务的输出参数
  45 + *
  46 + * 输出参数定义服务调用后返回的结果或反馈信息,用于确认操作结果或提供额外的信息。
  47 + */
  48 + private List<ThingModelInputOutputParam> outputParams;
  49 + /**
  50 + * 标识设备需要执行的具体操作
  51 + */
31 private String method; 52 private String method;
32 53
33 } 54 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelArgument.java deleted
1 -package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType;  
2 -  
3 -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty;  
4 -import com.fasterxml.jackson.annotation.JsonIgnoreProperties;  
5 -import lombok.Data;  
6 -  
7 -@Data  
8 -@JsonIgnoreProperties(ignoreUnknown = true)  
9 -public class ThingModelArgument {  
10 -  
11 - public static final String DIRECTION_INPUT = "input";  
12 - public static final String DIRECTION_OUTPUT = "output";  
13 -  
14 - private String identifier;  
15 - private String name;  
16 - /**  
17 - * 物模型中的属性  
18 - */  
19 - private ThingModelProperty property;  
20 - /**  
21 - * 用于区分输入或输出参数,"input" 或 "output"  
22 - */  
23 - private String direction;  
24 - private String description;  
25 -  
26 -}  
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/dataType/ThingModelStructDataSpecs.java
@@ -26,10 +26,6 @@ public class ThingModelStructDataSpecs extends ThingModelDataSpecs { @@ -26,10 +26,6 @@ public class ThingModelStructDataSpecs extends ThingModelDataSpecs {
26 */ 26 */
27 private String name; 27 private String name;
28 /** 28 /**
29 - * 属性描述  
30 - */  
31 - private String description;  
32 - /**  
33 * 云端可以对该属性进行的操作类型 29 * 云端可以对该属性进行的操作类型
34 * 关联枚举 {@link IotProductThingModelAccessModeEnum} 30 * 关联枚举 {@link IotProductThingModelAccessModeEnum}
35 */ 31 */
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotProductThingModelServiceImpl.java
@@ -3,14 +3,10 @@ package cn.iocoder.yudao.module.iot.service.thingmodel; @@ -3,14 +3,10 @@ package cn.iocoder.yudao.module.iot.service.thingmodel;
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.ObjectUtil; 4 import cn.hutool.core.util.ObjectUtil;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
7 -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; 6 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
8 import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; 7 import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent;
9 -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; 8 +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelInputOutputParam;
10 import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; 9 import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService;
11 -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelArgument;  
12 -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelArrayDataSpecs;  
13 -import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs;  
14 import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelPageReqVO; 10 import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelPageReqVO;
15 import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelSaveReqVO; 11 import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelSaveReqVO;
16 import cn.iocoder.yudao.module.iot.convert.thingmodel.IotProductThingModelConvert; 12 import cn.iocoder.yudao.module.iot.convert.thingmodel.IotProductThingModelConvert;
@@ -18,8 +14,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; @@ -18,8 +14,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
18 import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; 14 import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO;
19 import cn.iocoder.yudao.module.iot.dal.mysql.thingmodel.IotProductThingModelMapper; 15 import cn.iocoder.yudao.module.iot.dal.mysql.thingmodel.IotProductThingModelMapper;
20 import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; 16 import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum;
21 -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelAccessModeEnum;  
22 -import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum; 17 +import cn.iocoder.yudao.module.iot.enums.thingmodel.*;
23 import cn.iocoder.yudao.module.iot.service.product.IotProductService; 18 import cn.iocoder.yudao.module.iot.service.product.IotProductService;
24 import jakarta.annotation.Resource; 19 import jakarta.annotation.Resource;
25 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
@@ -30,8 +25,7 @@ import org.springframework.validation.annotation.Validated; @@ -30,8 +25,7 @@ import org.springframework.validation.annotation.Validated;
30 import java.util.*; 25 import java.util.*;
31 26
32 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 27 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
33 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;  
34 -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; 28 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
35 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; 29 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
36 30
37 /** 31 /**
@@ -73,37 +67,10 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ @@ -73,37 +67,10 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ
73 if (Objects.equals(createReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { 67 if (Objects.equals(createReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) {
74 createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); 68 createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey());
75 } 69 }
  70 + // TODO @puhui999: 服务和事件的情况 method 怎么设置?在前端设置还是后端设置?
76 return thingModel.getId(); 71 return thingModel.getId();
77 } 72 }
78 73
79 - private void validateProductStatus(Long createReqVO) {  
80 - IotProductDO product = productService.getProduct(createReqVO);  
81 - if (Objects.equals(product.getStatus(), IotProductStatusEnum.PUBLISHED.getStatus())) {  
82 - throw exception(PRODUCT_STATUS_NOT_ALLOW_THING_MODEL);  
83 - }  
84 - }  
85 -  
86 - private void validateNotDefaultEventAndService(String identifier) {  
87 - // set, get, post, property, event, time, value 是系统保留字段,不能用于标识符定义  
88 - if (CollUtil.containsAny(Arrays.asList("set", "get", "post", "property", "event", "time", "value"), Collections.singletonList(identifier))) {  
89 - throw exception(THING_MODEL_IDENTIFIER_INVALID);  
90 - }  
91 - }  
92 -  
93 - private void validateNameUnique(Long productId, String name) {  
94 - IotProductThingModelDO thingModel = productThingModelMapper.selectByProductIdAndName(productId, name);  
95 - if (thingModel != null) {  
96 - throw exception(THING_MODEL_NAME_EXISTS);  
97 - }  
98 - }  
99 -  
100 - private void validateIdentifierUnique(Long productId, String identifier) {  
101 - IotProductThingModelDO thingModel = productThingModelMapper.selectByProductIdAndIdentifier(productId, identifier);  
102 - if (thingModel != null) {  
103 - throw exception(THING_MODEL_IDENTIFIER_EXISTS);  
104 - }  
105 - }  
106 -  
107 @Override 74 @Override
108 @Transactional(rollbackFor = Exception.class) 75 @Transactional(rollbackFor = Exception.class)
109 public void updateProductThingModel(IotProductThingModelSaveReqVO updateReqVO) { 76 public void updateProductThingModel(IotProductThingModelSaveReqVO updateReqVO) {
@@ -126,13 +93,6 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ @@ -126,13 +93,6 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ
126 } 93 }
127 } 94 }
128 95
129 - private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) {  
130 - IotProductThingModelDO thingModel = productThingModelMapper.selectByProductIdAndIdentifier(productId, identifier);  
131 - if (thingModel != null && ObjectUtil.notEqual(thingModel.getId(), id)) {  
132 - throw exception(THING_MODEL_IDENTIFIER_EXISTS);  
133 - }  
134 - }  
135 -  
136 @Override 96 @Override
137 @Transactional(rollbackFor = Exception.class) 97 @Transactional(rollbackFor = Exception.class)
138 public void deleteProductThingModel(Long id) { 98 public void deleteProductThingModel(Long id) {
@@ -154,17 +114,6 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ @@ -154,17 +114,6 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ
154 } 114 }
155 } 115 }
156 116
157 - /**  
158 - * 校验功能是否存在  
159 - *  
160 - * @param id 功能编号  
161 - */  
162 - private void validateProductThingModelMapperExists(Long id) {  
163 - if (productThingModelMapper.selectById(id) == null) {  
164 - throw exception(THING_MODEL_NOT_EXISTS);  
165 - }  
166 - }  
167 -  
168 @Override 117 @Override
169 public IotProductThingModelDO getProductThingModel(Long id) { 118 public IotProductThingModelDO getProductThingModel(Long id) {
170 return productThingModelMapper.selectById(id); 119 return productThingModelMapper.selectById(id);
@@ -186,6 +135,52 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ @@ -186,6 +135,52 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ
186 } 135 }
187 136
188 /** 137 /**
  138 + * 校验功能是否存在
  139 + *
  140 + * @param id 功能编号
  141 + */
  142 + private void validateProductThingModelMapperExists(Long id) {
  143 + if (productThingModelMapper.selectById(id) == null) {
  144 + throw exception(THING_MODEL_NOT_EXISTS);
  145 + }
  146 + }
  147 +
  148 + private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) {
  149 + IotProductThingModelDO thingModel = productThingModelMapper.selectByProductIdAndIdentifier(productId, identifier);
  150 + if (thingModel != null && ObjectUtil.notEqual(thingModel.getId(), id)) {
  151 + throw exception(THING_MODEL_IDENTIFIER_EXISTS);
  152 + }
  153 + }
  154 +
  155 + private void validateProductStatus(Long createReqVO) {
  156 + IotProductDO product = productService.getProduct(createReqVO);
  157 + if (Objects.equals(product.getStatus(), IotProductStatusEnum.PUBLISHED.getStatus())) {
  158 + throw exception(PRODUCT_STATUS_NOT_ALLOW_THING_MODEL);
  159 + }
  160 + }
  161 +
  162 + private void validateNotDefaultEventAndService(String identifier) {
  163 + // set, get, post, property, event, time, value 是系统保留字段,不能用于标识符定义
  164 + if (CollUtil.containsAny(Arrays.asList("set", "get", "post", "property", "event", "time", "value"), Collections.singletonList(identifier))) {
  165 + throw exception(THING_MODEL_IDENTIFIER_INVALID);
  166 + }
  167 + }
  168 +
  169 + private void validateNameUnique(Long productId, String name) {
  170 + IotProductThingModelDO thingModel = productThingModelMapper.selectByProductIdAndName(productId, name);
  171 + if (thingModel != null) {
  172 + throw exception(THING_MODEL_NAME_EXISTS);
  173 + }
  174 + }
  175 +
  176 + private void validateIdentifierUnique(Long productId, String identifier) {
  177 + IotProductThingModelDO thingModel = productThingModelMapper.selectByProductIdAndIdentifier(productId, identifier);
  178 + if (thingModel != null) {
  179 + throw exception(THING_MODEL_IDENTIFIER_EXISTS);
  180 + }
  181 + }
  182 +
  183 + /**
189 * 创建默认的事件和服务 184 * 创建默认的事件和服务
190 */ 185 */
191 public void createDefaultEventsAndServices(Long productId, String productKey) { 186 public void createDefaultEventsAndServices(Long productId, String productKey) {
@@ -195,231 +190,140 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ @@ -195,231 +190,140 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ
195 190
196 // 2. 生成新的事件和服务列表 191 // 2. 生成新的事件和服务列表
197 List<IotProductThingModelDO> newThingModelList = new ArrayList<>(); 192 List<IotProductThingModelDO> newThingModelList = new ArrayList<>();
198 - // 生成属性上报事件 193 + // 2.1 生成属性上报事件
199 ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList); 194 ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList);
200 if (propertyPostEvent != null) { 195 if (propertyPostEvent != null) {
201 - IotProductThingModelDO eventThingModel = buildEventThingModelDO(productId, productKey, propertyPostEvent);  
202 - newThingModelList.add(eventThingModel); 196 + newThingModelList.add(buildEventThingModelDO(productId, productKey, propertyPostEvent, "属性上报事件"));
203 } 197 }
204 - // 生成属性设置服务 198 + // 2.2 生成属性设置服务
205 ThingModelService propertySetService = generatePropertySetService(propertyList); 199 ThingModelService propertySetService = generatePropertySetService(propertyList);
206 if (propertySetService != null) { 200 if (propertySetService != null) {
207 - IotProductThingModelDO setServiceThingModel = buildServiceThingModelDO(productId, productKey, propertySetService);  
208 - newThingModelList.add(setServiceThingModel); 201 + newThingModelList.add(buildServiceThingModelDO(productId, productKey, propertySetService, "属性设置服务"));
209 } 202 }
210 - // 生成属性获取服务 203 + // 2.3 生成属性获取服务
211 ThingModelService propertyGetService = generatePropertyGetService(propertyList); 204 ThingModelService propertyGetService = generatePropertyGetService(propertyList);
212 if (propertyGetService != null) { 205 if (propertyGetService != null) {
213 - IotProductThingModelDO getServiceThingModel = buildServiceThingModelDO(productId, productKey, propertyGetService);  
214 - newThingModelList.add(getServiceThingModel); 206 + newThingModelList.add(buildServiceThingModelDO(productId, productKey, propertyGetService,"属性获取服务"));
215 } 207 }
216 208
217 - // 3. 获取数据库中的默认的旧事件和服务列表 209 + // 3.1 获取数据库中的默认的旧事件和服务列表
218 List<IotProductThingModelDO> oldThingModelList = productThingModelMapper.selectListByProductIdAndIdentifiersAndTypes( 210 List<IotProductThingModelDO> oldThingModelList = productThingModelMapper.selectListByProductIdAndIdentifiersAndTypes(
219 productId, 211 productId,
220 Arrays.asList("post", "set", "get"), 212 Arrays.asList("post", "set", "get"),
221 Arrays.asList(IotProductThingModelTypeEnum.EVENT.getType(), IotProductThingModelTypeEnum.SERVICE.getType()) 213 Arrays.asList(IotProductThingModelTypeEnum.EVENT.getType(), IotProductThingModelTypeEnum.SERVICE.getType())
222 ); 214 );
  215 + // 3.2 创建默认的事件和服务
  216 + createDefaultEventsAndServices(oldThingModelList, newThingModelList);
  217 + }
223 218
224 - // 3.1 使用 diffList 方法比较新旧列表 219 + /**
  220 + * 创建默认的事件和服务
  221 + */
  222 + private void createDefaultEventsAndServices(List<IotProductThingModelDO> oldThingModelList, List<IotProductThingModelDO> newThingModelList) {
  223 + // 1.1 使用 diffList 方法比较新旧列表
225 List<List<IotProductThingModelDO>> diffResult = diffList(oldThingModelList, newThingModelList, 224 List<List<IotProductThingModelDO>> diffResult = diffList(oldThingModelList, newThingModelList,
226 - // 继续使用 identifier 和 type 进行比较:这样可以准确地匹配对应的功能对象。  
227 - (oldFunc, newFunc) -> Objects.equals(oldFunc.getIdentifier(), newFunc.getIdentifier())  
228 - && Objects.equals(oldFunc.getType(), newFunc.getType()));  
229 - List<IotProductThingModelDO> createList = diffResult.get(0); // 需要新增的  
230 - List<IotProductThingModelDO> updateList = diffResult.get(1); // 需要更新的  
231 - List<IotProductThingModelDO> deleteList = diffResult.get(2); // 需要删除的  
232 -  
233 - // 3.2 批量执行数据库操作  
234 - // 新增数据库中的新事件和服务列表  
235 - if (CollUtil.isNotEmpty(createList)) {  
236 - productThingModelMapper.insertBatch(createList); 225 + (oldVal, newVal) -> {
  226 + // 继续使用 identifier 和 type 进行比较:这样可以准确地匹配对应的功能对象。
  227 + boolean same = Objects.equals(oldVal.getIdentifier(), newVal.getIdentifier())
  228 + && Objects.equals(oldVal.getType(), newVal.getType());
  229 + if (same) {
  230 + newVal.setId(oldVal.getId()); // 设置编号
  231 + }
  232 + return same;
  233 + });
  234 + // 1.2 批量添加、修改、删除
  235 + if (CollUtil.isNotEmpty(diffResult.get(0))) {
  236 + productThingModelMapper.insertBatch(diffResult.get(0));
237 } 237 }
238 - // 更新数据库中的事件和服务列表  
239 - if (CollUtil.isNotEmpty(updateList)) {  
240 - // 首先,为每个需要更新的对象设置其对应的 ID  
241 - updateList.forEach(updateFunc -> {  
242 - IotProductThingModelDO oldFunc = findThingModelByIdentifierAndType(  
243 - oldThingModelList, updateFunc.getIdentifier(), updateFunc.getType());  
244 - if (oldFunc != null) {  
245 - updateFunc.setId(oldFunc.getId());  
246 - }  
247 - });  
248 - // 过滤掉没有设置 ID 的对象  
249 - List<IotProductThingModelDO> validUpdateList = filterList(updateList, thingModel -> thingModel.getId() != null);  
250 - // 执行批量更新  
251 - if (CollUtil.isNotEmpty(validUpdateList)) {  
252 - productThingModelMapper.updateBatch(validUpdateList);  
253 - } 238 + if (CollUtil.isNotEmpty(diffResult.get(1))) {
  239 + productThingModelMapper.updateBatch(diffResult.get(1));
254 } 240 }
255 -  
256 - // 删除数据库中的旧事件和服务列表  
257 - if (CollUtil.isNotEmpty(deleteList)) {  
258 - Set<Long> idsToDelete = CollectionUtils.convertSet(deleteList, IotProductThingModelDO::getId);  
259 - productThingModelMapper.deleteByIds(idsToDelete); 241 + if (CollUtil.isNotEmpty(diffResult.get(2))) {
  242 + productThingModelMapper.deleteByIds(convertSet(diffResult.get(2), IotProductThingModelDO::getId));
260 } 243 }
261 } 244 }
262 245
263 /** 246 /**
264 - * 根据标识符和类型查找功能对象  
265 - */  
266 - private IotProductThingModelDO findThingModelByIdentifierAndType(List<IotProductThingModelDO> thingModelList,  
267 - String identifier, Integer type) {  
268 - return CollUtil.findOne(thingModelList, func ->  
269 - Objects.equals(func.getIdentifier(), identifier) && Objects.equals(func.getType(), type));  
270 - }  
271 -  
272 - /**  
273 * 构建事件功能对象 247 * 构建事件功能对象
274 */ 248 */
275 - private IotProductThingModelDO buildEventThingModelDO(Long productId, String productKey, ThingModelEvent event) {  
276 - return new IotProductThingModelDO()  
277 - .setProductId(productId)  
278 - .setProductKey(productKey)  
279 - .setIdentifier(event.getIdentifier())  
280 - .setName(event.getName())  
281 - .setDescription(event.getDescription())  
282 - .setType(IotProductThingModelTypeEnum.EVENT.getType())  
283 - .setEvent(event); 249 + private IotProductThingModelDO buildEventThingModelDO(Long productId, String productKey, ThingModelEvent event,
  250 + String description) {
  251 + return new IotProductThingModelDO().setProductId(productId).setProductKey(productKey)
  252 + .setIdentifier(event.getIdentifier()).setName(event.getName()).setDescription(description)
  253 + .setType(IotProductThingModelTypeEnum.EVENT.getType()).setEvent(event);
284 } 254 }
285 255
286 /** 256 /**
287 * 构建服务功能对象 257 * 构建服务功能对象
288 */ 258 */
289 - private IotProductThingModelDO buildServiceThingModelDO(Long productId, String productKey, ThingModelService service) {  
290 - return new IotProductThingModelDO()  
291 - .setProductId(productId)  
292 - .setProductKey(productKey)  
293 - .setIdentifier(service.getIdentifier())  
294 - .setName(service.getName())  
295 - .setDescription(service.getDescription())  
296 - .setType(IotProductThingModelTypeEnum.SERVICE.getType())  
297 - .setService(service); 259 + private IotProductThingModelDO buildServiceThingModelDO(Long productId, String productKey, ThingModelService service,
  260 + String description) {
  261 + return new IotProductThingModelDO().setProductId(productId).setProductKey(productKey)
  262 + .setIdentifier(service.getIdentifier()).setName(service.getName()).setDescription(description)
  263 + .setType(IotProductThingModelTypeEnum.SERVICE.getType()).setService(service);
298 } 264 }
299 265
300 /** 266 /**
301 * 生成属性上报事件 267 * 生成属性上报事件
302 */ 268 */
303 - private ThingModelEvent generatePropertyPostEvent(List<IotProductThingModelDO> propertyList) {  
304 - if (CollUtil.isEmpty(propertyList)) { 269 + private ThingModelEvent generatePropertyPostEvent(List<IotProductThingModelDO> thingModelList) {
  270 + // 1.1 没有属性则不生成
  271 + if (CollUtil.isEmpty(thingModelList)) {
305 return null; 272 return null;
306 } 273 }
307 274
308 - ThingModelEvent event = new ThingModelEvent()  
309 - .setIdentifier("post")  
310 - .setName("属性上报")  
311 - .setType("info")  
312 - .setDescription("属性上报事件")  
313 - .setMethod("thing.event.property.post");  
314 -  
315 - // 将属性列表转换为事件的输出参数  
316 - List<ThingModelArgument> outputData = new ArrayList<>();  
317 - for (IotProductThingModelDO thingModel : propertyList) {  
318 - ThingModelArgument arg = new ThingModelArgument()  
319 - .setIdentifier(thingModel.getIdentifier())  
320 - .setName(thingModel.getName())  
321 - .setProperty(thingModel.getProperty())  
322 - .setDescription(thingModel.getDescription())  
323 - .setDirection("output"); // 设置为输出参数  
324 - outputData.add(arg);  
325 - }  
326 - event.setOutputData(outputData);  
327 - return event; 275 + // 1.2 生成属性上报事件
  276 + return new ThingModelEvent().setIdentifier("post").setName("属性上报").setMethod("thing.event.property.post")
  277 + .setType(IotProductThingModelServiceEventTypeEnum.INFO.getType())
  278 + .setOutputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.OUTPUT));
328 } 279 }
329 280
330 /** 281 /**
331 * 生成属性设置服务 282 * 生成属性设置服务
332 */ 283 */
333 - private ThingModelService generatePropertySetService(List<IotProductThingModelDO> propertyList) {  
334 - if (propertyList == null || propertyList.isEmpty()) {  
335 - return null;  
336 - }  
337 -  
338 - List<ThingModelArgument> inputData = new ArrayList<>();  
339 - for (IotProductThingModelDO thingModel : propertyList) {  
340 - ThingModelProperty property = thingModel.getProperty();  
341 - if (IotProductThingModelAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) {  
342 - ThingModelArgument arg = new ThingModelArgument()  
343 - .setIdentifier(property.getIdentifier())  
344 - .setName(property.getName())  
345 - .setProperty(property)  
346 - .setDescription(property.getDescription())  
347 - .setDirection("input"); // 设置为输入参数  
348 - inputData.add(arg);  
349 - }  
350 - }  
351 - if (inputData.isEmpty()) {  
352 - // 如果没有可写属性,不生成属性设置服务 284 + private ThingModelService generatePropertySetService(List<IotProductThingModelDO> thingModelList) {
  285 + // 1.1 过滤出所有可写属性
  286 + thingModelList = filterList(thingModelList, thingModel ->
  287 + IotProductThingModelAccessModeEnum.READ_WRITE.getMode().equals(thingModel.getProperty().getAccessMode()));
  288 + // 1.2 没有可写属性则不生成
  289 + if (CollUtil.isEmpty(thingModelList)) {
353 return null; 290 return null;
354 } 291 }
355 292
356 - // 属性设置服务一般不需要输出参数  
357 - return new ThingModelService()  
358 - .setIdentifier("set")  
359 - .setName("属性设置")  
360 - .setCallType("async")  
361 - .setDescription("属性设置服务")  
362 - .setMethod("thing.service.property.set")  
363 - .setInputData(inputData)  
364 - // 属性设置服务一般不需要输出参数  
365 - .setOutputData(new ArrayList<>()); 293 + // 2. 生成属性设置服务
  294 + return new ThingModelService().setIdentifier("set").setName("属性设置").setMethod("thing.service.property.set")
  295 + .setCallType(IotProductThingModelServiceCallTypeEnum.ASYNC.getType())
  296 + .setInputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.INPUT))
  297 + .setOutputParams(Collections.emptyList()); // 属性设置服务一般不需要输出参数
366 } 298 }
367 299
368 /** 300 /**
369 * 生成属性获取服务 301 * 生成属性获取服务
370 */ 302 */
371 - private ThingModelService generatePropertyGetService(List<IotProductThingModelDO> propertyList) {  
372 - if (propertyList == null || propertyList.isEmpty()) { 303 + private ThingModelService generatePropertyGetService(List<IotProductThingModelDO> thingModelList) {
  304 + // 1.1 没有属性则不生成
  305 + if (CollUtil.isEmpty(thingModelList)) {
373 return null; 306 return null;
374 } 307 }
375 308
376 - List<ThingModelArgument> outputData = new ArrayList<>();  
377 - for (IotProductThingModelDO thingModelDO : propertyList) {  
378 - ThingModelProperty property = thingModelDO.getProperty();  
379 - if (ObjectUtils.equalsAny(property.getAccessMode(),  
380 - IotProductThingModelAccessModeEnum.READ_ONLY.getMode(), IotProductThingModelAccessModeEnum.READ_WRITE.getMode())) {  
381 - ThingModelArgument arg = new ThingModelArgument()  
382 - .setIdentifier(property.getIdentifier())  
383 - .setName(property.getName())  
384 - .setProperty(property)  
385 - .setDescription(property.getDescription())  
386 - .setDirection("output"); // 设置为输出参数  
387 - outputData.add(arg);  
388 - }  
389 - }  
390 - if (outputData.isEmpty()) {  
391 - // 如果没有可读属性,不生成属性获取服务  
392 - return null;  
393 - } 309 + // 1.2 生成属性获取服务
  310 + return new ThingModelService().setIdentifier("get").setName("属性获取").setMethod("thing.service.property.get")
  311 + .setCallType(IotProductThingModelServiceCallTypeEnum.ASYNC.getType())
  312 + .setInputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.INPUT))
  313 + .setOutputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.OUTPUT));
  314 + }
394 315
395 - ThingModelService service = new ThingModelService()  
396 - .setIdentifier("get")  
397 - .setName("属性获取")  
398 - .setCallType("async")  
399 - .setDescription("属性获取服务")  
400 - .setMethod("thing.service.property.get");  
401 -  
402 - // 定义输入参数:属性标识符列表  
403 - ThingModelArgument inputArg = new ThingModelArgument()  
404 - .setIdentifier("properties")  
405 - .setName("属性标识符列表")  
406 - .setDescription("需要获取的属性标识符列表")  
407 - .setDirection("input"); // 设置为输入参数  
408 -  
409 - // 创建数组类型,元素类型为文本类型(字符串)TODO @puhui999: 还得研究研究  
410 - ThingModelArrayDataSpecs arrayType = new ThingModelArrayDataSpecs();  
411 - arrayType.setDataType("array");  
412 - inputArg.setProperty(new ThingModelProperty().setIdentifier(inputArg.getIdentifier()).setName(inputArg.getName())  
413 - .setDescription(inputArg.getDescription()).setDataSpecs(arrayType));  
414 -  
415 - ThingModelDateOrTextDataSpecs textType = new ThingModelDateOrTextDataSpecs();  
416 - textType.setDataType("text");  
417 - inputArg.setProperty(new ThingModelProperty().setIdentifier(inputArg.getIdentifier()).setName(inputArg.getName())  
418 - .setDescription(inputArg.getDescription()).setDataSpecs(textType));  
419 -  
420 - service.setInputData(Collections.singletonList(inputArg));  
421 - service.setOutputData(outputData);  
422 - return service; 316 + /**
  317 + * 构建输入/输出参数列表
  318 + *
  319 + * @param thingModelList 属性列表
  320 + * @return 输入/输出参数列表
  321 + */
  322 + private List<ThingModelInputOutputParam> buildInputOutputParam(List<IotProductThingModelDO> thingModelList,
  323 + IotProductThingModelParamDirectionEnum directionEnum) {
  324 + return convertList(thingModelList, thingModel ->
  325 + BeanUtils.toBean(thingModel.getProperty(), ThingModelInputOutputParam.class).setParaOrder(0) // TODO @puhui999: 先搞个默认值看看怎么个事
  326 + .setDirection(directionEnum.getDirection()));
423 } 327 }
424 328
425 } 329 }