修改:IOT 根据属性列表,自动生成属性上报事件和属性设置、获取服务

This commit is contained in:
安浩浩 2024-09-14 00:35:43 +08:00
parent 9e77692414
commit 1f8576f643
22 changed files with 664 additions and 173 deletions

View File

@ -5,45 +5,139 @@ tenant-id: {{adminTenentId}}
Authorization: Bearer {{token}}
{
"productId": 1,
"productKey": "123456",
"productId": 1002,
"productKey": "smart-sensor-002",
"properties": [
{
"identifier": "Temperature",
"name": "温度",
"accessMode": "r",
"required": true,
"dataType": {
"type": "float",
"specs": {
"min": -40.0,
"max": 125.0,
"step": 0.1,
"unit": "℃"
}
},
"description": "当前温度值"
},
{
"identifier": "Humidity",
"name": "湿度",
"accessMode": "r",
"required": true,
"dataType": {
"type": "float",
"specs": {
"min": 0.0,
"max": 100.0,
"step": 0.1,
"unit": "%"
}
},
"description": "当前湿度值"
},
{
"identifier": "GeoLocation",
"name": "地理位置",
"accessMode": "r",
"required": false,
"dataType": {
"type": "struct",
"specs": [
{
"identifier": "Longitude",
"name": "经度",
"dataType": {
"type": "double",
"specs": {
"min": -180.0,
"max": 180.0,
"step": 0.000001,
"unit": "°"
}
},
"description": "设备所在位置的经度"
},
{
"identifier": "Latitude",
"name": "纬度",
"dataType": {
"type": "double",
"specs": {
"min": -90.0,
"max": 90.0,
"step": 0.000001,
"unit": "°"
}
},
"description": "设备所在位置的纬度"
}
]
},
"description": "设备的地理位置信息"
}
],
"services": [
{
"identifier": "Reboot",
"name": "重启设备",
"callType": "async",
"inputData": [],
"description": "远程重启设备",
"method": "thing.service.reboot"
},
{
"identifier": "SetThreshold",
"name": "设置温度阈值",
"callType": "sync",
"inputData": [
{
"identifier": "Threshold",
"name": "阈值",
"dataType": {
"type": "float",
"specs": {
"min": -40.0,
"max": 125.0,
"step": 0.1,
"unit": "℃"
}
},
"description": "报警温度阈值"
}
],
"description": "设置设备的温度报警阈值",
"method": "thing.service.setThreshold"
}
],
"events": [
{
"identifier": "HighTemperatureAlert",
"name": "高温报警",
"type": "alert",
"outputData": [
{
"identifier": "CurrentTemperature",
"name": "当前温度",
"accessMode": "r",
"required": true,
"dataType": {
"type": "float",
"specs": {
"min": "-40",
"max": "120",
"unit": "°C",
"unitName": "摄氏度",
"step": "0.1"
}
"unit": "℃"
}
},
{
"identifier": "CurrentHumidity",
"name": "当前湿度",
"accessMode": "r",
"required": true,
"dataType": {
"type": "float",
"specs": {
"min": "0",
"max": "100",
"unit": "%",
"unitName": "百分比",
"step": "0.1"
}
}
"description": "触发报警时的温度值"
}
],
"services": "{}",
"events": "{}"
"description": "当温度超过阈值时触发高温报警事件",
"method": "thing.event.highTemperatureAlert"
}
]
}
### 请求 /iot/think-model-function/update 接口 => 成功
PUT {{baseUrl}}/iot/think-model-function/update
@ -53,45 +147,136 @@ Authorization: Bearer {{token}}
{
"id": 1,
"productId": 1,
"productKey": "123456",
"productId": 1001,
"productKey": "smart-sensor-001",
"properties": [
{
"identifier": "Temperature",
"name": "温度",
"accessMode": "r",
"required": true,
"dataType": {
"type": "float",
"specs": {
"min": -40.0,
"max": 125.0,
"step": 0.1,
"unit": "℃"
}
},
"description": "当前温度值"
},
{
"identifier": "Humidity",
"name": "湿度",
"accessMode": "r",
"required": true,
"dataType": {
"type": "float",
"specs": {
"min": 0.0,
"max": 100.0,
"step": 0.1,
"unit": "%"
}
},
"description": "当前湿度值"
},
{
"identifier": "GeoLocation",
"name": "地理位置",
"accessMode": "r",
"required": false,
"dataType": {
"type": "struct",
"specs": [
{
"identifier": "Longitude",
"name": "经度",
"dataType": {
"type": "double",
"specs": {
"min": -180.0,
"max": 180.0,
"step": 0.000001,
"unit": "°"
}
},
"description": "设备所在位置的经度"
},
{
"identifier": "Latitude",
"name": "纬度",
"dataType": {
"type": "double",
"specs": {
"min": -90.0,
"max": 90.0,
"step": 0.000001,
"unit": "°"
}
},
"description": "设备所在位置的纬度"
}
]
},
"description": "设备的地理位置信息"
}
],
"services": [
{
"identifier": "Reboot",
"name": "重启设备",
"callType": "async",
"inputData": [],
"description": "远程重启设备"
},
{
"identifier": "SetThreshold",
"name": "设置温度阈值",
"callType": "sync",
"inputData": [
{
"identifier": "Threshold",
"name": "阈值",
"dataType": {
"type": "float",
"specs": {
"min": -40.0,
"max": 125.0,
"step": 0.1,
"unit": "℃"
}
},
"description": "报警温度阈值"
}
],
"description": "设置设备的温度报警阈值"
}
],
"events": [
{
"identifier": "HighTemperatureAlert",
"name": "高温报警",
"type": "alert",
"outputData": [
{
"identifier": "CurrentTemperature",
"name": "当前温度",
"accessMode": "r",
"required": true,
"dataType": {
"type": "float",
"specs": {
"min": "-40",
"max": "130",
"unit": "°C",
"unitName": "摄氏度",
"step": "0.1"
}
"unit": "℃"
}
},
{
"identifier": "CurrentHumidity",
"name": "当前湿度",
"accessMode": "r",
"required": true,
"dataType": {
"type": "float",
"specs": {
"min": "0",
"max": "100",
"unit": "%",
"unitName": "百分比",
"step": "0.1"
}
}
"description": "触发报警时的温度值"
}
],
"services": "{}",
"events": "{}"
"description": "当温度超过阈值时触发高温报警事件"
}
]
}
### 请求 /iot/think-model-function/get-by-product-key 接口 => 成功
GET {{baseUrl}}/iot/think-model-function/get-by-product-key?productKey=123456

View File

@ -0,0 +1,12 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
import lombok.Data;
@Data
public class ThingModelArgument {
private String identifier;
private String name;
private ThingModelDataType dataType;
private String direction; // 用于区分输入或输出参数"input" "output"
private String description;
}

View File

@ -0,0 +1,9 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
import lombok.Data;
@Data
public class ThingModelArraySpecs {
private int size; // 数组长度
private ThingModelDataType item; // 数组元素的类型
}

View File

@ -0,0 +1,11 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class ThingModelArrayType extends ThingModelDataType {
private ThingModelArraySpecs specs;
}

View File

@ -0,0 +1,10 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class ThingModelBoolType extends ThingModelDataType {
// Bool 类型一般不需要额外的 specs
}

View File

@ -0,0 +1,22 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import lombok.Data;
@Data
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true)
@JsonSubTypes({
@JsonSubTypes.Type(value = ThingModelIntType.class, name = "int"),
@JsonSubTypes.Type(value = ThingModelFloatType.class, name = "float"),
@JsonSubTypes.Type(value = ThingModelDoubleType.class, name = "double"),
@JsonSubTypes.Type(value = ThingModelTextType.class, name = "text"),
@JsonSubTypes.Type(value = ThingModelDateType.class, name = "date"),
@JsonSubTypes.Type(value = ThingModelBoolType.class, name = "bool"),
@JsonSubTypes.Type(value = ThingModelEnumType.class, name = "enum"),
@JsonSubTypes.Type(value = ThingModelStructType.class, name = "struct"),
@JsonSubTypes.Type(value = ThingModelArrayType.class, name = "array")
})
public abstract class ThingModelDataType {
private String type;
}

View File

@ -0,0 +1,10 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class ThingModelDateType extends ThingModelDataType {
// Date 类型一般不需要额外的 specs
}

View File

@ -0,0 +1,18 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class ThingModelDoubleType extends ThingModelDataType {
private ThingModelDoubleSpecs specs;
}
@Data
class ThingModelDoubleSpecs {
private Double min;
private Double max;
private Double step;
private String unit;
}

View File

@ -0,0 +1,11 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Map;
@Data
@EqualsAndHashCode(callSuper = true)
public class ThingModelEnumType extends ThingModelDataType {
private Map<String, String> specs; // 枚举值和描述的键值对
}

View File

@ -0,0 +1,14 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
import lombok.Data;
import java.util.List;
@Data
public class ThingModelEvent {
private String identifier;
private String name;
private String type; // "info""alert""error"
private List<ThingModelArgument> outputData;
private String description;
private String method;
}

View File

@ -0,0 +1,18 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class ThingModelFloatType extends ThingModelDataType {
private ThingModelFloatSpecs specs;
}
@Data
class ThingModelFloatSpecs {
private Float min;
private Float max;
private Float step;
private String unit;
}

View File

@ -0,0 +1,18 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class ThingModelIntType extends ThingModelDataType {
private ThingModelIntSpecs specs;
}
@Data
class ThingModelIntSpecs {
private Integer min;
private Integer max;
private Integer step;
private String unit;
}

View File

@ -0,0 +1,13 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
import lombok.Data;
@Data
public class ThingModelProperty {
private String identifier;
private String name;
private String accessMode; // "rw""r""w"
private boolean required;
private ThingModelDataType dataType;
private String description;
}

View File

@ -0,0 +1,15 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
import lombok.Data;
import java.util.List;
@Data
public class ThingModelService {
private String identifier;
private String name;
private String callType; // "sync""async"
private List<ThingModelArgument> inputData;
private List<ThingModelArgument> outputData;
private String description;
private String method;
}

View File

@ -0,0 +1,11 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
import lombok.Data;
@Data
public class ThingModelStructField {
private String identifier;
private String name;
private ThingModelDataType dataType;
private String description;
}

View File

@ -0,0 +1,13 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
public class ThingModelStructType extends ThingModelDataType {
private List<ThingModelStructField> specs;
}

View File

@ -0,0 +1,15 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class ThingModelTextType extends ThingModelDataType {
private ThingModelTextSpecs specs;
}
@Data
class ThingModelTextSpecs {
private Integer length; // 最大长度
}

View File

@ -1,90 +0,0 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - IoT 产品物模型属性")
@Data
public class IotThingModelProperty {
@Schema(description = "属性标识符")
private String identifier;
@Schema(description = "属性名称")
private String name;
@Schema(description = "访问模式 (r/rw)")
private String accessMode;
@Schema(description = "是否必需")
private boolean required;
@Schema(description = "数据类型")
private DataType dataType;
@Schema(description = "数据类型")
@Data
public static class DataType {
@Schema(description = "数据类型float, double, struct, enum等")
private String type;
@Schema(description = "单一类型的规格适用于float, double等")
private Specs specs;
@Schema(description = "结构体字段适用于struct类型")
private List<StructField> structSpecs;
@Schema(description = "规格")
@Data
public static class Specs {
@Schema(description = "最小值")
private String min;
@Schema(description = "最大值")
private String max;
@Schema(description = "单位符号")
private String unit;
@Schema(description = "单位名称")
private String unitName;
@Schema(description = "步进值")
private String step;
}
@Schema(description = "结构体字段")
@Data
public static class StructField {
@Schema(description = "字段标识符")
private String identifier;
@Schema(description = "字段名称")
private String name;
@Schema(description = "字段的数据类型")
private DataType dataType;
}
}
@Schema(description = "枚举规格")
@Data
public static class EnumSpecs {
@Schema(description = "枚举值")
private int value;
@Schema(description = "枚举名称")
private String name;
public EnumSpecs(int value, String name) {
this.value = value;
this.name = name;
}
}
}

View File

@ -1,5 +1,8 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
@ -23,15 +26,15 @@ public class IotThinkModelFunctionRespVO {
@Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("属性列表")
private List<IotThingModelProperty> properties;
private List<ThingModelProperty> properties;
@Schema(description = "服务列表")
@ExcelProperty("服务列表")
private String services;
private List<ThingModelService> services;
@Schema(description = "事件列表")
@ExcelProperty("事件列表")
private String events;
private List<ThingModelEvent> events;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")

View File

@ -1,9 +1,14 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import jakarta.validation.constraints.*;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO")
@Data
@ -22,12 +27,12 @@ public class IotThinkModelFunctionSaveReqVO {
@Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "属性列表不能为空")
private List<IotThingModelProperty> properties;
private List<ThingModelProperty> properties;
@Schema(description = "服务列表")
private String services;
private List<ThingModelService> services;
@Schema(description = "事件列表")
private String events;
private List<ThingModelEvent> events;
}

View File

@ -1,16 +1,17 @@
package cn.iocoder.yudao.module.iot.convert.thinkmodelfunction;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThingModelProperty;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
import org.mapstruct.AfterMapping;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.factory.Mappers;
import java.util.ArrayList;
import java.util.List;
@Mapper
@ -18,34 +19,43 @@ public interface IotThinkModelFunctionConvert {
IotThinkModelFunctionConvert INSTANCE = Mappers.getMapper(IotThinkModelFunctionConvert.class);
// SaveReqVO 转换为 DO
@Mapping(target = "properties", ignore = true)
// SaveReqVO 转换为 DO 对象处理 properties, services, events 字段
@Mapping(target = "properties", expression = "java(convertPropertiesToJson(bean.getProperties()))")
@Mapping(target = "services", expression = "java(convertServicesToJson(bean.getServices()))")
@Mapping(target = "events", expression = "java(convertEventsToJson(bean.getEvents()))")
IotThinkModelFunctionDO convert(IotThinkModelFunctionSaveReqVO bean);
// DO 转换为 RespVO
@Mapping(target = "properties", ignore = true)
IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean);
// 处理 properties 字段的转换 VO DO
@AfterMapping
default void convertPropertiesToDO(IotThinkModelFunctionSaveReqVO source, @MappingTarget IotThinkModelFunctionDO target) {
target.setProperties(JSONUtil.toJsonStr(source.getProperties()));
default String convertPropertiesToJson(List<ThingModelProperty> properties) {
return properties != null ? JSONUtil.toJsonStr(properties) : "[]";
}
// 处理 properties 字段的转换 DO VO
@AfterMapping
default void convertPropertiesToVO(IotThinkModelFunctionDO source, @MappingTarget IotThinkModelFunctionRespVO target) {
target.setProperties(JSONUtil.toList(source.getProperties(), IotThingModelProperty.class));
default String convertServicesToJson(List<ThingModelService> services) {
return services != null ? JSONUtil.toJsonStr(services) : "[]";
}
default String convertEventsToJson(List<ThingModelEvent> events) {
return events != null ? JSONUtil.toJsonStr(events) : "[]";
}
// DO 转换为 RespVO 对象处理 properties, services, events 字段
@Mapping(target = "properties", expression = "java(convertJsonToProperties(bean.getProperties()))")
@Mapping(target = "services", expression = "java(convertJsonToServices(bean.getServices()))")
@Mapping(target = "events", expression = "java(convertJsonToEvents(bean.getEvents()))")
IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean);
default List<ThingModelProperty> convertJsonToProperties(String propertiesJson) {
return propertiesJson != null ? JSONUtil.toList(propertiesJson, ThingModelProperty.class) : new ArrayList<>();
}
default List<ThingModelService> convertJsonToServices(String servicesJson) {
return servicesJson != null ? JSONUtil.toList(servicesJson, ThingModelService.class) : new ArrayList<>();
}
default List<ThingModelEvent> convertJsonToEvents(String eventsJson) {
return eventsJson != null ? JSONUtil.toList(eventsJson, ThingModelEvent.class) : new ArrayList<>();
}
// 批量转换 DO 列表到 RespVO 列表
List<IotThinkModelFunctionRespVO> convertList(List<IotThinkModelFunctionDO> list);
}
// 批量转换处理 properties 字段
@AfterMapping
default void convertPropertiesListToVO(List<IotThinkModelFunctionDO> sourceList, @MappingTarget List<IotThinkModelFunctionRespVO> targetList) {
for (int i = 0; i < sourceList.size(); i++) {
convertPropertiesToVO(sourceList.get(i), targetList.get(i));
}
}
}

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.iot.service.thinkmodelfunction;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.*;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert;
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
@ -10,6 +11,10 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS;
@ -27,10 +32,13 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
log.info("创建物模型,参数:{}", createReqVO);
// 验证 ProductKey 对应的产品物模型是否已存在
validateThinkModelFunctionNotExistsByProductKey(createReqVO.getProductKey());
// 插入
// 转换请求对象为数据对象
IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO);
// 自动生成属性上报事件和属性设置获取服务
generateDefaultEventsAndServices(createReqVO, thinkModelFunction);
// 插入数据库
thinkModelFunctionMapper.insert(thinkModelFunction);
// 返回
// 返回生成的 ID
return thinkModelFunction.getId();
}
@ -43,9 +51,9 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
@Override
public void deleteThinkModelFunction(Long id) {
log.info("删除物模型id{}", id);
// 校验存在
// 校验物模型是否存在
validateThinkModelFunctionExists(id);
// 删除
// 删除物模型
thinkModelFunctionMapper.deleteById(id);
}
@ -68,12 +76,15 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
@Override
public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) {
log.info("更新物模型,参数:{}", updateReqVO);
// 校验存在
// 校验物模型是否存在
validateThinkModelFunctionExists(updateReqVO.getId());
// 校验 productKey 是否重复
// 校验 ProductKey 是否唯一
validateProductKeyUnique(updateReqVO.getId(), updateReqVO.getProductKey());
// 更新
// 转换请求对象为数据对象
IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO);
// 自动生成或更新属性上报事件和属性设置获取服务
generateDefaultEventsAndServices(updateReqVO, thinkModelFunction);
// 更新数据库
thinkModelFunctionMapper.updateById(thinkModelFunction);
}
@ -83,4 +94,151 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY);
}
}
/**
* @ TODO 还要再优化
* 根据属性列表自动生成属性上报事件和属性设置获取服务
*/
private void generateDefaultEventsAndServices(IotThinkModelFunctionSaveReqVO reqVO, IotThinkModelFunctionDO thinkModelFunction) {
// 获取属性列表
List<ThingModelProperty> properties = reqVO.getProperties();
if (properties == null) {
properties = new ArrayList<>();
}
// 生成属性上报事件
List<ThingModelEvent> events = reqVO.getEvents() != null ? new ArrayList<>(reqVO.getEvents()) : new ArrayList<>();
ThingModelEvent propertyPostEvent = generatePropertyPostEvent(properties);
events.add(propertyPostEvent);
// 生成属性设置和获取服务
List<ThingModelService> services = reqVO.getServices() != null ? new ArrayList<>(reqVO.getServices()) : new ArrayList<>();
ThingModelService propertySetService = generatePropertySetService(properties);
if (propertySetService != null) {
services.add(propertySetService);
}
ThingModelService propertyGetService = generatePropertyGetService(properties);
if (propertyGetService != null) {
services.add(propertyGetService);
}
// 更新 thinkModelFunction 对象的 events services 字段
thinkModelFunction.setEvents(JSONUtil.toJsonStr(events));
thinkModelFunction.setServices(JSONUtil.toJsonStr(services));
}
/**
* 生成属性上报事件
*/
private ThingModelEvent generatePropertyPostEvent(List<ThingModelProperty> properties) {
ThingModelEvent event = new ThingModelEvent();
event.setIdentifier("post");
event.setName("属性上报");
event.setType("info");
event.setDescription("属性上报事件");
event.setMethod("thing.event.property.post");
// 将属性列表转换为事件的输出参数
List<ThingModelArgument> outputData = new ArrayList<>();
for (ThingModelProperty property : properties) {
ThingModelArgument arg = new ThingModelArgument();
arg.setIdentifier(property.getIdentifier());
arg.setName(property.getName());
arg.setDataType(property.getDataType());
arg.setDescription(property.getDescription());
arg.setDirection("output"); // 设置为输出参数
outputData.add(arg);
}
event.setOutputData(outputData);
return event;
}
/**
* 生成属性设置服务
*/
private ThingModelService generatePropertySetService(List<ThingModelProperty> properties) {
List<ThingModelArgument> inputData = new ArrayList<>();
for (ThingModelProperty property : properties) {
if ("w".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) {
ThingModelArgument arg = new ThingModelArgument();
arg.setIdentifier(property.getIdentifier());
arg.setName(property.getName());
arg.setDataType(property.getDataType());
arg.setDescription(property.getDescription());
arg.setDirection("input"); // 设置为输入参数
inputData.add(arg);
}
}
if (inputData.isEmpty()) {
// 如果没有可写属性不生成属性设置服务
return null;
}
ThingModelService service = new ThingModelService();
service.setIdentifier("set");
service.setName("属性设置");
service.setCallType("async");
service.setDescription("属性设置服务");
service.setMethod("thing.service.property.set");
service.setInputData(inputData);
// 属性设置服务一般不需要输出参数
service.setOutputData(new ArrayList<>());
return service;
}
/**
* 生成属性获取服务
*/
private ThingModelService generatePropertyGetService(List<ThingModelProperty> properties) {
List<ThingModelArgument> outputData = new ArrayList<>();
for (ThingModelProperty property : properties) {
if ("r".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) {
ThingModelArgument arg = new ThingModelArgument();
arg.setIdentifier(property.getIdentifier());
arg.setName(property.getName());
arg.setDataType(property.getDataType());
arg.setDescription(property.getDescription());
arg.setDirection("output"); // 设置为输出参数
outputData.add(arg);
}
}
if (outputData.isEmpty()) {
// 如果没有可读属性不生成属性获取服务
return null;
}
ThingModelService service = new ThingModelService();
service.setIdentifier("get");
service.setName("属性获取");
service.setCallType("async");
service.setDescription("属性获取服务");
service.setMethod("thing.service.property.get");
// 定义输入参数属性标识符列表
ThingModelArgument inputArg = new ThingModelArgument();
inputArg.setIdentifier("properties");
inputArg.setName("属性标识符列表");
inputArg.setDescription("需要获取的属性标识符列表");
inputArg.setDirection("input"); // 设置为输入参数
// 创建数组类型元素类型为文本类型字符串
ThingModelArrayType arrayType = new ThingModelArrayType();
arrayType.setType("array");
ThingModelArraySpecs arraySpecs = new ThingModelArraySpecs();
// 不指定数组长度size 可以为 0 或者省略
ThingModelTextType textType = new ThingModelTextType();
textType.setType("text");
// 如果有需要可以设置 TextType specs如长度限制
arraySpecs.setItem(textType);
arrayType.setSpecs(arraySpecs);
inputArg.setDataType(arrayType);
service.setInputData(Collections.singletonList(inputArg));
service.setOutputData(outputData);
return service;
}
}