mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-10-31 10:37:41 +08:00 
			
		
		
		
	Merge branch 'feature/iot' of https://gitee.com/alwayssuper/ruoyi-vue-pro into feature/iot
# Conflicts: # yudao-server/src/main/resources/application-local.yaml
This commit is contained in:
		| @ -3,19 +3,19 @@ package cn.iocoder.yudao.module.iot.controller.admin.device; | |||||||
| import cn.iocoder.yudao.framework.common.pojo.CommonResult; | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||||
| import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||||||
| import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataPageReqVO; | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceSaveReqVO; | ||||||
| import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataRespVO; | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.*; | ||||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; | ||||||
| import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotTimeDataRespVO; | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; | ||||||
|  | import cn.iocoder.yudao.module.iot.service.device.IotDeviceLogDataService; | ||||||
| import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; | import cn.iocoder.yudao.module.iot.service.device.IotDevicePropertyDataService; | ||||||
| import io.swagger.v3.oas.annotations.Operation; | import io.swagger.v3.oas.annotations.Operation; | ||||||
| import io.swagger.v3.oas.annotations.tags.Tag; | import io.swagger.v3.oas.annotations.tags.Tag; | ||||||
| import jakarta.annotation.Resource; | import jakarta.annotation.Resource; | ||||||
| import jakarta.validation.Valid; | import jakarta.validation.Valid; | ||||||
|  | import org.springframework.security.access.prepost.PreAuthorize; | ||||||
| import org.springframework.validation.annotation.Validated; | import org.springframework.validation.annotation.Validated; | ||||||
| import org.springframework.web.bind.annotation.GetMapping; | import org.springframework.web.bind.annotation.*; | ||||||
| import org.springframework.web.bind.annotation.RequestMapping; |  | ||||||
| import org.springframework.web.bind.annotation.RestController; |  | ||||||
|  |  | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| @ -31,6 +31,12 @@ public class IotDeviceDataController { | |||||||
|     @Resource |     @Resource | ||||||
|     private IotDevicePropertyDataService deviceDataService; |     private IotDevicePropertyDataService deviceDataService; | ||||||
|  |  | ||||||
|  |     @Resource | ||||||
|  |     private IotDeviceLogDataService iotDeviceLogDataService; | ||||||
|  |  | ||||||
|  |     @Resource | ||||||
|  |     private IotDeviceLogDataService deviceLogDataService; | ||||||
|  |  | ||||||
|     // TODO @浩浩:这里的 /latest-list,包括方法名。 |     // TODO @浩浩:这里的 /latest-list,包括方法名。 | ||||||
|     @GetMapping("/latest") |     @GetMapping("/latest") | ||||||
|     @Operation(summary = "获取设备属性最新数据") |     @Operation(summary = "获取设备属性最新数据") | ||||||
| @ -46,5 +52,20 @@ public class IotDeviceDataController { | |||||||
|         PageResult<Map<String, Object>> list = deviceDataService.getHistoryDeviceProperties(deviceDataReqVO); |         PageResult<Map<String, Object>> list = deviceDataService.getHistoryDeviceProperties(deviceDataReqVO); | ||||||
|         return success(BeanUtils.toBean(list, IotTimeDataRespVO.class)); |         return success(BeanUtils.toBean(list, IotTimeDataRespVO.class)); | ||||||
|     } |     } | ||||||
|  |     // TODO:数据权限 | ||||||
|  |     @PostMapping("/simulator") | ||||||
|  |     @Operation(summary = "模拟设备") | ||||||
|  |     public CommonResult<Boolean> simulatorDevice(@Valid @RequestBody IotDeviceDataSimulatorSaveReqVO simulatorReqVO) { | ||||||
|  |         //TODO:先生成一下设备日志  后续完善模拟设备代码逻辑 | ||||||
|  |         iotDeviceLogDataService.createDeviceLog(simulatorReqVO); | ||||||
|  |         return success(true); | ||||||
|  |     } | ||||||
|  |     // TODO:数据权限 | ||||||
|  |     @GetMapping("/log/page") | ||||||
|  |     @Operation(summary = "获得设备日志分页") | ||||||
|  |     public CommonResult<PageResult<IotDeviceLogRespVO>> getDeviceLogPage(@Valid IotDeviceLogPageReqVO pageReqVO) { | ||||||
|  |         PageResult<IotDeviceLogDO> pageResult = deviceLogDataService.getDeviceLogPage(pageReqVO); | ||||||
|  |         return success(BeanUtils.toBean(pageResult, IotDeviceLogRespVO.class)); | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
| @ -1,6 +1,7 @@ | |||||||
| package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device; | package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device; | ||||||
|  |  | ||||||
| import io.swagger.v3.oas.annotations.media.Schema; | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
|  | import jakarta.validation.constraints.Size; | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
|  |  | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| @ -13,6 +14,7 @@ public class IotDeviceSaveReqVO { | |||||||
|     private Long id; |     private Long id; | ||||||
|  |  | ||||||
|     @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.AUTO, example = "177") |     @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.AUTO, example = "177") | ||||||
|  |     @Size(max = 50, message = "设备编号长度不能超过50个字符") | ||||||
|     private String deviceKey; |     private String deviceKey; | ||||||
|  |  | ||||||
|     @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") |     @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") | ||||||
|  | |||||||
| @ -0,0 +1,42 @@ | |||||||
|  | package cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData; | ||||||
|  |  | ||||||
|  | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
|  | import jakarta.validation.constraints.NotEmpty; | ||||||
|  | import lombok.Data; | ||||||
|  | import org.springframework.format.annotation.DateTimeFormat; | ||||||
|  |  | ||||||
|  | import java.time.LocalDateTime; | ||||||
|  |  | ||||||
|  | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||||||
|  |  | ||||||
|  | @Schema(description = "管理后台 - IoT 模拟设备数据 Request VO") | ||||||
|  | @Data | ||||||
|  | public class IotDeviceDataSimulatorSaveReqVO { | ||||||
|  |  | ||||||
|  |     @Schema(description = "消息ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "msg123") | ||||||
|  |     private String id; | ||||||
|  |  | ||||||
|  |     @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "product123") | ||||||
|  |     @NotEmpty(message = "产品ID不能为空") | ||||||
|  |     private String productKey; | ||||||
|  |  | ||||||
|  |     @Schema(description = "设备ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "device123") | ||||||
|  |     @NotEmpty(message = "设备ID不能为空") | ||||||
|  |     private String deviceKey; | ||||||
|  |  | ||||||
|  |     @Schema(description = "消息/日志类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property") | ||||||
|  |     @NotEmpty(message = "消息类型不能为空") | ||||||
|  |     private String type; | ||||||
|  |  | ||||||
|  |     @Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature") | ||||||
|  |     @NotEmpty(message = "标识符不能为空") | ||||||
|  |     private String subType; | ||||||
|  |  | ||||||
|  |     @Schema(description = "数据内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "{\"value\": 25.6}") | ||||||
|  |     @NotEmpty(message = "数据内容不能为空") | ||||||
|  |     private String content; | ||||||
|  |  | ||||||
|  |     @Schema(description = "上报时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||||||
|  |     private Long reportTime; | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -0,0 +1,30 @@ | |||||||
|  | package cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData; | ||||||
|  |  | ||||||
|  | import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||||||
|  | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
|  | import jakarta.validation.constraints.NotEmpty; | ||||||
|  | import lombok.Data; | ||||||
|  | import org.springframework.format.annotation.DateTimeFormat; | ||||||
|  |  | ||||||
|  | import java.time.LocalDateTime; | ||||||
|  |  | ||||||
|  | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||||||
|  |  | ||||||
|  | @Schema(description = "管理后台 - IoT 设备日志分页查询 Request VO") | ||||||
|  | @Data | ||||||
|  | public class IotDeviceLogPageReqVO extends PageParam { | ||||||
|  |  | ||||||
|  |     @Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "device123") | ||||||
|  |     @NotEmpty(message = "设备标识不能为空") | ||||||
|  |     private String deviceKey; | ||||||
|  |  | ||||||
|  |     @Schema(description = "消息类型", example = "property") | ||||||
|  |     private String type; | ||||||
|  |  | ||||||
|  |     @Schema(description = "标识符", example = "temperature") | ||||||
|  |     private String subType; | ||||||
|  |  | ||||||
|  |     @Schema(description = "创建时间") | ||||||
|  |     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||||||
|  |     private LocalDateTime[] createTime; | ||||||
|  | }  | ||||||
| @ -0,0 +1,33 @@ | |||||||
|  | package cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData; | ||||||
|  |  | ||||||
|  | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | import java.time.LocalDateTime; | ||||||
|  |  | ||||||
|  | @Schema(description = "管理后台 - IoT 设备日志 Response VO") | ||||||
|  | @Data | ||||||
|  | public class IotDeviceLogRespVO { | ||||||
|  |  | ||||||
|  |     @Schema(description = "日志编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | ||||||
|  |     private String id; | ||||||
|  |     @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "product123") | ||||||
|  |     private String productKey; | ||||||
|  |     @Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "device123") | ||||||
|  |     private String deviceKey; | ||||||
|  |  | ||||||
|  |     @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property") | ||||||
|  |     private String type; | ||||||
|  |  | ||||||
|  |     @Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature") | ||||||
|  |     private String subType; | ||||||
|  |  | ||||||
|  |     @Schema(description = "日志内容", requiredMode = Schema.RequiredMode.REQUIRED) | ||||||
|  |     private String content; | ||||||
|  |  | ||||||
|  |     @Schema(description = "上报时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||||||
|  |     private LocalDateTime reportTime; | ||||||
|  |  | ||||||
|  |     @Schema(description = "记录时间戳", requiredMode = Schema.RequiredMode.REQUIRED) | ||||||
|  |     private LocalDateTime ts; | ||||||
|  | }  | ||||||
| @ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.thingmodel; | |||||||
| import cn.iocoder.yudao.framework.common.pojo.CommonResult; | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||||
| import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||||||
|  | import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelListReqVO; | ||||||
| import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelPageReqVO; | import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelPageReqVO; | ||||||
| import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelRespVO; | import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelRespVO; | ||||||
| import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelSaveReqVO; | import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelSaveReqVO; | ||||||
| @ -73,6 +74,14 @@ public class IotThingModelController { | |||||||
|         return success(IotThingModelConvert.INSTANCE.convertList(list)); |         return success(IotThingModelConvert.INSTANCE.convertList(list)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @GetMapping("/list") | ||||||
|  |     @Operation(summary = "获得产品物模型列表") | ||||||
|  |     @PreAuthorize("@ss.hasPermission('iot:thing-model:query')") | ||||||
|  |     public CommonResult<List<IotThingModelRespVO>> getThingModelListByProductId(@Valid IotThingModelListReqVO reqVO) { | ||||||
|  |         List<IotThingModelDO> list = thingModelService.getThingModelList(reqVO); | ||||||
|  |         return success(IotThingModelConvert.INSTANCE.convertList(list)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @GetMapping("/page") |     @GetMapping("/page") | ||||||
|     @Operation(summary = "获得产品物模型分页") |     @Operation(summary = "获得产品物模型分页") | ||||||
|     @PreAuthorize("@ss.hasPermission('iot:thing-model:query')") |     @PreAuthorize("@ss.hasPermission('iot:thing-model:query')") | ||||||
|  | |||||||
| @ -0,0 +1,27 @@ | |||||||
|  | package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo; | ||||||
|  |  | ||||||
|  | import cn.iocoder.yudao.framework.common.validation.InEnum; | ||||||
|  | import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; | ||||||
|  | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
|  | import jakarta.validation.constraints.NotNull; | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @Schema(description = "管理后台 - IoT 产品物模型List Request VO") | ||||||
|  | @Data | ||||||
|  | public class IotThingModelListReqVO { | ||||||
|  |     @Schema(description = "功能标识") | ||||||
|  |     private String identifier; | ||||||
|  |  | ||||||
|  |     @Schema(description = "功能名称", example = "张三") | ||||||
|  |     private String name; | ||||||
|  |  | ||||||
|  |     @Schema(description = "功能类型", example = "1") | ||||||
|  |     @InEnum(IotThingModelTypeEnum.class) | ||||||
|  |     private Integer type; | ||||||
|  |  | ||||||
|  |     @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED) | ||||||
|  |     @NotNull(message = "产品ID不能为空") | ||||||
|  |     private Long productId; | ||||||
|  | } | ||||||
| @ -0,0 +1,62 @@ | |||||||
|  | package cn.iocoder.yudao.module.iot.dal.dataobject.device; | ||||||
|  |  | ||||||
|  | import cn.hutool.core.date.DateTime; | ||||||
|  | import lombok.AllArgsConstructor; | ||||||
|  | import lombok.Builder; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  |  | ||||||
|  | import java.time.LocalDateTime; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * IoT 设备日志数据 DO | ||||||
|  |  * | ||||||
|  |  * @author alwayssuper | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | @Builder | ||||||
|  | @NoArgsConstructor | ||||||
|  | @AllArgsConstructor | ||||||
|  | public class IotDeviceLogDO { | ||||||
|  |     /** | ||||||
|  |      * 消息ID | ||||||
|  |      */ | ||||||
|  |     private String id; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 产品ID | ||||||
|  |      */ | ||||||
|  |     private String productKey; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 设备ID | ||||||
|  |      */ | ||||||
|  |     private String deviceKey; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 消息/日志类型 | ||||||
|  |      */ | ||||||
|  |     private String type; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 标识符:用于标识具体的属性、事件或服务 | ||||||
|  |      */ | ||||||
|  |     private String subType; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 数据内容:存储具体的消息数据内容,通常是JSON格式 | ||||||
|  |      */ | ||||||
|  |     private String content; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 上报时间戳 | ||||||
|  |      */ | ||||||
|  |     private Long reportTime; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 时序时间 | ||||||
|  |      */ | ||||||
|  |     private Long ts; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -6,6 +6,7 @@ import lombok.Data; | |||||||
| import lombok.NoArgsConstructor; | import lombok.NoArgsConstructor; | ||||||
|  |  | ||||||
| // TODO @芋艿:纠结下字段 | // TODO @芋艿:纠结下字段 | ||||||
|  | @Deprecated | ||||||
| /** | /** | ||||||
|  * TD 物模型消息日志的数据库 |  * TD 物模型消息日志的数据库 | ||||||
|  */ |  */ | ||||||
| @ -15,21 +16,7 @@ import lombok.NoArgsConstructor; | |||||||
| @AllArgsConstructor | @AllArgsConstructor | ||||||
| public class ThingModelMessageDO { | public class ThingModelMessageDO { | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 数据库名称 |  | ||||||
|      */ |  | ||||||
|     private String dataBaseName; |  | ||||||
|  |  | ||||||
|     // TODO @haohao:superTableName 和 tableName 是不是合并。因为每个 mapper 操作的时候,有且只会使用到其中一个。 |  | ||||||
|     /** |  | ||||||
|      * 超级表名称 |  | ||||||
|      */ |  | ||||||
|     private String superTableName; |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 表名称 |  | ||||||
|      */ |  | ||||||
|     private String tableName; |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 消息 ID |      * 消息 ID | ||||||
| @ -37,9 +24,11 @@ public class ThingModelMessageDO { | |||||||
|     private String id; |     private String id; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 扩展功能的参数 |      * 系统扩展参数 | ||||||
|  |      *  | ||||||
|  |      * 例如:设备状态、系统时间、固件版本等系统级信息 | ||||||
|      */ |      */ | ||||||
|     private Object sys; |     private Object system; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 请求方法 |      * 请求方法 | ||||||
| @ -58,6 +47,12 @@ public class ThingModelMessageDO { | |||||||
|      */ |      */ | ||||||
|     private Long time; |     private Long time; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 设备信息 | ||||||
|  |      */ | ||||||
|  |     private String productKey; | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 设备 key |      * 设备 key | ||||||
|      */ |      */ | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.dal.mysql.thingmodel; | |||||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||||
| import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||||||
| import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | ||||||
|  | import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelListReqVO; | ||||||
| import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelPageReqVO; | import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelPageReqVO; | ||||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; | import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; | ||||||
| import org.apache.ibatis.annotations.Mapper; | import org.apache.ibatis.annotations.Mapper; | ||||||
| @ -28,6 +29,17 @@ public interface IotThingModelMapper extends BaseMapperX<IotThingModelDO> { | |||||||
|                 .orderByDesc(IotThingModelDO::getId)); |                 .orderByDesc(IotThingModelDO::getId)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     default List<IotThingModelDO> selectList(IotThingModelListReqVO reqVO) { | ||||||
|  |         return selectList(new LambdaQueryWrapperX<IotThingModelDO>() | ||||||
|  |                 .eqIfPresent(IotThingModelDO::getIdentifier, reqVO.getIdentifier()) | ||||||
|  |                 .likeIfPresent(IotThingModelDO::getName, reqVO.getName()) | ||||||
|  |                 .eqIfPresent(IotThingModelDO::getType, reqVO.getType()) | ||||||
|  |                 .eqIfPresent(IotThingModelDO::getProductId, reqVO.getProductId()) | ||||||
|  |                 // TODO @芋艿:看看要不要加枚举 | ||||||
|  |                 .notIn(IotThingModelDO::getIdentifier, "get", "set", "post") | ||||||
|  |                 .orderByDesc(IotThingModelDO::getId)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     default IotThingModelDO selectByProductIdAndIdentifier(Long productId, String identifier) { |     default IotThingModelDO selectByProductIdAndIdentifier(Long productId, String identifier) { | ||||||
|         return selectOne(IotThingModelDO::getProductId, productId, |         return selectOne(IotThingModelDO::getProductId, productId, | ||||||
|                 IotThingModelDO::getIdentifier, identifier); |                 IotThingModelDO::getIdentifier, identifier); | ||||||
|  | |||||||
| @ -0,0 +1,61 @@ | |||||||
|  | package cn.iocoder.yudao.module.iot.dal.tdengine; | ||||||
|  |  | ||||||
|  | import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||||
|  | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO; | ||||||
|  | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; | ||||||
|  | import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS; | ||||||
|  | import com.baomidou.mybatisplus.annotation.InterceptorIgnore; | ||||||
|  | import org.apache.ibatis.annotations.Mapper; | ||||||
|  | import org.apache.ibatis.annotations.Param; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * IOT 设备日志数据 Mapper 接口 | ||||||
|  |  *  | ||||||
|  |  * 基于 TDengine 实现设备日志的存储 | ||||||
|  |  */ | ||||||
|  | @Mapper | ||||||
|  | @TDengineDS | ||||||
|  | @InterceptorIgnore(tenantLine = "true") // 避免 SQL 解析,因为 JSqlParser 对 TDengine 的 SQL 解析会报错 | ||||||
|  | public interface IotDeviceLogDataMapper { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 创建设备日志超级表 | ||||||
|  |      *  | ||||||
|  |      * 注意:初始化时只需创建一次 | ||||||
|  |      */ | ||||||
|  |     void createDeviceLogSTable(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 创建设备日志子表 | ||||||
|  |      * | ||||||
|  |      * @param deviceKey 设备标识 | ||||||
|  |      */ | ||||||
|  |     void createDeviceLogTable(@Param("deviceKey") String deviceKey); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 插入设备日志数据 | ||||||
|  |      *  | ||||||
|  |      * 如果子表不存在,会自动创建子表 | ||||||
|  |      *  | ||||||
|  |      * @param log 设备日志数据 | ||||||
|  |      */ | ||||||
|  |     void insert(@Param("log") IotDeviceLogDO log); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获得设备日志分页 | ||||||
|  |      * | ||||||
|  |      * @param reqVO 分页查询条件 | ||||||
|  |      * @return 设备日志列表 | ||||||
|  |      */ | ||||||
|  |     List<IotDeviceLogDO> selectPage(@Param("reqVO") IotDeviceLogPageReqVO reqVO); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获得设备日志总数 | ||||||
|  |      * | ||||||
|  |      * @param reqVO 查询条件 | ||||||
|  |      * @return 日志总数 | ||||||
|  |      */ | ||||||
|  |     Long selectCount(@Param("reqVO") IotDeviceLogPageReqVO reqVO); | ||||||
|  | } | ||||||
| @ -1,29 +1,35 @@ | |||||||
| package cn.iocoder.yudao.module.iot.dal.tdengine; | package cn.iocoder.yudao.module.iot.dal.tdengine; | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; | import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; | ||||||
|  | import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; | ||||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessageDO; | import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessageDO; | ||||||
|  | import cn.iocoder.yudao.module.iot.framework.tdengine.core.annotation.TDengineDS; | ||||||
| import com.baomidou.dynamic.datasource.annotation.DS; | import com.baomidou.dynamic.datasource.annotation.DS; | ||||||
|  | import com.baomidou.mybatisplus.annotation.InterceptorIgnore; | ||||||
| import org.apache.ibatis.annotations.Mapper; | import org.apache.ibatis.annotations.Mapper; | ||||||
|  | import org.apache.ibatis.annotations.Param; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * 处理 TD 中物模型消息日志的操作 |  * 处理 TD 中物模型消息日志的操作 | ||||||
|  */ |  */ | ||||||
| @Mapper | @Mapper | ||||||
| @DS("tdengine") | @Deprecated | ||||||
|  | @TDengineDS | ||||||
|  | @InterceptorIgnore(tenantLine = "true") // 避免 SQL 解析,因为 JSqlParser 对 TDengine 的 SQL 解析会报错 | ||||||
| public interface TdThingModelMessageMapper { | public interface TdThingModelMessageMapper { | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 创建物模型消息日志超级表超级表 |      * 创建物模型消息日志超级表超级表 | ||||||
|      * |      * | ||||||
|      */ |      */ | ||||||
|     @TenantIgnore |  | ||||||
|     void createSuperTable(ThingModelMessageDO superTable); |     void createSuperTable(@Param("productKey") String productKey); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 创建子表 |      * 创建子表 | ||||||
|      * |      * | ||||||
|      */ |      */ | ||||||
|     @TenantIgnore |  | ||||||
|     void createTableWithTag(ThingModelMessageDO table); |     void createTableWithTag(@Param("productKey") String productKey,@Param("deviceKey") String deviceKey); | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,40 @@ | |||||||
|  | package cn.iocoder.yudao.module.iot.framework.tdengine.config; | ||||||
|  |  | ||||||
|  | import cn.iocoder.yudao.module.iot.service.device.IotDeviceLogDataService; | ||||||
|  | import lombok.RequiredArgsConstructor; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import org.springframework.boot.ApplicationArguments; | ||||||
|  | import org.springframework.boot.ApplicationRunner; | ||||||
|  | import org.springframework.context.annotation.Configuration; | ||||||
|  | import org.springframework.core.annotation.Order; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * TDengine 表初始化的 Configuration | ||||||
|  |  * | ||||||
|  |  * @author alwayssuper | ||||||
|  |  */ | ||||||
|  | @Slf4j | ||||||
|  | @RequiredArgsConstructor | ||||||
|  | @Configuration | ||||||
|  | @Order(Integer.MAX_VALUE) // 保证在最后执行 | ||||||
|  | public class TDengineTableInitConfiguration implements ApplicationRunner { | ||||||
|  |  | ||||||
|  |     private final IotDeviceLogDataService deviceLogService; | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void run(ApplicationArguments args) { | ||||||
|  |         try { | ||||||
|  |             // 初始化设备日志表 | ||||||
|  |             deviceLogService.initTDengineSTable(); | ||||||
|  |             log.info("初始化 设备日志表 TDengine 表结构成功"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             if (ex.getMessage().contains("Table already exists")) { | ||||||
|  |                 log.info("TDengine 设备日志超级表已存在,跳过创建"); | ||||||
|  |                 return; | ||||||
|  |             }else{ | ||||||
|  |                 log.error("初始化 设备日志表 TDengine  表结构失败", ex); | ||||||
|  |             } | ||||||
|  |             throw ex; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,40 @@ | |||||||
|  | package cn.iocoder.yudao.module.iot.service.device; | ||||||
|  |  | ||||||
|  | import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||||
|  | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; | ||||||
|  | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO; | ||||||
|  | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * IoT 设备日志数据 Service 接口 | ||||||
|  |  * | ||||||
|  |  * @author alwayssuper | ||||||
|  |  */ | ||||||
|  | public interface IotDeviceLogDataService { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 初始化 TDengine 超级表 | ||||||
|  |      *  | ||||||
|  |      *系统启动时,会自动初始化一次 | ||||||
|  |      */ | ||||||
|  |     void initTDengineSTable(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 插入设备日志 | ||||||
|  |      * | ||||||
|  |      * 当该设备第一次插入日志时,自动创建该设备的设备日志子表 | ||||||
|  |      * | ||||||
|  |      * @param simulatorReqVO 设备日志模拟数据 | ||||||
|  |      */ | ||||||
|  |     void createDeviceLog(IotDeviceDataSimulatorSaveReqVO simulatorReqVO); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获得设备日志分页 | ||||||
|  |      * | ||||||
|  |      * @param pageReqVO 分页查询 | ||||||
|  |      * @return 设备日志分页 | ||||||
|  |      */ | ||||||
|  |     PageResult<IotDeviceLogDO> getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO); | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -0,0 +1,68 @@ | |||||||
|  | package cn.iocoder.yudao.module.iot.service.device; | ||||||
|  |  | ||||||
|  | import cn.hutool.core.date.DateTime; | ||||||
|  | import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||||
|  | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||||||
|  | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceDataSimulatorSaveReqVO; | ||||||
|  | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.deviceData.IotDeviceLogPageReqVO; | ||||||
|  | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO; | ||||||
|  | import cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogDataMapper; | ||||||
|  | import jakarta.annotation.Resource; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import org.springframework.stereotype.Service; | ||||||
|  | import org.springframework.validation.annotation.Validated; | ||||||
|  |  | ||||||
|  | import java.time.LocalDateTime; | ||||||
|  | import java.time.ZoneId; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * IoT 设备日志数据 Service 实现了 | ||||||
|  |  * | ||||||
|  |  * @author alwayssuper | ||||||
|  |  */ | ||||||
|  | @Service | ||||||
|  | @Slf4j | ||||||
|  | @Validated | ||||||
|  | public class IotDeviceLogDataServiceImpl implements IotDeviceLogDataService{ | ||||||
|  |  | ||||||
|  |     @Resource | ||||||
|  |     private IotDeviceLogDataMapper iotDeviceLogDataMapper; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void initTDengineSTable() { | ||||||
|  |         try { | ||||||
|  |             // 创建设备日志超级表 | ||||||
|  |             iotDeviceLogDataMapper.createDeviceLogSTable(); | ||||||
|  |             log.info("创建设备日志超级表成功"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             throw ex; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void createDeviceLog(IotDeviceDataSimulatorSaveReqVO simulatorReqVO) { | ||||||
|  |         //TODO:讨论一下,iotkit这块TS和上报时间都是外部传入的   但是看TDengine文档 他是建议对TS在SQL中直接NOW   咱们的TS数据获取是走哪一种 | ||||||
|  |  | ||||||
|  |         // 1. 转换请求对象为 DO | ||||||
|  |         IotDeviceLogDO iotDeviceLogDO = BeanUtils.toBean(simulatorReqVO, IotDeviceLogDO.class); | ||||||
|  |          | ||||||
|  |         // 2. 处理时间字段 | ||||||
|  |         long currentTime = System.currentTimeMillis(); | ||||||
|  |         // 2.1 设置时序时间为当前时间 | ||||||
|  |         iotDeviceLogDO.setTs(currentTime); | ||||||
|  |  | ||||||
|  |         // 3. 插入数据 | ||||||
|  |         iotDeviceLogDataMapper.insert(iotDeviceLogDO); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public PageResult<IotDeviceLogDO> getDeviceLogPage(IotDeviceLogPageReqVO pageReqVO) { | ||||||
|  |         // 查询数据 | ||||||
|  |         List<IotDeviceLogDO> list = iotDeviceLogDataMapper.selectPage(pageReqVO); | ||||||
|  |         Long total = iotDeviceLogDataMapper.selectCount(pageReqVO); | ||||||
|  |         // 构造分页结果 | ||||||
|  |         return new PageResult<>(list, total); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -18,6 +18,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; | |||||||
| import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; | import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; | ||||||
| import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; | import cn.iocoder.yudao.module.iot.dal.tdengine.IotDevicePropertyDataMapper; | ||||||
| import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; | import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; | ||||||
|  | import cn.iocoder.yudao.module.iot.dal.tdengine.TdThingModelMessageMapper; | ||||||
| import cn.iocoder.yudao.module.iot.enums.IotConstants; | import cn.iocoder.yudao.module.iot.enums.IotConstants; | ||||||
| import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; | import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum; | ||||||
| import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; | import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; | ||||||
| @ -85,6 +86,7 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe | |||||||
|     @Resource |     @Resource | ||||||
|     private IotDevicePropertyDataMapper devicePropertyDataMapper; |     private IotDevicePropertyDataMapper devicePropertyDataMapper; | ||||||
|  |  | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void defineDevicePropertyData(Long productId) { |     public void defineDevicePropertyData(Long productId) { | ||||||
|         // 1.1 查询产品和物模型 |         // 1.1 查询产品和物模型 | ||||||
| @ -109,6 +111,7 @@ public class IotDevicePropertyDataServiceImpl implements IotDevicePropertyDataSe | |||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             newFields.add(0, new TDengineTableField(TDengineTableField.FIELD_TS, TDengineTableField.TYPE_TIMESTAMP)); |             newFields.add(0, new TDengineTableField(TDengineTableField.FIELD_TS, TDengineTableField.TYPE_TIMESTAMP)); | ||||||
|  |             // 2.1.1 创建产品超级表 | ||||||
|             devicePropertyDataMapper.createProductPropertySTable(product.getProductKey(), newFields); |             devicePropertyDataMapper.createProductPropertySTable(product.getProductKey(), newFields); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -34,9 +34,6 @@ public class IotProductServiceImpl implements IotProductService { | |||||||
|     @Resource |     @Resource | ||||||
|     private IotProductMapper productMapper; |     private IotProductMapper productMapper; | ||||||
|  |  | ||||||
|     @Resource |  | ||||||
|     @Lazy  // 延迟加载,解决循环依赖 |  | ||||||
|     private IotThingModelMessageService thingModelMessageService; |  | ||||||
|     @Resource |     @Resource | ||||||
|     @Lazy  // 延迟加载,解决循环依赖 |     @Lazy  // 延迟加载,解决循环依赖 | ||||||
|     private IotDevicePropertyDataService devicePropertyDataService; |     private IotDevicePropertyDataService devicePropertyDataService; | ||||||
| @ -125,8 +122,7 @@ public class IotProductServiceImpl implements IotProductService { | |||||||
|         if (Objects.equals(status, IotProductStatusEnum.PUBLISHED.getStatus())) { |         if (Objects.equals(status, IotProductStatusEnum.PUBLISHED.getStatus())) { | ||||||
|             // 3.1 创建产品超级表数据模型 |             // 3.1 创建产品超级表数据模型 | ||||||
|             devicePropertyDataService.defineDevicePropertyData(id); |             devicePropertyDataService.defineDevicePropertyData(id); | ||||||
|             // 3.2 创建物模型日志超级表数据模型 TODO 待定:message 要不要分; |  | ||||||
|             thingModelMessageService.createSuperTable(id); |  | ||||||
|         } |         } | ||||||
|         productMapper.updateById(updateObj); |         productMapper.updateById(updateObj); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -16,11 +16,6 @@ public interface IotThingModelMessageService { | |||||||
|      */ |      */ | ||||||
|     void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage); |     void saveThingModelMessage(IotDeviceDO device, ThingModelMessage thingModelMessage); | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 创建物模型消息日志超级表 |  | ||||||
|      * |  | ||||||
|      * @param productId 产品编号 |  | ||||||
|      */ |  | ||||||
|     void createSuperTable(Long productId); |  | ||||||
|  |  | ||||||
| } | } | ||||||
| @ -7,15 +7,13 @@ import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; | |||||||
| import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDeviceStatusUpdateReqVO; | ||||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | ||||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDataDO; | ||||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.FieldParser; | import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.*; | ||||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdFieldDO; |  | ||||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TdTableDO; |  | ||||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.ThingModelMessage; |  | ||||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; | import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; | ||||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; | import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; | ||||||
| import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; | import cn.iocoder.yudao.module.iot.dal.redis.deviceData.DeviceDataRedisDAO; | ||||||
| import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; | import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDDLMapper; | ||||||
| import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; | import cn.iocoder.yudao.module.iot.dal.tdengine.TdEngineDMLMapper; | ||||||
|  | import cn.iocoder.yudao.module.iot.dal.tdengine.TdThingModelMessageMapper; | ||||||
| import cn.iocoder.yudao.module.iot.enums.IotConstants; | import cn.iocoder.yudao.module.iot.enums.IotConstants; | ||||||
| import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; | import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; | ||||||
| import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; | import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum; | ||||||
| @ -63,6 +61,9 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ | |||||||
|     @Resource |     @Resource | ||||||
|     private TdEngineDMLMapper tdEngineDMLMapper; |     private TdEngineDMLMapper tdEngineDMLMapper; | ||||||
|  |  | ||||||
|  |     @Resource | ||||||
|  |     private TdThingModelMessageMapper tdThingModelMessageMapper; | ||||||
|  |  | ||||||
|     @Resource |     @Resource | ||||||
|     private DeviceDataRedisDAO deviceDataRedisDAO; |     private DeviceDataRedisDAO deviceDataRedisDAO; | ||||||
|  |  | ||||||
| @ -77,8 +78,6 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ | |||||||
|             createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); |             createDeviceTable(device.getDeviceType(), device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); | ||||||
|             iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO() |             iotDeviceService.updateDeviceStatus(new IotDeviceStatusUpdateReqVO() | ||||||
|                     .setId(device.getId()).setStatus(IotDeviceStatusEnum.ONLINE.getStatus())); |                     .setId(device.getId()).setStatus(IotDeviceStatusEnum.ONLINE.getStatus())); | ||||||
|             // 1.2 创建物模型日志设备表 |  | ||||||
|             createThingModelMessageDeviceTable(device.getProductKey(), device.getDeviceName(), device.getDeviceKey()); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 2. 获取设备属性并进行物模型校验,过滤非物模型属性 |         // 2. 获取设备属性并进行物模型校验,过滤非物模型属性 | ||||||
| @ -107,32 +106,34 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ | |||||||
|                 thingModel -> IotThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType())); |                 thingModel -> IotThingModelTypeEnum.PROPERTY.getType().equals(thingModel.getType())); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override | //    @Override | ||||||
|     @TenantIgnore | //    @TenantIgnore | ||||||
|     public void createSuperTable(Long productId) { | //    public void createSuperTable(Long productId) { | ||||||
|         // 1. 查询产品 | //        // 1. 查询产品 | ||||||
|         IotProductDO product = productService.getProduct(productId); | //        IotProductDO product = productService.getProduct(productId); | ||||||
|  | //        // 2. 创建日志超级表 | ||||||
|         // 2. 获取超级表的名称和数据库名称 | //        tdThingModelMessageMapper.createSuperTable(product.getProductKey()); | ||||||
|         // TODO @alwayssuper:最好 databaseName、superTableName 的处理,放到 tdThinkModelMessageMapper 里。可以考虑,弄个 default 方法 | // | ||||||
|         String databaseName = IotTdDatabaseUtils.getDatabaseName(url); | //        // 2. 获取超级表的名称和数据库名称 | ||||||
|         String superTableName = IotTdDatabaseUtils.getThingModelMessageSuperTableName(product.getProductKey()); | //        // TODO @alwayssuper:最好 databaseName、superTableName 的处理,放到 tdThinkModelMessageMapper 里。可以考虑,弄个 default 方法 | ||||||
|  | ////        String databaseName = IotTdDatabaseUtils.getDatabaseName(url); | ||||||
|         // 解析物模型,获取字段列表 | ////        String superTableName = IotTdDatabaseUtils.getThingModelMessageSuperTableName(product.getProductKey()); | ||||||
|         List<TdFieldDO> schemaFields = List.of( | //// | ||||||
|                 TdFieldDO.builder().fieldName("time").dataType("TIMESTAMP").build(), | ////        // 解析物模型,获取字段列表 | ||||||
|                 TdFieldDO.builder().fieldName("id").dataType("NCHAR").dataLength(64).build(), | ////        List<TdFieldDO> schemaFields = List.of( | ||||||
|                 TdFieldDO.builder().fieldName("sys").dataType("NCHAR").dataLength(2048).build(), | ////                TdFieldDO.builder().fieldName("time").dataType("TIMESTAMP").build(), | ||||||
|                 TdFieldDO.builder().fieldName("method").dataType("NCHAR").dataLength(256).build(), | ////                TdFieldDO.builder().fieldName("id").dataType("NCHAR").dataLength(64).build(), | ||||||
|                 TdFieldDO.builder().fieldName("params").dataType("NCHAR").dataLength(2048).build() | ////                TdFieldDO.builder().fieldName("sys").dataType("NCHAR").dataLength(2048).build(), | ||||||
|         ); | ////                TdFieldDO.builder().fieldName("method").dataType("NCHAR").dataLength(256).build(), | ||||||
|         // 设置超级表的标签 | ////                TdFieldDO.builder().fieldName("params").dataType("NCHAR").dataLength(2048).build() | ||||||
|         List<TdFieldDO> tagsFields = List.of( | ////        ); | ||||||
|                 TdFieldDO.builder().fieldName("device_key").dataType("NCHAR").dataLength(64).build() | ////        // 设置超级表的标签 | ||||||
|         ); | ////        List<TdFieldDO> tagsFields = List.of( | ||||||
|         // 3. 创建超级表 | ////                TdFieldDO.builder().fieldName("device_key").dataType("NCHAR").dataLength(64).build() | ||||||
|         tdEngineDDLMapper.createSuperTable(new TdTableDO(databaseName, superTableName, schemaFields, tagsFields)); | ////        ); | ||||||
|     } | ////        // 3. 创建超级表 | ||||||
|  | ////        tdEngineDDLMapper.createSuperTable(new TdTableDO(databaseName, superTableName, schemaFields, tagsFields)); | ||||||
|  | //    } | ||||||
|  |  | ||||||
|     private List<IotThingModelDO> getValidFunctionList(String productKey) { |     private List<IotThingModelDO> getValidFunctionList(String productKey) { | ||||||
|         return filterList(iotThingModelService.getProductThingModelListByProductKey(productKey), |         return filterList(iotThingModelService.getProductThingModelListByProductKey(productKey), | ||||||
| @ -228,29 +229,7 @@ public class IotThingModelMessageServiceImpl implements IotThingModelMessageServ | |||||||
|                 .setTags(tagsFieldValues)); |                 .setTags(tagsFieldValues)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 创建物模型日志设备数据表 |  | ||||||
|      * |  | ||||||
|      * @param productKey 产品 Key |  | ||||||
|      * @param deviceName 设备名称 |  | ||||||
|      * @param deviceKey  设备 Key |  | ||||||
|      * |  | ||||||
|      */ |  | ||||||
|     private void createThingModelMessageDeviceTable(String productKey, String deviceName, String deviceKey){ |  | ||||||
|  |  | ||||||
|         // 1. 获取超级表的名称、数据库名称、设备日志表名称 |  | ||||||
|         String databaseName = IotTdDatabaseUtils.getDatabaseName(url); |  | ||||||
|         String superTableName = IotTdDatabaseUtils.getThingModelMessageSuperTableName(productKey); |  | ||||||
|         // TODO @alwayssuper:最好 databaseName、superTableName、thinkModelMessageDeviceTableName 的处理,放到 tdThinkModelMessageMapper 里。可以考虑,弄个 default 方法 |  | ||||||
|         String thinkModelMessageDeviceTableName = IotTdDatabaseUtils.getThingModelMessageDeviceTableName(productKey, deviceName); |  | ||||||
|  |  | ||||||
|         // 2. 创建物模型日志设备数据表 |  | ||||||
| //        tdThingModelMessageMapper.createTableWithTag(ThingModelMessageDO.builder().build() |  | ||||||
| //                .setDataBaseName(databaseName) |  | ||||||
| //                .setSuperTableName(superTableName) |  | ||||||
| //                .setTableName(thinkModelMessageDeviceTableName) |  | ||||||
| //                .setDeviceKey(deviceKey)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 获取数据库名称 |      * 获取数据库名称 | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| package cn.iocoder.yudao.module.iot.service.thingmodel; | package cn.iocoder.yudao.module.iot.service.thingmodel; | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||||
|  | import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelListReqVO; | ||||||
| import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelPageReqVO; | import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelPageReqVO; | ||||||
| import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelSaveReqVO; | import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelSaveReqVO; | ||||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; | import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO; | ||||||
| @ -69,4 +70,11 @@ public interface IotThingModelService { | |||||||
|      */ |      */ | ||||||
|     List<IotThingModelDO> getProductThingModelListByProductKey(String productKey); |     List<IotThingModelDO> getProductThingModelListByProductKey(String productKey); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获得产品物模型列表 | ||||||
|  |      * | ||||||
|  |      * @param reqVO 列表查询 | ||||||
|  |      * @return 产品物模型列表 | ||||||
|  |      */ | ||||||
|  |     List<IotThingModelDO> getThingModelList(IotThingModelListReqVO reqVO); | ||||||
| } | } | ||||||
| @ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |||||||
| 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.ThingModelParam; | import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelParam; | ||||||
| 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.vo.IotThingModelListReqVO; | ||||||
| import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelPageReqVO; | import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelPageReqVO; | ||||||
| import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelSaveReqVO; | import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.vo.IotThingModelSaveReqVO; | ||||||
| import cn.iocoder.yudao.module.iot.convert.thingmodel.IotThingModelConvert; | import cn.iocoder.yudao.module.iot.convert.thingmodel.IotThingModelConvert; | ||||||
| @ -134,6 +135,11 @@ public class IotThingModelServiceImpl implements IotThingModelService { | |||||||
|         return thingModelMapper.selectListByProductKey(productKey); |         return thingModelMapper.selectListByProductKey(productKey); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<IotThingModelDO> getThingModelList(IotThingModelListReqVO reqVO) { | ||||||
|  |         return thingModelMapper.selectList(reqVO); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 校验功能是否存在 |      * 校验功能是否存在 | ||||||
|      * |      * | ||||||
|  | |||||||
| @ -0,0 +1,78 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!DOCTYPE mapper | ||||||
|  |         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | ||||||
|  |         "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||||||
|  | <mapper namespace="cn.iocoder.yudao.module.iot.dal.tdengine.IotDeviceLogDataMapper"> | ||||||
|  |  | ||||||
|  |     <!-- 创建设备日志超级表   初始化只创建一次--> | ||||||
|  |     <update id="createDeviceLogSTable"> | ||||||
|  |         CREATE STABLE device_log ( | ||||||
|  |         ts TIMESTAMP, | ||||||
|  |         id NCHAR(50), | ||||||
|  |         product_key NCHAR(50), | ||||||
|  |         type NCHAR(50), | ||||||
|  |         subType NCHAR(50), | ||||||
|  |         content NCHAR(1024), | ||||||
|  |         report_time TIMESTAMP | ||||||
|  |         )TAGS ( | ||||||
|  |         device_key NCHAR(50) | ||||||
|  |         ) | ||||||
|  |     </update> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     <!-- 创建设备日志子表  讨论:TDengine 在子表不存在的情况下 可在数据插入时 自动建表  要不要去掉创建子表的逻辑  由第一次插入数据时自动创建--> | ||||||
|  |     <update id="createDeviceLogTable"> | ||||||
|  |         CREATE TABLE device_log_${deviceKey} USING device_log TAGS('${deviceKey}') | ||||||
|  |     </update> | ||||||
|  |  | ||||||
|  |     <!-- 插入设备日志数据 在子表不存在的情况下 可在数据插入时 自动建表 --> | ||||||
|  |     <insert id="insert"> | ||||||
|  |         INSERT INTO device_log_${log.deviceKey} (ts, id, product_key, type, subType, content, report_time) | ||||||
|  |         USING device_log | ||||||
|  |         TAGS ('${log.deviceKey}') | ||||||
|  |         VALUES ( | ||||||
|  |             #{log.ts}, | ||||||
|  |             #{log.id}, | ||||||
|  |             #{log.productKey}, | ||||||
|  |             #{log.type}, | ||||||
|  |             #{log.subType}, | ||||||
|  |             #{log.content}, | ||||||
|  |             #{log.reportTime} | ||||||
|  |         ) | ||||||
|  |     </insert> | ||||||
|  |  | ||||||
|  |     <select id="selectPage" resultType="cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO"> | ||||||
|  |         SELECT ts, id, device_key, product_key, type, subType, content, report_time | ||||||
|  |         FROM device_log_${reqVO.deviceKey} | ||||||
|  |         <where> | ||||||
|  |             <if test="reqVO.type != null and reqVO.type != ''"> | ||||||
|  |                 AND type = #{reqVO.type} | ||||||
|  |             </if> | ||||||
|  |             <if test="reqVO.subType != null and reqVO.subType != ''"> | ||||||
|  |                 AND subType = #{reqVO.subType} | ||||||
|  |             </if> | ||||||
|  |             <if test="reqVO.createTime != null"> | ||||||
|  |                 AND ts BETWEEN #{reqVO.createTime[0]} AND #{reqVO.createTime[1]} | ||||||
|  |             </if> | ||||||
|  |         </where> | ||||||
|  |         ORDER BY ts DESC | ||||||
|  |         LIMIT #{reqVO.pageSize} OFFSET #{reqVO.pageNo} | ||||||
|  |     </select> | ||||||
|  |  | ||||||
|  |     <select id="selectCount" resultType="Long"> | ||||||
|  |         SELECT COUNT(*) | ||||||
|  |         FROM device_log_${reqVO.deviceKey} | ||||||
|  |         <where> | ||||||
|  |             <if test="reqVO.type != null and reqVO.type != ''"> | ||||||
|  |                 AND type = #{reqVO.type} | ||||||
|  |             </if> | ||||||
|  |             <if test="reqVO.subType != null and reqVO.subType != ''"> | ||||||
|  |                 AND subType = #{reqVO.subType} | ||||||
|  |             </if> | ||||||
|  |             <if test="reqVO.createTime != null"> | ||||||
|  |                 AND ts BETWEEN #{reqVO.createTime[0]} AND #{reqVO.createTime[1]} | ||||||
|  |             </if> | ||||||
|  |         </where> | ||||||
|  |     </select> | ||||||
|  |  | ||||||
|  | </mapper> | ||||||
| @ -42,7 +42,7 @@ | |||||||
|  |  | ||||||
|     <!-- 根据标签获取最新数据 --> |     <!-- 根据标签获取最新数据 --> | ||||||
|     <select id="selectLastDataListByTags" parameterType="cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TagsSelectDO" |     <select id="selectLastDataListByTags" parameterType="cn.iocoder.yudao.module.iot.dal.dataobject.tdengine.TagsSelectDO" | ||||||
|             resultType="Map"> |             resultType="java.util.Map"> | ||||||
|         SELECT LAST(*) |         SELECT LAST(*) | ||||||
|         FROM ${dataBaseName}.${stableName} |         FROM ${dataBaseName}.${stableName} | ||||||
|         GROUP BY ${tagsName} |         GROUP BY ${tagsName} | ||||||
|  | |||||||
| @ -6,26 +6,28 @@ | |||||||
|  |  | ||||||
|     <!-- 创建物模型消息日志超级表 --> |     <!-- 创建物模型消息日志超级表 --> | ||||||
|     <update id="createSuperTable"> |     <update id="createSuperTable"> | ||||||
|         CREATE STABLE ${dataBaseName}.${superTableName}( |         CREATE STABLE thing_model_message_${productKey}( | ||||||
|             ts TIMESTAMP, |             ts TIMESTAMP, | ||||||
|             id VARCHAR(255), |             id NCHAR(64), | ||||||
|             sys VARCHAR(2048), |             sys NCHAR(2048), | ||||||
|             method VARCHAR(255), |             method NCHAR(255), | ||||||
|             params VARCHAR(2048) |             params NCHAR(2048), | ||||||
|  |             device_name NCHAR(64) | ||||||
|         )TAGS ( |         )TAGS ( | ||||||
|             device_key VARCHAR(255) |             device_key NCHAR(50) | ||||||
|         ) |         ) | ||||||
|     </update> |     </update> | ||||||
|  |  | ||||||
|     <!-- 创建物模型消息日志子表,带有deviceKey的TAG --> |     <!-- 创建物模型消息日志子表,带有deviceKey的TAG --> | ||||||
|     <update id="createTableWithTag"> |     <update id="createTableWithTag"> | ||||||
|         CREATE TABLE IF NOT EXISTS ${dataBaseName}.${tableName} |         CREATE STABLE ${deviceKey} | ||||||
|         USING ${dataBaseName}.${superTableName}( |         USING thing_model_message_${productKey}( | ||||||
|             ts, |             ts, | ||||||
|             id , |             id , | ||||||
|             sys , |             sys , | ||||||
|             method , |             method , | ||||||
|             params |             params , | ||||||
|  |             device_name | ||||||
|         )TAGS( |         )TAGS( | ||||||
|             #{device_key} |             #{device_key} | ||||||
|         ) |         ) | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV