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

Merge pull request !1171 from puhui999/iot
This commit is contained in:
芋道源码 2024-12-26 05:50:02 +00:00 committed by Gitee
commit 4075fde765
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
13 changed files with 329 additions and 318 deletions

View File

@ -4,7 +4,7 @@ import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
/** /**
* IOT 访问方式枚举类 * IOT 产品物模型属性读取类型枚举
* *
* @author ahh * @author ahh
*/ */

View File

@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.iot.enums.thingmodel;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* IOT 产品物模型参数是输入参数还是输出参数枚举
*
* @author HUIHUI
*/
@AllArgsConstructor
@Getter
public enum IotProductThingModelParamDirectionEnum {
INPUT("input"), // 输入参数
OUTPUT("output"); // 输出参数
private final String direction;
}

View File

@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.iot.enums.thingmodel;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* IOT 产品物模型服务调用方式枚举
*
* @author HUIHUI
*/
@AllArgsConstructor
@Getter
public enum IotProductThingModelServiceCallTypeEnum {
ASYNC("async"), // 异步调用
SYNC("sync"); // 同步调用
private final String type;
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.iot.enums.thingmodel;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* IOT 产品物模型事件类型枚举
*
* @author HUIHUI
*/
@AllArgsConstructor
@Getter
public enum IotProductThingModelServiceEventTypeEnum {
INFO("info"), // 信息
ALERT("alert"), // 告警
ERROR("error"); // 故障
private final String type;
}

View File

@ -25,13 +25,6 @@
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-iot-plugin-api</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
<dependency> <dependency>
<groupId>cn.iocoder.boot</groupId> <groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId> <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>

View File

@ -176,7 +176,7 @@ tenant-id: {{adminTenentId}}
Authorization: Bearer {{token}} Authorization: Bearer {{token}}
### 请求 /iot/product-thing-model/get 接口 => 成功 ### 请求 /iot/product-thing-model/get 接口 => 成功
GET {{baseUrl}}/iot/product-thing-model/get?id=40 GET {{baseUrl}}/iot/product-thing-model/get?id=67
tenant-id: {{adminTenentId}} tenant-id: {{adminTenentId}}
Authorization: Bearer {{token}} Authorization: Bearer {{token}}

View File

@ -1,9 +1,15 @@
package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelArgument; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelServiceEventTypeEnum;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
/**
* 物模型中的事件
*
* @author HUIHUI
*/
@Data @Data
public class ThingModelEvent { public class ThingModelEvent {
@ -16,17 +22,27 @@ public class ThingModelEvent {
*/ */
private String name; private String name;
/** /**
* 事件描述 * 是否是标准品类的必选事件
*
* - true
* - false
*/ */
private String description; private Boolean required;
/** /**
* 事件类型 * 事件类型
* *
* "info""alert""error" * 关联枚举 {@link IotProductThingModelServiceEventTypeEnum}
*/ */
private String type; private String type;
private List<ThingModelArgument> outputData; /**
* 事件的输出参数
*
* 输出参数定义事件调用后返回的结果或反馈信息用于确认操作结果或提供额外的信息
*/
private List<ThingModelInputOutputParam> outputParams;
/**
* 标识设备需要执行的具体操作
*/
private String method; private String method;
} }

View File

@ -0,0 +1,50 @@
package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDataSpecs;
import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelParamDirectionEnum;
import lombok.Data;
import java.util.List;
/**
* IOT 产品物模型中的参数 // TODO @puhui999 考虑要不改成 ThingModelParam
*
* @author HUIHUI
*/
@Data
public class ThingModelInputOutputParam {
/**
* 参数标识符
*/
private String identifier;
/**
* 参数名称
*/
private String name;
/**
* 用于区分输入或输出参数
*
* 关联枚举 {@link IotProductThingModelParamDirectionEnum}
*/
private String direction;
/**
* 参数的序号 0 开始排序且不能重复
*
* TODO 考虑要不要序号感觉是要的, 先留一手看看
*/
private Integer paraOrder;
/**
* 参数值的数据类型 dataSpecs dataType 保持一致
*/
private String dataType;
/**
* 参数值的数据类型dataType为非列表型intfloatdoubletextdatearray的数据规范存储在 dataSpecs
*/
private ThingModelDataSpecs dataSpecs;
/**
* 参数值的数据类型dataType为列表型enumboolstruct的数据规范存储在 dataSpecsList
*/
private List<ThingModelDataSpecs> dataSpecsList;
}

View File

@ -24,10 +24,6 @@ public class ThingModelProperty {
* 属性名称 * 属性名称
*/ */
private String name; private String name;
/**
* 属性描述
*/
private String description;
/** /**
* 云端可以对该属性进行的操作类型 * 云端可以对该属性进行的操作类型
* *

View File

@ -1,9 +1,15 @@
package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model; package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelArgument; import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelServiceCallTypeEnum;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
/**
* 物模型中的服务
*
* @author HUIHUI
*/
@Data @Data
public class ThingModelService { public class ThingModelService {
@ -16,18 +22,33 @@ public class ThingModelService {
*/ */
private String name; private String name;
/** /**
* 服务描述 * 是否是标准品类的必选服务
*
* - true
* - false
*/ */
private String description; private Boolean required;
/** /**
* 调用类型 * 调用类型
* *
* "sync""async" * 关联枚举 {@link IotProductThingModelServiceCallTypeEnum}
*/ */
private String callType; private String callType;
private List<ThingModelArgument> inputData; /**
private List<ThingModelArgument> outputData; * 服务的输入参数
*
* 输入参数定义服务调用时所需提供的信息用于控制设备行为或执行特定任务
*/
private List<ThingModelInputOutputParam> inputParams;
/**
* 服务的输出参数
*
* 输出参数定义服务调用后返回的结果或反馈信息用于确认操作结果或提供额外的信息
*/
private List<ThingModelInputOutputParam> outputParams;
/**
* 标识设备需要执行的具体操作
*/
private String method; private String method;
} }

View File

@ -1,26 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class ThingModelArgument {
public static final String DIRECTION_INPUT = "input";
public static final String DIRECTION_OUTPUT = "output";
private String identifier;
private String name;
/**
* 物模型中的属性
*/
private ThingModelProperty property;
/**
* 用于区分输入或输出参数"input" "output"
*/
private String direction;
private String description;
}

View File

@ -25,10 +25,6 @@ public class ThingModelStructDataSpecs extends ThingModelDataSpecs {
* 属性名称 * 属性名称
*/ */
private String name; private String name;
/**
* 属性描述
*/
private String description;
/** /**
* 云端可以对该属性进行的操作类型 * 云端可以对该属性进行的操作类型
* 关联枚举 {@link IotProductThingModelAccessModeEnum} * 关联枚举 {@link IotProductThingModelAccessModeEnum}

View File

@ -3,14 +3,10 @@ package cn.iocoder.yudao.module.iot.service.thingmodel;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelEvent;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelInputOutputParam;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelArgument;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelArrayDataSpecs;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDateOrTextDataSpecs;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelPageReqVO;
import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelSaveReqVO; import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotProductThingModelSaveReqVO;
import cn.iocoder.yudao.module.iot.convert.thingmodel.IotProductThingModelConvert; import cn.iocoder.yudao.module.iot.convert.thingmodel.IotProductThingModelConvert;
@ -18,8 +14,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO; import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotProductThingModelDO;
import cn.iocoder.yudao.module.iot.dal.mysql.thingmodel.IotProductThingModelMapper; import cn.iocoder.yudao.module.iot.dal.mysql.thingmodel.IotProductThingModelMapper;
import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum;
import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelAccessModeEnum; import cn.iocoder.yudao.module.iot.enums.thingmodel.*;
import cn.iocoder.yudao.module.iot.enums.thingmodel.IotProductThingModelTypeEnum;
import cn.iocoder.yudao.module.iot.service.product.IotProductService; import cn.iocoder.yudao.module.iot.service.product.IotProductService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -30,8 +25,7 @@ import org.springframework.validation.annotation.Validated;
import java.util.*; import java.util.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
/** /**
@ -73,9 +67,91 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ
if (Objects.equals(createReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) { if (Objects.equals(createReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) {
createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey());
} }
// TODO @puhui999: 服务和事件的情况 method 怎么设置在前端设置还是后端设置
return thingModel.getId(); return thingModel.getId();
} }
@Override
@Transactional(rollbackFor = Exception.class)
public void updateProductThingModel(IotProductThingModelSaveReqVO updateReqVO) {
// 1. 校验功能是否存在
validateProductThingModelMapperExists(updateReqVO.getId());
// 2. 校验功能标识符是否唯一
validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier());
// 3. 校验产品状态发布状态下不允许操作功能
validateProductStatus(updateReqVO.getProductId());
// 4. 更新数据库
IotProductThingModelDO thingModel = IotProductThingModelConvert.INSTANCE.convert(updateReqVO);
productThingModelMapper.updateById(thingModel);
// 5. 如果更新的是属性需要更新默认的事件和服务
if (Objects.equals(updateReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) {
createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey());
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteProductThingModel(Long id) {
// 1. 校验功能是否存在
IotProductThingModelDO thingModel = productThingModelMapper.selectById(id);
if (thingModel == null) {
throw exception(THING_MODEL_NOT_EXISTS);
}
// 3. 校验产品状态发布状态下不允许操作功能
validateProductStatus(thingModel.getProductId());
// 2. 删除功能
productThingModelMapper.deleteById(id);
// 3. 如果删除的是属性需要更新默认的事件和服务
if (Objects.equals(thingModel.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) {
createDefaultEventsAndServices(thingModel.getProductId(), thingModel.getProductKey());
}
}
@Override
public IotProductThingModelDO getProductThingModel(Long id) {
return productThingModelMapper.selectById(id);
}
@Override
public List<IotProductThingModelDO> getProductThingModelListByProductId(Long productId) {
return productThingModelMapper.selectListByProductId(productId);
}
@Override
public PageResult<IotProductThingModelDO> getProductThingModelPage(IotProductThingModelPageReqVO pageReqVO) {
return productThingModelMapper.selectPage(pageReqVO);
}
@Override
public List<IotProductThingModelDO> getProductThingModelListByProductKey(String productKey) {
return productThingModelMapper.selectListByProductKey(productKey);
}
/**
* 校验功能是否存在
*
* @param id 功能编号
*/
private void validateProductThingModelMapperExists(Long id) {
if (productThingModelMapper.selectById(id) == null) {
throw exception(THING_MODEL_NOT_EXISTS);
}
}
private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) {
IotProductThingModelDO thingModel = productThingModelMapper.selectByProductIdAndIdentifier(productId, identifier);
if (thingModel != null && ObjectUtil.notEqual(thingModel.getId(), id)) {
throw exception(THING_MODEL_IDENTIFIER_EXISTS);
}
}
private void validateProductStatus(Long createReqVO) { private void validateProductStatus(Long createReqVO) {
IotProductDO product = productService.getProduct(createReqVO); IotProductDO product = productService.getProduct(createReqVO);
if (Objects.equals(product.getStatus(), IotProductStatusEnum.PUBLISHED.getStatus())) { if (Objects.equals(product.getStatus(), IotProductStatusEnum.PUBLISHED.getStatus())) {
@ -104,87 +180,6 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ
} }
} }
@Override
@Transactional(rollbackFor = Exception.class)
public void updateProductThingModel(IotProductThingModelSaveReqVO updateReqVO) {
// 1. 校验功能是否存在
validateProductThingModelMapperExists(updateReqVO.getId());
// 2. 校验功能标识符是否唯一
validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier());
// 3. 校验产品状态发布状态下不允许操作功能
validateProductStatus(updateReqVO.getProductId());
// 4. 更新数据库
IotProductThingModelDO thingModel = IotProductThingModelConvert.INSTANCE.convert(updateReqVO);
productThingModelMapper.updateById(thingModel);
// 5. 如果更新的是属性需要更新默认的事件和服务
if (Objects.equals(updateReqVO.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) {
createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey());
}
}
private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) {
IotProductThingModelDO thingModel = productThingModelMapper.selectByProductIdAndIdentifier(productId, identifier);
if (thingModel != null && ObjectUtil.notEqual(thingModel.getId(), id)) {
throw exception(THING_MODEL_IDENTIFIER_EXISTS);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteProductThingModel(Long id) {
// 1. 校验功能是否存在
IotProductThingModelDO thingModel = productThingModelMapper.selectById(id);
if (thingModel == null) {
throw exception(THING_MODEL_NOT_EXISTS);
}
// 3. 校验产品状态发布状态下不允许操作功能
validateProductStatus(thingModel.getProductId());
// 2. 删除功能
productThingModelMapper.deleteById(id);
// 3. 如果删除的是属性需要更新默认的事件和服务
if (Objects.equals(thingModel.getType(), IotProductThingModelTypeEnum.PROPERTY.getType())) {
createDefaultEventsAndServices(thingModel.getProductId(), thingModel.getProductKey());
}
}
/**
* 校验功能是否存在
*
* @param id 功能编号
*/
private void validateProductThingModelMapperExists(Long id) {
if (productThingModelMapper.selectById(id) == null) {
throw exception(THING_MODEL_NOT_EXISTS);
}
}
@Override
public IotProductThingModelDO getProductThingModel(Long id) {
return productThingModelMapper.selectById(id);
}
@Override
public List<IotProductThingModelDO> getProductThingModelListByProductId(Long productId) {
return productThingModelMapper.selectListByProductId(productId);
}
@Override
public PageResult<IotProductThingModelDO> getProductThingModelPage(IotProductThingModelPageReqVO pageReqVO) {
return productThingModelMapper.selectPage(pageReqVO);
}
@Override
public List<IotProductThingModelDO> getProductThingModelListByProductKey(String productKey) {
return productThingModelMapper.selectListByProductKey(productKey);
}
/** /**
* 创建默认的事件和服务 * 创建默认的事件和服务
*/ */
@ -195,231 +190,140 @@ public class IotProductThingModelServiceImpl implements IotProductThingModelServ
// 2. 生成新的事件和服务列表 // 2. 生成新的事件和服务列表
List<IotProductThingModelDO> newThingModelList = new ArrayList<>(); List<IotProductThingModelDO> newThingModelList = new ArrayList<>();
// 生成属性上报事件 // 2.1 生成属性上报事件
ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList); ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList);
if (propertyPostEvent != null) { if (propertyPostEvent != null) {
IotProductThingModelDO eventThingModel = buildEventThingModelDO(productId, productKey, propertyPostEvent); newThingModelList.add(buildEventThingModelDO(productId, productKey, propertyPostEvent, "属性上报事件"));
newThingModelList.add(eventThingModel);
} }
// 生成属性设置服务 // 2.2 生成属性设置服务
ThingModelService propertySetService = generatePropertySetService(propertyList); ThingModelService propertySetService = generatePropertySetService(propertyList);
if (propertySetService != null) { if (propertySetService != null) {
IotProductThingModelDO setServiceThingModel = buildServiceThingModelDO(productId, productKey, propertySetService); newThingModelList.add(buildServiceThingModelDO(productId, productKey, propertySetService, "属性设置服务"));
newThingModelList.add(setServiceThingModel);
} }
// 生成属性获取服务 // 2.3 生成属性获取服务
ThingModelService propertyGetService = generatePropertyGetService(propertyList); ThingModelService propertyGetService = generatePropertyGetService(propertyList);
if (propertyGetService != null) { if (propertyGetService != null) {
IotProductThingModelDO getServiceThingModel = buildServiceThingModelDO(productId, productKey, propertyGetService); newThingModelList.add(buildServiceThingModelDO(productId, productKey, propertyGetService,"属性获取服务"));
newThingModelList.add(getServiceThingModel);
} }
// 3. 获取数据库中的默认的旧事件和服务列表 // 3.1 获取数据库中的默认的旧事件和服务列表
List<IotProductThingModelDO> oldThingModelList = productThingModelMapper.selectListByProductIdAndIdentifiersAndTypes( List<IotProductThingModelDO> oldThingModelList = productThingModelMapper.selectListByProductIdAndIdentifiersAndTypes(
productId, productId,
Arrays.asList("post", "set", "get"), Arrays.asList("post", "set", "get"),
Arrays.asList(IotProductThingModelTypeEnum.EVENT.getType(), IotProductThingModelTypeEnum.SERVICE.getType()) Arrays.asList(IotProductThingModelTypeEnum.EVENT.getType(), IotProductThingModelTypeEnum.SERVICE.getType())
); );
// 3.2 创建默认的事件和服务
// 3.1 使用 diffList 方法比较新旧列表 createDefaultEventsAndServices(oldThingModelList, newThingModelList);
List<List<IotProductThingModelDO>> diffResult = diffList(oldThingModelList, newThingModelList,
// 继续使用 identifier type 进行比较这样可以准确地匹配对应的功能对象
(oldFunc, newFunc) -> Objects.equals(oldFunc.getIdentifier(), newFunc.getIdentifier())
&& Objects.equals(oldFunc.getType(), newFunc.getType()));
List<IotProductThingModelDO> createList = diffResult.get(0); // 需要新增的
List<IotProductThingModelDO> updateList = diffResult.get(1); // 需要更新的
List<IotProductThingModelDO> deleteList = diffResult.get(2); // 需要删除的
// 3.2 批量执行数据库操作
// 新增数据库中的新事件和服务列表
if (CollUtil.isNotEmpty(createList)) {
productThingModelMapper.insertBatch(createList);
}
// 更新数据库中的事件和服务列表
if (CollUtil.isNotEmpty(updateList)) {
// 首先为每个需要更新的对象设置其对应的 ID
updateList.forEach(updateFunc -> {
IotProductThingModelDO oldFunc = findThingModelByIdentifierAndType(
oldThingModelList, updateFunc.getIdentifier(), updateFunc.getType());
if (oldFunc != null) {
updateFunc.setId(oldFunc.getId());
}
});
// 过滤掉没有设置 ID 的对象
List<IotProductThingModelDO> validUpdateList = filterList(updateList, thingModel -> thingModel.getId() != null);
// 执行批量更新
if (CollUtil.isNotEmpty(validUpdateList)) {
productThingModelMapper.updateBatch(validUpdateList);
}
}
// 删除数据库中的旧事件和服务列表
if (CollUtil.isNotEmpty(deleteList)) {
Set<Long> idsToDelete = CollectionUtils.convertSet(deleteList, IotProductThingModelDO::getId);
productThingModelMapper.deleteByIds(idsToDelete);
}
} }
/** /**
* 根据标识符和类型查找功能对象 * 创建默认的事件和服务
*/ */
private IotProductThingModelDO findThingModelByIdentifierAndType(List<IotProductThingModelDO> thingModelList, private void createDefaultEventsAndServices(List<IotProductThingModelDO> oldThingModelList, List<IotProductThingModelDO> newThingModelList) {
String identifier, Integer type) { // 1.1 使用 diffList 方法比较新旧列表
return CollUtil.findOne(thingModelList, func -> List<List<IotProductThingModelDO>> diffResult = diffList(oldThingModelList, newThingModelList,
Objects.equals(func.getIdentifier(), identifier) && Objects.equals(func.getType(), type)); (oldVal, newVal) -> {
// 继续使用 identifier type 进行比较这样可以准确地匹配对应的功能对象
boolean same = Objects.equals(oldVal.getIdentifier(), newVal.getIdentifier())
&& Objects.equals(oldVal.getType(), newVal.getType());
if (same) {
newVal.setId(oldVal.getId()); // 设置编号
}
return same;
});
// 1.2 批量添加修改删除
if (CollUtil.isNotEmpty(diffResult.get(0))) {
productThingModelMapper.insertBatch(diffResult.get(0));
}
if (CollUtil.isNotEmpty(diffResult.get(1))) {
productThingModelMapper.updateBatch(diffResult.get(1));
}
if (CollUtil.isNotEmpty(diffResult.get(2))) {
productThingModelMapper.deleteByIds(convertSet(diffResult.get(2), IotProductThingModelDO::getId));
}
} }
/** /**
* 构建事件功能对象 * 构建事件功能对象
*/ */
private IotProductThingModelDO buildEventThingModelDO(Long productId, String productKey, ThingModelEvent event) { private IotProductThingModelDO buildEventThingModelDO(Long productId, String productKey, ThingModelEvent event,
return new IotProductThingModelDO() String description) {
.setProductId(productId) return new IotProductThingModelDO().setProductId(productId).setProductKey(productKey)
.setProductKey(productKey) .setIdentifier(event.getIdentifier()).setName(event.getName()).setDescription(description)
.setIdentifier(event.getIdentifier()) .setType(IotProductThingModelTypeEnum.EVENT.getType()).setEvent(event);
.setName(event.getName())
.setDescription(event.getDescription())
.setType(IotProductThingModelTypeEnum.EVENT.getType())
.setEvent(event);
} }
/** /**
* 构建服务功能对象 * 构建服务功能对象
*/ */
private IotProductThingModelDO buildServiceThingModelDO(Long productId, String productKey, ThingModelService service) { private IotProductThingModelDO buildServiceThingModelDO(Long productId, String productKey, ThingModelService service,
return new IotProductThingModelDO() String description) {
.setProductId(productId) return new IotProductThingModelDO().setProductId(productId).setProductKey(productKey)
.setProductKey(productKey) .setIdentifier(service.getIdentifier()).setName(service.getName()).setDescription(description)
.setIdentifier(service.getIdentifier()) .setType(IotProductThingModelTypeEnum.SERVICE.getType()).setService(service);
.setName(service.getName())
.setDescription(service.getDescription())
.setType(IotProductThingModelTypeEnum.SERVICE.getType())
.setService(service);
} }
/** /**
* 生成属性上报事件 * 生成属性上报事件
*/ */
private ThingModelEvent generatePropertyPostEvent(List<IotProductThingModelDO> propertyList) { private ThingModelEvent generatePropertyPostEvent(List<IotProductThingModelDO> thingModelList) {
if (CollUtil.isEmpty(propertyList)) { // 1.1 没有属性则不生成
if (CollUtil.isEmpty(thingModelList)) {
return null; return null;
} }
ThingModelEvent event = new ThingModelEvent() // 1.2 生成属性上报事件
.setIdentifier("post") return new ThingModelEvent().setIdentifier("post").setName("属性上报").setMethod("thing.event.property.post")
.setName("属性上报") .setType(IotProductThingModelServiceEventTypeEnum.INFO.getType())
.setType("info") .setOutputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.OUTPUT));
.setDescription("属性上报事件")
.setMethod("thing.event.property.post");
// 将属性列表转换为事件的输出参数
List<ThingModelArgument> outputData = new ArrayList<>();
for (IotProductThingModelDO thingModel : propertyList) {
ThingModelArgument arg = new ThingModelArgument()
.setIdentifier(thingModel.getIdentifier())
.setName(thingModel.getName())
.setProperty(thingModel.getProperty())
.setDescription(thingModel.getDescription())
.setDirection("output"); // 设置为输出参数
outputData.add(arg);
}
event.setOutputData(outputData);
return event;
} }
/** /**
* 生成属性设置服务 * 生成属性设置服务
*/ */
private ThingModelService generatePropertySetService(List<IotProductThingModelDO> propertyList) { private ThingModelService generatePropertySetService(List<IotProductThingModelDO> thingModelList) {
if (propertyList == null || propertyList.isEmpty()) { // 1.1 过滤出所有可写属性
thingModelList = filterList(thingModelList, thingModel ->
IotProductThingModelAccessModeEnum.READ_WRITE.getMode().equals(thingModel.getProperty().getAccessMode()));
// 1.2 没有可写属性则不生成
if (CollUtil.isEmpty(thingModelList)) {
return null; return null;
} }
List<ThingModelArgument> inputData = new ArrayList<>(); // 2. 生成属性设置服务
for (IotProductThingModelDO thingModel : propertyList) { return new ThingModelService().setIdentifier("set").setName("属性设置").setMethod("thing.service.property.set")
ThingModelProperty property = thingModel.getProperty(); .setCallType(IotProductThingModelServiceCallTypeEnum.ASYNC.getType())
if (IotProductThingModelAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) { .setInputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.INPUT))
ThingModelArgument arg = new ThingModelArgument() .setOutputParams(Collections.emptyList()); // 属性设置服务一般不需要输出参数
.setIdentifier(property.getIdentifier())
.setName(property.getName())
.setProperty(property)
.setDescription(property.getDescription())
.setDirection("input"); // 设置为输入参数
inputData.add(arg);
}
}
if (inputData.isEmpty()) {
// 如果没有可写属性不生成属性设置服务
return null;
}
// 属性设置服务一般不需要输出参数
return new ThingModelService()
.setIdentifier("set")
.setName("属性设置")
.setCallType("async")
.setDescription("属性设置服务")
.setMethod("thing.service.property.set")
.setInputData(inputData)
// 属性设置服务一般不需要输出参数
.setOutputData(new ArrayList<>());
} }
/** /**
* 生成属性获取服务 * 生成属性获取服务
*/ */
private ThingModelService generatePropertyGetService(List<IotProductThingModelDO> propertyList) { private ThingModelService generatePropertyGetService(List<IotProductThingModelDO> thingModelList) {
if (propertyList == null || propertyList.isEmpty()) { // 1.1 没有属性则不生成
if (CollUtil.isEmpty(thingModelList)) {
return null; return null;
} }
List<ThingModelArgument> outputData = new ArrayList<>(); // 1.2 生成属性获取服务
for (IotProductThingModelDO thingModelDO : propertyList) { return new ThingModelService().setIdentifier("get").setName("属性获取").setMethod("thing.service.property.get")
ThingModelProperty property = thingModelDO.getProperty(); .setCallType(IotProductThingModelServiceCallTypeEnum.ASYNC.getType())
if (ObjectUtils.equalsAny(property.getAccessMode(), .setInputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.INPUT))
IotProductThingModelAccessModeEnum.READ_ONLY.getMode(), IotProductThingModelAccessModeEnum.READ_WRITE.getMode())) { .setOutputParams(buildInputOutputParam(thingModelList, IotProductThingModelParamDirectionEnum.OUTPUT));
ThingModelArgument arg = new ThingModelArgument() }
.setIdentifier(property.getIdentifier())
.setName(property.getName())
.setProperty(property)
.setDescription(property.getDescription())
.setDirection("output"); // 设置为输出参数
outputData.add(arg);
}
}
if (outputData.isEmpty()) {
// 如果没有可读属性不生成属性获取服务
return null;
}
ThingModelService service = new ThingModelService() /**
.setIdentifier("get") * 构建输入/输出参数列表
.setName("属性获取") *
.setCallType("async") * @param thingModelList 属性列表
.setDescription("属性获取服务") * @return 输入/输出参数列表
.setMethod("thing.service.property.get"); */
private List<ThingModelInputOutputParam> buildInputOutputParam(List<IotProductThingModelDO> thingModelList,
// 定义输入参数属性标识符列表 IotProductThingModelParamDirectionEnum directionEnum) {
ThingModelArgument inputArg = new ThingModelArgument() return convertList(thingModelList, thingModel ->
.setIdentifier("properties") BeanUtils.toBean(thingModel.getProperty(), ThingModelInputOutputParam.class).setParaOrder(0) // TODO @puhui999: 先搞个默认值看看怎么个事
.setName("属性标识符列表") .setDirection(directionEnum.getDirection()));
.setDescription("需要获取的属性标识符列表")
.setDirection("input"); // 设置为输入参数
// 创建数组类型元素类型为文本类型字符串TODO @puhui999: 还得研究研究
ThingModelArrayDataSpecs arrayType = new ThingModelArrayDataSpecs();
arrayType.setDataType("array");
inputArg.setProperty(new ThingModelProperty().setIdentifier(inputArg.getIdentifier()).setName(inputArg.getName())
.setDescription(inputArg.getDescription()).setDataSpecs(arrayType));
ThingModelDateOrTextDataSpecs textType = new ThingModelDateOrTextDataSpecs();
textType.setDataType("text");
inputArg.setProperty(new ThingModelProperty().setIdentifier(inputArg.getIdentifier()).setName(inputArg.getName())
.setDescription(inputArg.getDescription()).setDataSpecs(textType));
service.setInputData(Collections.singletonList(inputArg));
service.setOutputData(outputData);
return service;
} }
} }