修改:IOT 物模型接口优化

This commit is contained in:
安浩浩 2024-09-15 20:09:18 +08:00
parent 84bc5aec1e
commit 2932314ee0
12 changed files with 409 additions and 578 deletions

View File

@ -17,4 +17,5 @@ public interface ErrorCodeConstants {
// ========== IoT 产品物模型 1-050-002-000 ============
ErrorCode THINK_MODEL_FUNCTION_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在");
ErrorCode THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY = new ErrorCode(1_050_002_001, "ProductKey 对应的产品物模型已存在");
ErrorCode THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER = new ErrorCode(1_050_002_002, "产品物模型标识已存在");
}

View File

@ -0,0 +1,47 @@
package cn.iocoder.yudao.module.iot.enums.product;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* IOT 物模型功能类型枚举类
*
* @author ahh
*/
@AllArgsConstructor
@Getter
public enum IotThingModelTypeEnum implements IntArrayValuable {
/**
* 属性
*/
PROPERTY(1, "属性"),
/**
* 服务
*/
SERVICE(2, "服务"),
/**
* 事件
*/
EVENT(3, "事件");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotThingModelTypeEnum::getType).toArray();
/**
* 类型
*/
private final Integer type;
/**
* 描述
*/
private final String description;
@Override
public int[] array() {
return ARRAYS;
}
}

View File

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

View File

@ -15,6 +15,8 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - IoT 产品物模型")
@ -50,23 +52,23 @@ public class IotThinkModelFunctionController {
return success(true);
}
@GetMapping("/get-by-product-key")
@GetMapping("/get")
@Operation(summary = "获得IoT 产品物模型")
@Parameter(name = "productKey", description = "产品Key", required = true, example = "1024")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('iot:think-model-function:query')")
public CommonResult<IotThinkModelFunctionRespVO> getThinkModelFunctionByProductKey(@RequestParam("productKey") String productKey) {
IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionService.getThinkModelFunctionByProductKey(productKey);
public CommonResult<IotThinkModelFunctionRespVO> getThinkModelFunction(@RequestParam("id") Long id) {
IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionService.getThinkModelFunction(id);
IotThinkModelFunctionRespVO respVO = IotThinkModelFunctionConvert.INSTANCE.convert(thinkModelFunction);
return success(respVO);
}
@GetMapping("/get-by-product-id")
@GetMapping("/list-by-product-id")
@Operation(summary = "获得IoT 产品物模型")
@Parameter(name = "productId", description = "产品ID", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('iot:think-model-function:query')")
public CommonResult<IotThinkModelFunctionRespVO> getThinkModelFunctionByProductId(@RequestParam("productId") Long productId) {
IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionService.getThinkModelFunctionByProductId(productId);
IotThinkModelFunctionRespVO respVO = IotThinkModelFunctionConvert.INSTANCE.convert(thinkModelFunction);
public CommonResult<List<IotThinkModelFunctionRespVO>> getThinkModelFunctionListByProductId(@RequestParam("productId") Long productId) {
List<IotThinkModelFunctionDO> thinkModelFunctionListByProductId = thinkModelFunctionService.getThinkModelFunctionListByProductId(productId);
List<IotThinkModelFunctionRespVO> respVO = IotThinkModelFunctionConvert.INSTANCE.convertList(thinkModelFunctionListByProductId);
return success(respVO);
}
}

View File

@ -20,21 +20,33 @@ public class IotThinkModelFunctionRespVO {
@ExcelProperty("产品ID")
private Long id;
@Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED)
private Long productId;
@Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("产品标识")
private String productKey;
@Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("属性列表")
private List<ThingModelProperty> properties;
@Schema(description = "功能标识", requiredMode = Schema.RequiredMode.REQUIRED)
private String identifier;
@Schema(description = "服务列表")
@ExcelProperty("服务列表")
private List<ThingModelService> services;
@Schema(description = "功能名称", requiredMode = Schema.RequiredMode.REQUIRED)
private String name;
@Schema(description = "事件列表")
@ExcelProperty("事件列表")
private List<ThingModelEvent> events;
@Schema(description = "功能描述", requiredMode = Schema.RequiredMode.REQUIRED)
private String description;
@Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED)
private Integer type;
@Schema(description = "属性", requiredMode = Schema.RequiredMode.REQUIRED)
private ThingModelProperty property;
@Schema(description = "服务", requiredMode = Schema.RequiredMode.REQUIRED)
private ThingModelEvent event;
@Schema(description = "事件", requiredMode = Schema.RequiredMode.REQUIRED)
private ThingModelService service;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")

View File

@ -1,15 +1,15 @@
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
import cn.iocoder.yudao.module.iot.enums.product.IotThingModelTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO")
@Data
public class IotThinkModelFunctionSaveReqVO {
@ -25,14 +25,29 @@ public class IotThinkModelFunctionSaveReqVO {
@NotEmpty(message = "产品标识不能为空")
private String productKey;
@Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "属性列表不能为空")
private List<ThingModelProperty> properties;
@Schema(description = "功能标识", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "功能标识不能为空")
private String identifier;
@Schema(description = "服务列表")
private List<ThingModelService> services;
@Schema(description = "功能名称", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "功能名称不能为空")
private String name;
@Schema(description = "事件列表")
private List<ThingModelEvent> events;
@Schema(description = "功能描述", requiredMode = Schema.RequiredMode.REQUIRED)
private String description;
@Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "功能类型不能为空")
@InEnum(IotThingModelTypeEnum.class)
private Integer type;
@Schema(description = "属性", requiredMode = Schema.RequiredMode.REQUIRED)
private ThingModelProperty property;
@Schema(description = "服务", requiredMode = Schema.RequiredMode.REQUIRED)
private ThingModelService service;
@Schema(description = "事件", requiredMode = Schema.RequiredMode.REQUIRED)
private ThingModelEvent event;
}

View File

@ -6,82 +6,52 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingMode
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import cn.iocoder.yudao.module.iot.enums.product.IotThingModelTypeEnum;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Mapper
public interface IotThinkModelFunctionConvert {
IotThinkModelFunctionConvert INSTANCE = Mappers.getMapper(IotThinkModelFunctionConvert.class);
ObjectMapper objectMapper = new ObjectMapper();
// SaveReqVO 转换为 DO 对象处理 properties, services, events 字段
@Mapping(target = "properties", expression = "java(convertPropertiesToJson(bean.getProperties()))")
@Mapping(target = "services", expression = "java(convertServicesToJson(bean.getServices()))")
@Mapping(target = "events", expression = "java(convertEventsToJson(bean.getEvents()))")
// SaveReqVO 转换为 DO
@Mapping(target = "property", expression = "java(convertToProperty(bean))")
@Mapping(target = "event", expression = "java(convertToEvent(bean))")
@Mapping(target = "service", expression = "java(convertToService(bean))")
IotThinkModelFunctionDO convert(IotThinkModelFunctionSaveReqVO bean);
default String convertPropertiesToJson(List<ThingModelProperty> properties) {
try {
return properties != null ? objectMapper.writeValueAsString(properties) : "[]";
} catch (JsonProcessingException e) {
throw new RuntimeException("序列化 properties 时发生错误", e);
default ThingModelProperty convertToProperty(IotThinkModelFunctionSaveReqVO bean) {
if (Objects.equals(bean.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
return bean.getProperty();
}
return null;
}
default String convertServicesToJson(List<ThingModelService> services) {
try {
return services != null ? objectMapper.writeValueAsString(services) : "[]";
} catch (JsonProcessingException e) {
throw new RuntimeException("序列化 services 时发生错误", e);
default ThingModelEvent convertToEvent(IotThinkModelFunctionSaveReqVO bean) {
if (Objects.equals(bean.getType(), IotThingModelTypeEnum.EVENT.getType())) {
return bean.getEvent();
}
return null;
}
default String convertEventsToJson(List<ThingModelEvent> events) {
try {
return events != null ? objectMapper.writeValueAsString(events) : "[]";
} catch (JsonProcessingException e) {
throw new RuntimeException("序列化 events 时发生错误", e);
default ThingModelService convertToService(IotThinkModelFunctionSaveReqVO bean) {
if (Objects.equals(bean.getType(), IotThingModelTypeEnum.SERVICE.getType())) {
return bean.getService();
}
return null;
}
// DO 转换为 RespVO 对象处理 properties, services, events 字段
@Mapping(target = "properties", expression = "java(convertJsonToProperties(bean.getProperties()))")
@Mapping(target = "services", expression = "java(convertJsonToServices(bean.getServices()))")
@Mapping(target = "events", expression = "java(convertJsonToEvents(bean.getEvents()))")
// DO 转换为 RespVO
@Mapping(target = "property", source = "property")
@Mapping(target = "event", source = "event")
@Mapping(target = "service", source = "service")
IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean);
default List<ThingModelProperty> convertJsonToProperties(String propertiesJson) {
try {
return propertiesJson != null ? objectMapper.readValue(propertiesJson, objectMapper.getTypeFactory().constructCollectionType(List.class, ThingModelProperty.class)) : new ArrayList<>();
} catch (JsonProcessingException e) {
throw new RuntimeException("反序列化 properties 时发生错误", e);
}
}
default List<ThingModelService> convertJsonToServices(String servicesJson) {
try {
return servicesJson != null ? objectMapper.readValue(servicesJson, objectMapper.getTypeFactory().constructCollectionType(List.class, ThingModelService.class)) : new ArrayList<>();
} catch (JsonProcessingException e) {
throw new RuntimeException("反序列化 services 时发生错误", e);
}
}
default List<ThingModelEvent> convertJsonToEvents(String eventsJson) {
try {
return eventsJson != null ? objectMapper.readValue(eventsJson, objectMapper.getTypeFactory().constructCollectionType(List.class, ThingModelEvent.class)) : new ArrayList<>();
} catch (JsonProcessingException e) {
throw new RuntimeException("反序列化 events 时发生错误", e);
}
}
// 批量转换 DO 列表到 RespVO 列表
// 批量转换
List<IotThinkModelFunctionRespVO> convertList(List<IotThinkModelFunctionDO> list);
}

View File

@ -1,20 +1,28 @@
package cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* IoT 产品物模型功能 DO
*
* <p>
* 每个 {@link IotProductDO} {@link IotThinkModelFunctionDO} 一对多的关系它的每个属性事件服务都对应一条记录
*
* @author 芋道源码
*/
@TableName("iot_think_model_function")
@TableName(value = "iot_think_model_function", autoResultMap = true)
@KeySequence("iot_think_model_function_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@Builder
@ -27,35 +35,56 @@ public class IotThinkModelFunctionDO extends BaseDO {
*/
@TableId
private Long id;
// TODO @haohao是不是有一个 identifier需要要有哈
// TODO @haohaonamedescription 属性还有个类型
/**
* 功能标识
*/
private String identifier;
/**
* 功能名称
*/
private String name;
/**
* 功能描述
*/
private String description;
/**
* 产品标识
*
* <p>
* 关联 {@link IotProductDO#getId()}
*/
private Long productId;
/**
* 产品标识
*
* <p>
* 关联 {@link IotProductDO#getProductKey()}
*/
private String productKey;
// TODO @haohao是不是可以搞成 ThingModelPropertyThingModelEventThingModelService 进行存储
/**
* 属性列表
* 功能类型
* <p>
* 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotThingModelTypeEnum}
*/
private String properties;
private Integer type;
/**
* 服务列表
* 属性
*/
private String services;
@TableField(typeHandler = JacksonTypeHandler.class)
private ThingModelProperty property;
/**
* 事件列表
* 事件
*/
private String events;
@TableField(typeHandler = JacksonTypeHandler.class)
private ThingModelEvent event;
/**
* 服务
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private ThingModelService service;
}

View File

@ -1,85 +0,0 @@
package cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* IoT 产品物模型功能 DO
*
* 每个 {@link IotProductDO} {@link IotThinkModelFunctionDO2} 一对多的关系它的每个属性事件服务都对应一条记录
*
* @author 芋道源码
*/
@TableName("iot_think_model_function")
@KeySequence("iot_think_model_function_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class IotThinkModelFunctionDO2 extends BaseDO {
/**
* 物模型功能编号
*/
@TableId
private Long id;
/**
* 功能标识
*/
private String identifier;
/**
* 功能名称
*/
private String name;
/**
* 功能描述
*/
private String description;
/**
* 产品标识
*
* 关联 {@link IotProductDO#getId()}
*/
private Long productId;
/**
* 产品标识
*
* 关联 {@link IotProductDO#getProductKey()}
*/
private String productKey;
/**
* 功能类型
*
* 1 - 属性
* 2 - 服务
* 3 - 事件
*/
// TODO @haohao枚举
private Integer type;
/**
* 属性
*/
private ThingModelProperty property;
/**
* 事件
*/
private ThingModelEvent event;
/**
* 服务
*/
private String service;
}

View File

@ -5,6 +5,8 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* IoT 产品物模型 Mapper
*
@ -13,12 +15,17 @@ import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface IotThinkModelFunctionMapper extends BaseMapperX<IotThinkModelFunctionDO> {
default IotThinkModelFunctionDO selectByProductKey(String productKey) {
return selectOne(new LambdaQueryWrapperX<IotThinkModelFunctionDO>().eq(IotThinkModelFunctionDO::getProductKey, productKey));
default IotThinkModelFunctionDO selectByProductIdAndIdentifier(Long productId, String identifier) {
return selectOne(new LambdaQueryWrapperX<IotThinkModelFunctionDO>().eq(IotThinkModelFunctionDO::getProductId, productId)
.eq(IotThinkModelFunctionDO::getIdentifier, identifier));
}
default IotThinkModelFunctionDO selectByProductId(Long productId){
return selectOne(new LambdaQueryWrapperX<IotThinkModelFunctionDO>().eq(IotThinkModelFunctionDO::getProductId, productId));
default List<IotThinkModelFunctionDO> selectListByProductId(Long productId) {
return selectList(new LambdaQueryWrapperX<IotThinkModelFunctionDO>().eq(IotThinkModelFunctionDO::getProductId, productId));
}
default List<IotThinkModelFunctionDO> selectListByProductIdAndType(Long productId, Integer type) {
return selectList(new LambdaQueryWrapperX<IotThinkModelFunctionDO>().eq(IotThinkModelFunctionDO::getProductId, productId)
.eq(IotThinkModelFunctionDO::getType, type));
}
}

View File

@ -4,6 +4,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThi
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
import jakarta.validation.Valid;
import java.util.List;
/**
* IoT 产品物模型 Service 接口
*
@ -19,6 +21,14 @@ public interface IotThinkModelFunctionService {
*/
Long createThinkModelFunction(@Valid IotThinkModelFunctionSaveReqVO createReqVO);
/**
* 更新IoT 产品物模型
*
* @param updateReqVO 更新信息
*/
void updateThinkModelFunction(@Valid IotThinkModelFunctionSaveReqVO updateReqVO);
/**
* 删除IoT 产品物模型
*
@ -27,25 +37,18 @@ public interface IotThinkModelFunctionService {
void deleteThinkModelFunction(Long id);
/**
* 获得IoT 产品物模型通过产品Key
* 获得IoT 产品物模型
*
* @param productKey 产品Key
* @param id 编号
* @return IoT 产品物模型
*/
IotThinkModelFunctionDO getThinkModelFunctionByProductKey(String productKey);
IotThinkModelFunctionDO getThinkModelFunction(Long id);
/**
* 获得IoT 产品物模型通过产品ID
* 获得IoT 产品物模型列表
*
* @param productId 产品ID
* @return IoT 产品物模型
* @param productId 产品编号
* @return IoT 产品物模型列表
*/
IotThinkModelFunctionDO getThinkModelFunctionByProductId(Long productId);
/**
* 更新IoT 产品物模型
*
* @param updateReqVO 更新信息
*/
void updateThinkModelFunction(@Valid IotThinkModelFunctionSaveReqVO updateReqVO);
List<IotThinkModelFunctionDO> getThinkModelFunctionListByProductId(Long productId);
}

View File

@ -1,6 +1,9 @@
package cn.iocoder.yudao.module.iot.service.thinkmodelfunction;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.*;
import cn.iocoder.yudao.framework.common.validation.Telephone;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArgument;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArraySpecs;
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArrayType;
@ -9,19 +12,20 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThi
import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert;
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import cn.iocoder.yudao.module.iot.enums.product.IotThingModelTypeEnum;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS;
@Slf4j
@ -32,38 +36,83 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
@Resource
private IotThinkModelFunctionMapper thinkModelFunctionMapper;
private ObjectMapper objectMapper = new ObjectMapper();
@Override
public Long createThinkModelFunction(IotThinkModelFunctionSaveReqVO createReqVO) {
log.info("创建物模型,参数:{}", createReqVO);
// 验证 ProductKey 对应的产品物模型是否已存在
validateThinkModelFunctionNotExistsByProductKey(createReqVO.getProductKey());
// 校验功能标识符在同一产品下是否唯一
validateIdentifierUnique(createReqVO.getProductId(), createReqVO.getIdentifier());
// 转换请求对象为数据对象
IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO);
// 自动生成属性上报事件和属性设置获取服务
generateDefaultEventsAndServices(createReqVO, thinkModelFunction);
// 插入数据库
thinkModelFunctionMapper.insert(thinkModelFunction);
// 如果创建的是属性需要更新默认的事件和服务
if (Objects.equals(createReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
generateDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey());
}
// 返回生成的 ID
return thinkModelFunction.getId();
}
private void validateThinkModelFunctionNotExistsByProductKey(String productKey) {
if (thinkModelFunctionMapper.selectByProductKey(productKey) != null) {
throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY);
private void validateIdentifierUnique(Long productId, String identifier) {
IotThinkModelFunctionDO existingFunction = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier);
if (existingFunction != null) {
throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER);
}
}
@Override
public void deleteThinkModelFunction(Long id) {
log.info("删除物模型id{}", id);
// 校验物模型是否存在
validateThinkModelFunctionExists(id);
// 删除物模型
thinkModelFunctionMapper.deleteById(id);
public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) {
// 校验功能是否存在
validateThinkModelFunctionExists(updateReqVO.getId());
// 校验功能标识符是否唯一
validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier());
// 转换请求对象为数据对象
IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO);
// 更新数据库
thinkModelFunctionMapper.updateById(thinkModelFunction);
// 如果更新的是属性需要更新默认的事件和服务
if (Objects.equals(updateReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
generateDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey());
}
}
private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) {
IotThinkModelFunctionDO existingFunction = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier);
if (existingFunction != null && !existingFunction.getId().equals(id)) {
throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER);
}
}
@Override
public void deleteThinkModelFunction(Long id) {
// 校验功能是否存在
IotThinkModelFunctionDO functionDO = thinkModelFunctionMapper.selectById(id);
if (functionDO == null) {
throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS);
}
// 删除功能
thinkModelFunctionMapper.deleteById(id);
// 如果删除的是属性需要更新默认的事件和服务
if (Objects.equals(functionDO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) {
generateDefaultEventsAndServices(functionDO.getProductId(), functionDO.getProductKey());
}
}
/**
* 校验功能是否存在
*
* @param id 功能编号
*/
private void validateThinkModelFunctionExists(Long id) {
if (thinkModelFunctionMapper.selectById(id) == null) {
throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS);
@ -71,114 +120,49 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
}
@Override
public IotThinkModelFunctionDO getThinkModelFunctionByProductKey(String productKey) {
return thinkModelFunctionMapper.selectByProductKey(productKey);
public IotThinkModelFunctionDO getThinkModelFunction(Long id) {
return thinkModelFunctionMapper.selectById(id);
}
@Override
public IotThinkModelFunctionDO getThinkModelFunctionByProductId(Long productId) {
return thinkModelFunctionMapper.selectByProductId(productId);
}
@Override
public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) {
log.info("更新物模型,参数:{}", updateReqVO);
// 校验物模型是否存在
validateThinkModelFunctionExists(updateReqVO.getId());
// 校验 ProductKey 是否唯一
validateProductKeyUnique(updateReqVO.getId(), updateReqVO.getProductKey());
// 转换请求对象为数据对象
IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO);
// 自动生成或更新属性上报事件和属性设置获取服务
generateDefaultEventsAndServices(updateReqVO, thinkModelFunction);
// 更新数据库
thinkModelFunctionMapper.updateById(thinkModelFunction);
}
private void validateProductKeyUnique(Long id, String productKey) {
IotThinkModelFunctionDO existingFunction = thinkModelFunctionMapper.selectByProductKey(productKey);
if (existingFunction != null && !existingFunction.getId().equals(id)) {
throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY);
}
public List<IotThinkModelFunctionDO> getThinkModelFunctionListByProductId(Long productId) {
return thinkModelFunctionMapper.selectListByProductId(productId);
}
/**
* 根据属性列表自动生成属性上报事件和属性设置获取服务
* 生成默认的事件和服务
*/
private void generateDefaultEventsAndServices(IotThinkModelFunctionSaveReqVO reqVO, IotThinkModelFunctionDO thinkModelFunction) {
// 获取属性列表
List<ThingModelProperty> properties = reqVO.getProperties();
if (properties == null) {
properties = new ArrayList<>();
public void generateDefaultEventsAndServices(Long productId, String productKey) {
// 获取当前产品的所有属性列表
List<IotThinkModelFunctionDO> propertyList = thinkModelFunctionMapper.selectListByProductIdAndType(productId, IotThingModelTypeEnum.PROPERTY.getType());
// 生成属性上报事件
ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList);
if (propertyPostEvent != null) {
saveOrUpdateEvent(productId, productKey, propertyPostEvent);
}
// 获取现有的事件和服务
List<ThingModelEvent> existingEvents = reqVO.getEvents() != null ? new ArrayList<>(reqVO.getEvents()) : new ArrayList<>();
List<ThingModelService> existingServices = reqVO.getServices() != null ? new ArrayList<>(reqVO.getServices()) : new ArrayList<>();
// 生成属性设置服务
ThingModelService propertySetService = generatePropertySetService(propertyList);
if (propertySetService != null) {
saveOrUpdateService(productId, productKey, propertySetService);
}
// 生成或更新属性上报事件
ThingModelEvent propertyPostEvent = generatePropertyPostEvent(properties);
updateEventInList(existingEvents, propertyPostEvent);
// 生成或更新属性设置和获取服务
ThingModelService propertySetService = generatePropertySetService(properties);
updateServiceInList(existingServices, propertySetService);
ThingModelService propertyGetService = generatePropertyGetService(properties);
updateServiceInList(existingServices, propertyGetService);
// 更新 thinkModelFunction 对象的 events services 字段
try {
thinkModelFunction.setEvents(objectMapper.writeValueAsString(existingEvents));
thinkModelFunction.setServices(objectMapper.writeValueAsString(existingServices));
} catch (JsonProcessingException e) {
throw new RuntimeException("序列化事件和服务时发生错误", e);
// 生成属性获取服务
ThingModelService propertyGetService = generatePropertyGetService(propertyList);
if (propertyGetService != null) {
saveOrUpdateService(productId, productKey, propertyGetService);
}
}
/**
* 在事件列表中更新或添加事件
*/
private void updateEventInList(List<ThingModelEvent> events, ThingModelEvent newEvent) {
if (newEvent == null) {
return;
}
for (int i = 0; i < events.size(); i++) {
ThingModelEvent event = events.get(i);
if (event.getIdentifier().equals(newEvent.getIdentifier())) {
// 更新已有的事件
events.set(i, newEvent);
return;
}
}
// 如果不存在则添加新的事件
events.add(newEvent);
}
/**
* 在服务列表中更新或添加服务
*/
private void updateServiceInList(List<ThingModelService> services, ThingModelService newService) {
if (newService == null) {
return;
}
for (int i = 0; i < services.size(); i++) {
ThingModelService service = services.get(i);
if (service.getIdentifier().equals(newService.getIdentifier())) {
// 更新已有的服务
services.set(i, newService);
return;
}
}
// 如果不存在则添加新的服务
services.add(newService);
}
/**
* 生成属性上报事件
*/
private ThingModelEvent generatePropertyPostEvent(List<ThingModelProperty> properties) {
private ThingModelEvent generatePropertyPostEvent(List<IotThinkModelFunctionDO> propertyList) {
if (propertyList == null || propertyList.isEmpty()) {
return null;
}
ThingModelEvent event = new ThingModelEvent();
event.setIdentifier("post");
event.setName("属性上报");
@ -188,7 +172,8 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
// 将属性列表转换为事件的输出参数
List<ThingModelArgument> outputData = new ArrayList<>();
for (ThingModelProperty property : properties) {
for (IotThinkModelFunctionDO functionDO : propertyList) {
ThingModelProperty property = functionDO.getProperty();
ThingModelArgument arg = new ThingModelArgument();
arg.setIdentifier(property.getIdentifier());
arg.setName(property.getName());
@ -205,9 +190,14 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
/**
* 生成属性设置服务
*/
private ThingModelService generatePropertySetService(List<ThingModelProperty> properties) {
private ThingModelService generatePropertySetService(List<IotThinkModelFunctionDO> propertyList) {
if (propertyList == null || propertyList.isEmpty()) {
return null;
}
List<ThingModelArgument> inputData = new ArrayList<>();
for (ThingModelProperty property : properties) {
for (IotThinkModelFunctionDO functionDO : propertyList) {
ThingModelProperty property = functionDO.getProperty();
if ("w".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) {
ThingModelArgument arg = new ThingModelArgument();
arg.setIdentifier(property.getIdentifier());
@ -239,9 +229,14 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
/**
* 生成属性获取服务
*/
private ThingModelService generatePropertyGetService(List<ThingModelProperty> properties) {
private ThingModelService generatePropertyGetService(List<IotThinkModelFunctionDO> propertyList) {
if (propertyList == null || propertyList.isEmpty()) {
return null;
}
List<ThingModelArgument> outputData = new ArrayList<>();
for (ThingModelProperty property : properties) {
for (IotThinkModelFunctionDO functionDO : propertyList) {
ThingModelProperty property = functionDO.getProperty();
if ("r".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) {
ThingModelArgument arg = new ThingModelArgument();
arg.setIdentifier(property.getIdentifier());
@ -275,10 +270,8 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
ThingModelArrayType arrayType = new ThingModelArrayType();
arrayType.setType("array");
ThingModelArraySpecs arraySpecs = new ThingModelArraySpecs();
// 不指定数组长度size 可以为 0 或者省略
ThingModelTextType textType = new ThingModelTextType();
textType.setType("text");
// 如果有需要可以设置 TextType specs如长度限制
arraySpecs.setItem(textType);
arrayType.setSpecs(arraySpecs);
@ -289,4 +282,54 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
return service;
}
/**
* 保存或更新事件
*/
private void saveOrUpdateEvent(Long productId, String productKey, ThingModelEvent event) {
// 检查是否已存在相同的事件
IotThinkModelFunctionDO existingEvent = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, event.getIdentifier());
IotThinkModelFunctionDO functionDO = new IotThinkModelFunctionDO();
functionDO.setProductId(productId);
functionDO.setProductKey(productKey);
functionDO.setIdentifier(event.getIdentifier());
functionDO.setName(event.getName());
functionDO.setDescription(event.getDescription());
functionDO.setType(IotThingModelTypeEnum.EVENT.getType());
functionDO.setEvent(event);
if (existingEvent != null) {
// 更新事件
functionDO.setId(existingEvent.getId());
thinkModelFunctionMapper.updateById(functionDO);
} else {
// 创建新的事件
thinkModelFunctionMapper.insert(functionDO);
}
}
/**
* 保存或更新事服务
*/
private void saveOrUpdateService(Long productId, String productKey, ThingModelService service) {
// 检查是否已存在相同的服务
IotThinkModelFunctionDO existingService = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, service.getIdentifier());
IotThinkModelFunctionDO functionDO = new IotThinkModelFunctionDO();
functionDO.setProductId(productId);
functionDO.setProductKey(productKey);
functionDO.setIdentifier(service.getIdentifier());
functionDO.setName(service.getName());
functionDO.setDescription(service.getDescription());
functionDO.setType(IotThingModelTypeEnum.SERVICE.getType());
functionDO.setService(service);
if (existingService != null) {
// 更新服务
functionDO.setId(existingService.getId());
thinkModelFunctionMapper.updateById(functionDO);
} else {
// 创建新的服务
thinkModelFunctionMapper.insert(functionDO);
}
}
}