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 4 import lombok.Getter;
5 5  
6 6 /**
7   - * IOT 访问方式枚举类
  7 + * IOT 产品物模型属性读取类型枚举
8 8 *
9 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 27  
28 28 <dependency>
29 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 30 <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
38 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 176 Authorization: Bearer {{token}}
177 177  
178 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 180 tenant-id: {{adminTenentId}}
181 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 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 4 import lombok.Data;
  5 +
5 6 import java.util.List;
6 7  
  8 +/**
  9 + * 物模型中的事件
  10 + *
  11 + * @author HUIHUI
  12 + */
7 13 @Data
8 14 public class ThingModelEvent {
9 15  
... ... @@ -16,17 +22,27 @@ public class ThingModelEvent {
16 22 */
17 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 36 private String type;
29   - private List<ThingModelArgument> outputData;
  37 + /**
  38 + * 事件的输出参数
  39 + *
  40 + * 输出参数定义事件调用后返回的结果或反馈信息,用于确认操作结果或提供额外的信息。
  41 + */
  42 + private List<ThingModelInputOutputParam> outputParams;
  43 + /**
  44 + * 标识设备需要执行的具体操作
  45 + */
30 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 25 */
26 26 private String name;
27 27 /**
28   - * 属性描述
29   - */
30   - private String description;
31   - /**
32 28 * 云端可以对该属性进行的操作类型
33 29 *
34 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 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 4 import lombok.Data;
  5 +
5 6 import java.util.List;
6 7  
  8 +/**
  9 + * 物模型中的服务
  10 + *
  11 + * @author HUIHUI
  12 + */
7 13 @Data
8 14 public class ThingModelService {
9 15  
... ... @@ -16,18 +22,33 @@ public class ThingModelService {
16 22 */
17 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 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 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 26 */
27 27 private String name;
28 28 /**
29   - * 属性描述
30   - */
31   - private String description;
32   - /**
33 29 * 云端可以对该属性进行的操作类型
34 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 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.util.ObjectUtil;
5 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 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 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 10 import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelPageReqVO;
15 11 import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelSaveReqVO;
16 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 14 import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO;
19 15 import cn.iocoder.yudao.module.iot.dal.mysql.thingmodel.IotProductThingModelMapper;
20 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 18 import cn.iocoder.yudao.module.iot.service.product.IotProductService;
24 19 import jakarta.annotation.Resource;
25 20 import lombok.extern.slf4j.Slf4j;
... ... @@ -30,8 +25,7 @@ import org.springframework.validation.annotation.Validated;
30 25 import java.util.*;
31 26  
32 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 29 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
36 30  
37 31 /**
... ... @@ -73,37 +67,10 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ
73 67 if (Objects.equals(createReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) {
74 68 createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey());
75 69 }
  70 + // TODO @puhui999: 服务和事件的情况 method 怎么设置?在前端设置还是后端设置?
76 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 74 @Override
108 75 @Transactional(rollbackFor = Exception.class)
109 76 public void updateProductThingModel(IotProductThingModelSaveReqVO updateReqVO) {
... ... @@ -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 96 @Override
137 97 @Transactional(rollbackFor = Exception.class)
138 98 public void deleteProductThingModel(Long id) {
... ... @@ -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 117 @Override
169 118 public IotProductThingModelDO getProductThingModel(Long id) {
170 119 return productThingModelMapper.selectById(id);
... ... @@ -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 186 public void createDefaultEventsAndServices(Long productId, String productKey) {
... ... @@ -195,231 +190,140 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ
195 190  
196 191 // 2. 生成新的事件和服务列表
197 192 List<IotProductThingModelDO> newThingModelList = new ArrayList<>();
198   - // 生成属性上报事件
  193 + // 2.1 生成属性上报事件
199 194 ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList);
200 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 199 ThingModelService propertySetService = generatePropertySetService(propertyList);
206 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 204 ThingModelService propertyGetService = generatePropertyGetService(propertyList);
212 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 210 List<IotProductThingModelDO> oldThingModelList = productThingModelMapper.selectListByProductIdAndIdentifiersAndTypes(
219 211 productId,
220 212 Arrays.asList("post", "set", "get"),
221 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 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 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 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 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 }
... ...