Commit 44b466c67857c5faa66d6fd508060f28b43007db

Authored by YunaiV
2 parents 33496603 6a35ca72

Merge branch 'feature/iot' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into master-jdk17

# Conflicts:
#	pom.xml
#	yudao-dependencies/pom.xml
#	yudao-server/pom.xml
Showing 78 changed files with 3633 additions and 40 deletions
@@ -15,15 +15,16 @@ @@ -15,15 +15,16 @@
15 <!-- 各种 module 拓展 --> 15 <!-- 各种 module 拓展 -->
16 <module>yudao-module-system</module> 16 <module>yudao-module-system</module>
17 <module>yudao-module-infra</module> 17 <module>yudao-module-infra</module>
18 - <module>yudao-module-member</module> 18 +<!-- <module>yudao-module-member</module>-->
19 <!-- <module>yudao-module-bpm</module>--> 19 <!-- <module>yudao-module-bpm</module>-->
20 <!-- <module>yudao-module-report</module>--> 20 <!-- <module>yudao-module-report</module>-->
21 <!-- <module>yudao-module-mp</module>--> 21 <!-- <module>yudao-module-mp</module>-->
22 - <module>yudao-module-pay</module>  
23 - <module>yudao-module-mall</module> 22 +<!-- <module>yudao-module-pay</module>-->
  23 +<!-- <module>yudao-module-mall</module>-->
24 <!-- <module>yudao-module-crm</module>--> 24 <!-- <module>yudao-module-crm</module>-->
25 <!-- <module>yudao-module-erp</module>--> 25 <!-- <module>yudao-module-erp</module>-->
26 <!-- <module>yudao-module-ai</module>--> 26 <!-- <module>yudao-module-ai</module>-->
  27 +<!-- <module>yudao-module-iot</module>-->
27 </modules> 28 </modules>
28 29
29 <name>${project.artifactId}</name> 30 <name>${project.artifactId}</name>
yudao-dependencies/pom.xml
@@ -64,6 +64,7 @@ @@ -64,6 +64,7 @@
64 <ip2region.version>2.7.0</ip2region.version> 64 <ip2region.version>2.7.0</ip2region.version>
65 <bizlog-sdk.version>3.0.6</bizlog-sdk.version> 65 <bizlog-sdk.version>3.0.6</bizlog-sdk.version>
66 <netty.version>4.1.113.Final</netty.version> 66 <netty.version>4.1.113.Final</netty.version>
  67 + <mqtt.version>1.2.5</mqtt.version>
67 <!-- 三方云服务相关 --> 68 <!-- 三方云服务相关 -->
68 <okio.version>3.5.0</okio.version> 69 <okio.version>3.5.0</okio.version>
69 <okhttp3.version>4.11.0</okhttp3.version> 70 <okhttp3.version>4.11.0</okhttp3.version>
@@ -596,6 +597,13 @@ @@ -596,6 +597,13 @@
596 </exclusion> 597 </exclusion>
597 </exclusions> 598 </exclusions>
598 </dependency> 599 </dependency>
  600 +
  601 + <!-- MQTT -->
  602 + <dependency>
  603 + <groupId>org.eclipse.paho</groupId>
  604 + <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
  605 + <version>${mqtt.version}</version>
  606 + </dependency>
599 </dependencies> 607 </dependencies>
600 </dependencyManagement> 608 </dependencyManagement>
601 609
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java
@@ -13,7 +13,7 @@ import java.util.Set; @@ -13,7 +13,7 @@ import java.util.Set;
13 /** 13 /**
14 * 基于 MyBatis Plus 多租户的功能,实现 DB 层面的多租户的功能 14 * 基于 MyBatis Plus 多租户的功能,实现 DB 层面的多租户的功能
15 * 15 *
16 - * @author 芋道源码 16 + * @author
17 */ 17 */
18 public class TenantDatabaseInterceptor implements TenantLineHandler { 18 public class TenantDatabaseInterceptor implements TenantLineHandler {
19 19
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java
@@ -62,6 +62,10 @@ public class BannerApplicationRunner implements ApplicationRunner { @@ -62,6 +62,10 @@ public class BannerApplicationRunner implements ApplicationRunner {
62 if (isNotPresent("cn.iocoder.yudao.module.ai.framework.web.config.AiWebConfiguration")) { 62 if (isNotPresent("cn.iocoder.yudao.module.ai.framework.web.config.AiWebConfiguration")) {
63 System.out.println("[AI 大模型 yudao-module-ai - 已禁用][参考 https://doc.iocoder.cn/ai/build/ 开启]"); 63 System.out.println("[AI 大模型 yudao-module-ai - 已禁用][参考 https://doc.iocoder.cn/ai/build/ 开启]");
64 } 64 }
  65 + // IOT 物联网
  66 + if (isNotPresent("cn.iocoder.yudao.module.iot.framework.web.config.IotWebConfiguration")) {
  67 + System.out.println("[IOT 物联网 yudao-module-iot - 已禁用][参考 https://doc.iocoder.cn/iot/build/ 开启]");
  68 + }
65 }); 69 });
66 } 70 }
67 71
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java
@@ -378,6 +378,12 @@ public class GlobalExceptionHandler { @@ -378,6 +378,12 @@ public class GlobalExceptionHandler {
378 return CommonResult.error(NOT_IMPLEMENTED.getCode(), 378 return CommonResult.error(NOT_IMPLEMENTED.getCode(),
379 "[AI 大模型 yudao-module-ai - 表结构未导入][参考 https://cloud.iocoder.cn/ai/build/ 开启]"); 379 "[AI 大模型 yudao-module-ai - 表结构未导入][参考 https://cloud.iocoder.cn/ai/build/ 开启]");
380 } 380 }
  381 + // 9. IOT 物联网
  382 + if (message.contains("iot_")) {
  383 + log.error("[IOT 物联网 yudao-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]");
  384 + return CommonResult.error(NOT_IMPLEMENTED.getCode(),
  385 + "[IOT 物联网 yudao-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]");
  386 + }
381 return null; 387 return null;
382 } 388 }
383 389
yudao-module-iot/pom.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3 + xmlns="http://maven.apache.org/POM/4.0.0"
  4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <parent>
  6 + <artifactId>yudao</artifactId>
  7 + <groupId>cn.iocoder.boot</groupId>
  8 + <version>${revision}</version>
  9 + </parent>
  10 + <modules>
  11 + <module>yudao-module-iot-api</module>
  12 + <module>yudao-module-iot-biz</module>
  13 + </modules>
  14 + <modelVersion>4.0.0</modelVersion>
  15 +
  16 + <artifactId>yudao-module-iot</artifactId>
  17 + <packaging>pom</packaging>
  18 +
  19 + <name>${project.artifactId}</name>
  20 + <description>
  21 + 物联网模块
  22 + <!-- TODO 芋艿:需要补充下说明! -->
  23 + </description>
  24 +
  25 +</project>
0 \ No newline at end of file 26 \ No newline at end of file
yudao-module-iot/yudao-module-iot-api/pom.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <parent>
  6 + <artifactId>yudao-module-iot</artifactId>
  7 + <groupId>cn.iocoder.boot</groupId>
  8 + <version>${revision}</version>
  9 + </parent>
  10 + <modelVersion>4.0.0</modelVersion>
  11 + <artifactId>yudao-module-iot-api</artifactId>
  12 + <packaging>jar</packaging>
  13 +
  14 + <name>${project.artifactId}</name>
  15 + <description>
  16 + 物联网 模块 API,暴露给其它模块调用
  17 + </description>
  18 +
  19 + <dependencies>
  20 + <dependency>
  21 + <groupId>cn.iocoder.boot</groupId>
  22 + <artifactId>yudao-common</artifactId>
  23 + </dependency>
  24 + </dependencies>
  25 +
  26 +</project>
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java 0 → 100644
  1 +/**
  2 + * 占位
  3 + *
  4 + * TODO 芋艿:后续删除
  5 + */
  6 +package cn.iocoder.yudao.module.iot.api;
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums;
  2 +
  3 +import cn.iocoder.yudao.framework.common.exception.ErrorCode;
  4 +
  5 +/**
  6 + * iot 错误码枚举类
  7 + * <p>
  8 + * iot 系统,使用 1-050-000-000 段
  9 + */
  10 +public interface ErrorCodeConstants {
  11 +
  12 + // ========== IoT 产品相关 1-050-001-000 ============
  13 + ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_050_001_000, "产品不存在");
  14 + ErrorCode PRODUCT_IDENTIFICATION_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在");
  15 + ErrorCode PRODUCT_STATUS_NOT_DELETE = new ErrorCode(1_050_001_002, "产品状是发布状态,不允许删除");
  16 +
  17 + // ========== IoT 产品物模型 1-050-002-000 ============
  18 + ErrorCode THINK_MODEL_FUNCTION_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在");
  19 + ErrorCode THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY = new ErrorCode(1_050_002_001, "ProductKey 对应的产品物模型已存在");
  20 + ErrorCode THINK_MODEL_FUNCTION_IDENTIFIER_EXISTS = new ErrorCode(1_050_002_002, "存在重复的功能标识符。");
  21 + ErrorCode THINK_MODEL_FUNCTION_NAME_EXISTS = new ErrorCode(1_050_002_003, "存在重复的功能名称。");
  22 + ErrorCode THINK_MODEL_FUNCTION_IDENTIFIER_INVALID = new ErrorCode(1_050_002_003, "产品物模型标识无效");
  23 +
  24 + // ========== IoT 设备 1-050-003-000 ============
  25 + ErrorCode DEVICE_NOT_EXISTS = new ErrorCode(1_050_003_000, "设备不存在");
  26 + ErrorCode DEVICE_NAME_EXISTS = new ErrorCode(1_050_003_001, "设备名称在同一产品下必须唯一");
  27 + ErrorCode DEVICE_HAS_CHILDREN = new ErrorCode(1_050_003_002, "有子设备,不允许删除");
  28 + ErrorCode DEVICE_NAME_CANNOT_BE_MODIFIED = new ErrorCode(1_050_003_003, "设备名称不能修改");
  29 + ErrorCode DEVICE_PRODUCT_CANNOT_BE_MODIFIED = new ErrorCode(1_050_003_004, "产品不能修改");
  30 + ErrorCode DEVICE_INVALID_DEVICE_STATUS = new ErrorCode(1_050_003_005, "无效的设备状态");
  31 +
  32 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStatusEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.device;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.Getter;
  5 +
  6 +import java.util.Arrays;
  7 +
  8 +/**
  9 + * IoT 设备状态枚举
  10 + *
  11 + * @author haohao
  12 + */
  13 +@Getter
  14 +public enum IotDeviceStatusEnum implements IntArrayValuable {
  15 +
  16 + INACTIVE(0, "未激活"),
  17 + ONLINE(1, "在线"),
  18 + OFFLINE(2, "离线"),
  19 + DISABLED(3, "已禁用");
  20 +
  21 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotDeviceStatusEnum::getStatus).toArray();
  22 +
  23 + /**
  24 + * 状态
  25 + */
  26 + private final Integer status;
  27 + /**
  28 + * 状态名
  29 + */
  30 + private final String name;
  31 +
  32 + IotDeviceStatusEnum(Integer status, String name) {
  33 + this.status = status;
  34 + this.name = name;
  35 + }
  36 +
  37 + public static IotDeviceStatusEnum fromStatus(Integer status) {
  38 + for (IotDeviceStatusEnum value : values()) {
  39 + if (value.getStatus().equals(status)) {
  40 + return value;
  41 + }
  42 + }
  43 + return null;
  44 + }
  45 +
  46 + public static boolean isValidStatus(Integer status) {
  47 + return fromStatus(status) != null;
  48 + }
  49 +
  50 + @Override
  51 + public int[] array() {
  52 + return ARRAYS;
  53 + }
  54 +
  55 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.product;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * IOT 访问方式枚举类
  8 + *
  9 + * @author ahh
  10 + */
  11 +@AllArgsConstructor
  12 +@Getter
  13 +public enum IotAccessModeEnum {
  14 +
  15 + READ("r"),
  16 + WRITE("w"),
  17 + READ_WRITE("rw");
  18 +
  19 + private final String mode;
  20 +
  21 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotDataFormatEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.product;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * 产品数据格式枚举类
  11 + *
  12 + * @author ahh
  13 + * @see <a href="https://help.aliyun.com/zh/iot/user-guide/message-parsing">阿里云 - 什么是消息解析</a>
  14 + */
  15 +@AllArgsConstructor
  16 +@Getter
  17 +public enum IotDataFormatEnum implements IntArrayValuable {
  18 +
  19 + JSON(0, "标准数据格式(JSON)"),
  20 + CUSTOMIZE(1, "透传/自定义");
  21 +
  22 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotDataFormatEnum::getType).toArray();
  23 +
  24 + /**
  25 + * 类型
  26 + */
  27 + private final Integer type;
  28 + /**
  29 + * 描述
  30 + */
  31 + private final String description;
  32 +
  33 + @Override
  34 + public int[] array() {
  35 + return ARRAYS;
  36 + }
  37 +
  38 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.product;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IOT 联网方式枚举类
  11 + *
  12 + * @author ahh
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum IotNetTypeEnum implements IntArrayValuable {
  17 +
  18 + WIFI(0, "Wi-Fi"),
  19 + CELLULAR(1, "Cellular"),
  20 + ETHERNET(2, "Ethernet"),
  21 + OTHER(3, "其他");
  22 +
  23 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotNetTypeEnum::getType).toArray();
  24 +
  25 + /**
  26 + * 类型
  27 + */
  28 + private final Integer type;
  29 + /**
  30 + * 描述
  31 + */
  32 + private final String description;
  33 +
  34 + @Override
  35 + public int[] array() {
  36 + return ARRAYS;
  37 + }
  38 +
  39 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.product;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IOT 产品的设备类型
  11 + *
  12 + * @author ahh
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum IotProductDeviceTypeEnum implements IntArrayValuable {
  17 +
  18 + DIRECT(0, "直连设备"),
  19 + GATEWAY_CHILD(1, "网关子设备"),
  20 + GATEWAY(2, "网关设备");
  21 +
  22 + /**
  23 + * 类型
  24 + */
  25 + private final Integer type;
  26 +
  27 + /**
  28 + * 描述
  29 + */
  30 + private final String description;
  31 +
  32 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotProductDeviceTypeEnum::getType).toArray();
  33 +
  34 + @Override
  35 + public int[] array() {
  36 + return ARRAYS;
  37 + }
  38 +
  39 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.product;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IOT 产品功能(物模型)类型枚举类
  11 + *
  12 + * @author ahh
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum IotProductFunctionTypeEnum implements IntArrayValuable {
  17 +
  18 + PROPERTY(1, "属性"),
  19 + SERVICE(2, "服务"),
  20 + EVENT(3, "事件");
  21 +
  22 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotProductFunctionTypeEnum::getType).toArray();
  23 +
  24 + /**
  25 + * 类型
  26 + */
  27 + private final Integer type;
  28 + /**
  29 + * 描述
  30 + */
  31 + private final String description;
  32 +
  33 + @Override
  34 + public int[] array() {
  35 + return ARRAYS;
  36 + }
  37 +
  38 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.product;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IOT 产品的状态枚举类
  11 + *
  12 + * @author ahh
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum IotProductStatusEnum implements IntArrayValuable {
  17 +
  18 + UNPUBLISHED(0, "开发中"),
  19 + PUBLISHED(1, "已发布");
  20 +
  21 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotProductStatusEnum::getType).toArray();
  22 +
  23 + /**
  24 + * 类型
  25 + */
  26 + private final Integer type;
  27 + /**
  28 + * 描述
  29 + */
  30 + private final String description;
  31 +
  32 + @Override
  33 + public int[] array() {
  34 + return ARRAYS;
  35 + }
  36 +
  37 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProtocolTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.product;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IOT 接入网关协议枚举类
  11 + *
  12 + * @author ahh
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum IotProtocolTypeEnum implements IntArrayValuable {
  17 +
  18 + CUSTOM(0, "自定义"),
  19 + MODBUS(1, "Modbus"),
  20 + OPC_UA(2, "OPC UA"),
  21 + ZIGBEE(3, "ZigBee"),
  22 + BLE(4, "BLE");
  23 +
  24 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotProtocolTypeEnum::getType).toArray();
  25 +
  26 + /**
  27 + * 类型
  28 + */
  29 + private final Integer type;
  30 + /**
  31 + * 描述
  32 + */
  33 + private final String description;
  34 +
  35 + @Override
  36 + public int[] array() {
  37 + return ARRAYS;
  38 + }
  39 +
  40 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotValidateTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.product;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IOT 数据校验级别枚举类
  11 + *
  12 + * @author ahh
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum IotValidateTypeEnum implements IntArrayValuable {
  17 +
  18 + WEAK(0, "弱校验"),
  19 + NONE(1, "免校验");
  20 +
  21 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotValidateTypeEnum::getType).toArray();
  22 +
  23 + /**
  24 + * 类型
  25 + */
  26 + private final Integer type;
  27 + /**
  28 + * 描述
  29 + */
  30 + private final String description;
  31 +
  32 + @Override
  33 + public int[] array() {
  34 + return ARRAYS;
  35 + }
  36 +
  37 +}
yudao-module-iot/yudao-module-iot-biz/pom.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <parent>
  6 + <artifactId>yudao-module-iot</artifactId>
  7 + <groupId>cn.iocoder.boot</groupId>
  8 + <version>${revision}</version>
  9 + </parent>
  10 + <modelVersion>4.0.0</modelVersion>
  11 + <packaging>jar</packaging>
  12 +
  13 + <artifactId>yudao-module-iot-biz</artifactId>
  14 +
  15 + <name>${project.artifactId}</name>
  16 + <description>
  17 + 物联网 模块,主要实现 产品管理、设备管理、协议管理等功能。
  18 + <!-- TODO 芋艿:后续补充下 -->
  19 + </description>
  20 +
  21 + <dependencies>
  22 + <dependency>
  23 + <groupId>cn.iocoder.boot</groupId>
  24 + <artifactId>yudao-module-iot-api</artifactId>
  25 + <version>${revision}</version>
  26 + </dependency>
  27 +
  28 + <!-- Web 相关 -->
  29 + <dependency>
  30 + <groupId>cn.iocoder.boot</groupId>
  31 + <artifactId>yudao-spring-boot-starter-web</artifactId>
  32 + </dependency>
  33 +
  34 + <dependency>
  35 + <groupId>cn.iocoder.boot</groupId>
  36 + <artifactId>yudao-spring-boot-starter-security</artifactId>
  37 + </dependency>
  38 +
  39 + <!-- DB 相关 -->
  40 + <dependency>
  41 + <groupId>cn.iocoder.boot</groupId>
  42 + <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
  43 + </dependency>
  44 +
  45 + <!-- Test 测试相关 -->
  46 + <dependency>
  47 + <groupId>cn.iocoder.boot</groupId>
  48 + <artifactId>yudao-spring-boot-starter-test</artifactId>
  49 + </dependency>
  50 +
  51 + <!-- 工具类相关 -->
  52 + <dependency>
  53 + <groupId>cn.iocoder.boot</groupId>
  54 + <artifactId>yudao-spring-boot-starter-excel</artifactId>
  55 + </dependency>
  56 +
  57 + <!-- MQTT -->
  58 + <dependency>
  59 + <groupId>org.eclipse.paho</groupId>
  60 + <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
  61 + </dependency>
  62 + </dependencies>
  63 +
  64 +</project>
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO;
  7 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceRespVO;
  8 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO;
  9 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceStatusUpdateReqVO;
  10 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
  11 +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
  12 +import io.swagger.v3.oas.annotations.Operation;
  13 +import io.swagger.v3.oas.annotations.Parameter;
  14 +import io.swagger.v3.oas.annotations.tags.Tag;
  15 +import jakarta.annotation.Resource;
  16 +import jakarta.validation.Valid;
  17 +import org.springframework.security.access.prepost.PreAuthorize;
  18 +import org.springframework.validation.annotation.Validated;
  19 +import org.springframework.web.bind.annotation.*;
  20 +
  21 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  22 +
  23 +@Tag(name = "管理后台 - IoT 设备")
  24 +@RestController
  25 +@RequestMapping("/iot/device")
  26 +@Validated
  27 +public class IotDeviceController {
  28 +
  29 + @Resource
  30 + private IotDeviceService deviceService;
  31 +
  32 + @PostMapping("/create")
  33 + @Operation(summary = "创建设备")
  34 + @PreAuthorize("@ss.hasPermission('iot:device:create')")
  35 + public CommonResult<Long> createDevice(@Valid @RequestBody IotDeviceSaveReqVO createReqVO) {
  36 + return success(deviceService.createDevice(createReqVO));
  37 + }
  38 +
  39 + @PutMapping("/update-status")
  40 + @Operation(summary = "更新设备状态")
  41 + @PreAuthorize("@ss.hasPermission('iot:device:update')")
  42 + public CommonResult<Boolean> updateDeviceStatus(@Valid @RequestBody IotDeviceStatusUpdateReqVO updateReqVO) {
  43 + deviceService.updateDeviceStatus(updateReqVO);
  44 + return success(true);
  45 + }
  46 +
  47 + @PutMapping("/update")
  48 + @Operation(summary = "更新设备")
  49 + @PreAuthorize("@ss.hasPermission('iot:device:update')")
  50 + public CommonResult<Boolean> updateDevice(@Valid @RequestBody IotDeviceSaveReqVO updateReqVO) {
  51 + deviceService.updateDevice(updateReqVO);
  52 + return success(true);
  53 + }
  54 +
  55 + @DeleteMapping("/delete")
  56 + @Operation(summary = "删除设备")
  57 + @Parameter(name = "id", description = "编号", required = true)
  58 + @PreAuthorize("@ss.hasPermission('iot:device:delete')")
  59 + public CommonResult<Boolean> deleteDevice(@RequestParam("id") Long id) {
  60 + deviceService.deleteDevice(id);
  61 + return success(true);
  62 + }
  63 +
  64 + @GetMapping("/get")
  65 + @Operation(summary = "获得设备")
  66 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  67 + @PreAuthorize("@ss.hasPermission('iot:device:query')")
  68 + public CommonResult<IotDeviceRespVO> getDevice(@RequestParam("id") Long id) {
  69 + IotDeviceDO device = deviceService.getDevice(id);
  70 + return success(BeanUtils.toBean(device, IotDeviceRespVO.class));
  71 + }
  72 +
  73 + @GetMapping("/page")
  74 + @Operation(summary = "获得设备分页")
  75 + @PreAuthorize("@ss.hasPermission('iot:device:query')")
  76 + public CommonResult<PageResult<IotDeviceRespVO>> getDevicePage(@Valid IotDevicePageReqVO pageReqVO) {
  77 + PageResult<IotDeviceDO> pageResult = deviceService.getDevicePage(pageReqVO);
  78 + return success(BeanUtils.toBean(pageResult, IotDeviceRespVO.class));
  79 + }
  80 +
  81 + @GetMapping("/count")
  82 + @Operation(summary = "获得设备数量")
  83 + @Parameter(name = "productId", description = "产品编号", example = "1")
  84 + @PreAuthorize("@ss.hasPermission('iot:device:query')")
  85 + public CommonResult<Long> getDeviceCount(@RequestParam("productId") Long productId) {
  86 + return success(deviceService.getDeviceCountByProductId(productId));
  87 + }
  88 +
  89 +}
0 \ No newline at end of file 90 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  5 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
  6 +import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum;
  7 +import io.swagger.v3.oas.annotations.media.Schema;
  8 +import lombok.Data;
  9 +import lombok.EqualsAndHashCode;
  10 +import lombok.ToString;
  11 +import org.springframework.format.annotation.DateTimeFormat;
  12 +
  13 +import java.math.BigDecimal;
  14 +import java.time.LocalDateTime;
  15 +
  16 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  17 +
  18 +@Schema(description = "管理后台 - IoT 设备分页 Request VO")
  19 +@Data
  20 +@EqualsAndHashCode(callSuper = true)
  21 +@ToString(callSuper = true)
  22 +public class IotDevicePageReqVO extends PageParam {
  23 +
  24 + // TODO @芋艿:需要去掉一些多余的字段;
  25 +
  26 + @Schema(description = "设备唯一标识符", example = "24602")
  27 + private String deviceKey;
  28 +
  29 + @Schema(description = "设备名称", example = "王五")
  30 + private String deviceName;
  31 +
  32 + @Schema(description = "备注名称", example = "张三")
  33 + private String nickname;
  34 +
  35 + @Schema(description = "产品编号", example = "26202")
  36 + private Long productId;
  37 +
  38 + @Schema(description = "产品标识")
  39 + private String productKey;
  40 +
  41 + @Schema(description = "设备类型", example = "1")
  42 + @InEnum(IotProductDeviceTypeEnum.class)
  43 + private Integer deviceType;
  44 +
  45 + @Schema(description = "网关设备 ID", example = "16380")
  46 + private Long gatewayId;
  47 +
  48 + @Schema(description = "设备状态", example = "1")
  49 + @InEnum(IotDeviceStatusEnum.class)
  50 + private Integer status;
  51 +
  52 + @Schema(description = "设备状态最后更新时间")
  53 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  54 + private LocalDateTime[] statusLastUpdateTime;
  55 +
  56 + @Schema(description = "最后上线时间")
  57 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  58 + private LocalDateTime[] lastOnlineTime;
  59 +
  60 + @Schema(description = "最后离线时间")
  61 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  62 + private LocalDateTime[] lastOfflineTime;
  63 +
  64 + @Schema(description = "设备激活时间")
  65 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  66 + private LocalDateTime[] activeTime;
  67 +
  68 + @Schema(description = "设备密钥,用于设备认证,需安全存储")
  69 + private String deviceSecret;
  70 +
  71 + @Schema(description = "MQTT 客户端 ID", example = "24602")
  72 + private String mqttClientId;
  73 +
  74 + @Schema(description = "MQTT 用户名", example = "芋艿")
  75 + private String mqttUsername;
  76 +
  77 + @Schema(description = "MQTT 密码")
  78 + private String mqttPassword;
  79 +
  80 + @Schema(description = "认证类型(如一机一密、动态注册)", example = "2")
  81 + private String authType;
  82 +
  83 + @Schema(description = "创建时间")
  84 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  85 + private LocalDateTime[] createTime;
  86 +
  87 +}
0 \ No newline at end of file 88 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo;
  2 +
  3 +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
  4 +import com.alibaba.excel.annotation.ExcelProperty;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import lombok.Data;
  7 +
  8 +import java.math.BigDecimal;
  9 +import java.time.LocalDateTime;
  10 +
  11 +@Schema(description = "管理后台 - IoT 设备 Response VO")
  12 +@Data
  13 +@ExcelIgnoreUnannotated
  14 +public class IotDeviceRespVO {
  15 +
  16 + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
  17 + private Long id;
  18 +
  19 + @Schema(description = "设备唯一标识符", requiredMode = Schema.RequiredMode.REQUIRED)
  20 + @ExcelProperty("设备唯一标识符")
  21 + private String deviceKey;
  22 +
  23 + @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
  24 + @ExcelProperty("设备名称备")
  25 + private String deviceName;
  26 +
  27 + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202")
  28 + @ExcelProperty("产品编号")
  29 + private Long productId;
  30 +
  31 + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED)
  32 + @ExcelProperty("产品 Key")
  33 + private String productKey;
  34 +
  35 + @Schema(description = "设备类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  36 + @ExcelProperty("设备类型")
  37 + private Integer deviceType;
  38 +
  39 + @Schema(description = "设备备注名称", example = "张三")
  40 + @ExcelProperty("设备备注名称")
  41 + private String nickname;
  42 +
  43 + @Schema(description = "网关设备 ID", example = "16380")
  44 + private Long gatewayId;
  45 +
  46 + @Schema(description = "设备状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  47 + @ExcelProperty("设备状态")
  48 + private Integer status;
  49 +
  50 + @Schema(description = "设备状态最后更新时间")
  51 + @ExcelProperty("设备状态最后更新时间")
  52 + private LocalDateTime statusLastUpdateTime;
  53 +
  54 + @Schema(description = "最后上线时间")
  55 + @ExcelProperty("最后上线时间")
  56 + private LocalDateTime lastOnlineTime;
  57 +
  58 + @Schema(description = "最后离线时间")
  59 + @ExcelProperty("最后离线时间")
  60 + private LocalDateTime lastOfflineTime;
  61 +
  62 + @Schema(description = "设备激活时间")
  63 + @ExcelProperty("设备激活时间")
  64 + private LocalDateTime activeTime;
  65 +
  66 + @Schema(description = "设备密钥,用于设备认证")
  67 + @ExcelProperty("设备密钥")
  68 + private String deviceSecret;
  69 +
  70 + @Schema(description = "MQTT 客户端 ID", example = "24602")
  71 + @ExcelProperty("MQTT 客户端 ID")
  72 + private String mqttClientId;
  73 +
  74 + @Schema(description = "MQTT 用户名", example = "芋艿")
  75 + @ExcelProperty("MQTT 用户名")
  76 + private String mqttUsername;
  77 +
  78 + @Schema(description = "MQTT 密码")
  79 + @ExcelProperty("MQTT 密码")
  80 + private String mqttPassword;
  81 +
  82 + @Schema(description = "认证类型(如一机一密、动态注册)", example = "2")
  83 + @ExcelProperty("认证类型(如一机一密、动态注册)")
  84 + private String authType;
  85 +
  86 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  87 + @ExcelProperty("创建时间")
  88 + private LocalDateTime createTime;
  89 +
  90 +}
0 \ No newline at end of file 91 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +@Schema(description = "管理后台 - IoT 设备新增/修改 Request VO")
  7 +@Data
  8 +public class IotDeviceSaveReqVO {
  9 +
  10 + @Schema(description = "设备编号", example = "177")
  11 + private Long id;
  12 +
  13 + @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
  14 + private String deviceName;
  15 +
  16 + @Schema(description = "备注名称", example = "张三")
  17 + private String nickname;
  18 +
  19 + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202")
  20 + private Long productId;
  21 +
  22 +}
0 \ No newline at end of file 23 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceStatusUpdateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  4 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import jakarta.validation.constraints.NotNull;
  7 +import lombok.Data;
  8 +
  9 +@Schema(description = "管理后台 - IoT 设备状态更新 Request VO")
  10 +@Data
  11 +public class IotDeviceStatusUpdateReqVO {
  12 +
  13 + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  14 + @NotNull(message = "设备编号不能为空")
  15 + private Long id;
  16 +
  17 + @Schema(description = "设备状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  18 + @NotNull(message = "设备状态不能为空")
  19 + @InEnum(IotDeviceStatusEnum.class)
  20 + private Integer status;
  21 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.product;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductPageReqVO;
  7 +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductRespVO;
  8 +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSaveReqVO;
  9 +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSimpleRespVO;
  10 +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
  11 +import cn.iocoder.yudao.module.iot.service.product.IotProductService;
  12 +import io.swagger.v3.oas.annotations.Operation;
  13 +import io.swagger.v3.oas.annotations.Parameter;
  14 +import io.swagger.v3.oas.annotations.tags.Tag;
  15 +import jakarta.annotation.Resource;
  16 +import jakarta.validation.Valid;
  17 +import org.springframework.security.access.prepost.PreAuthorize;
  18 +import org.springframework.validation.annotation.Validated;
  19 +import org.springframework.web.bind.annotation.*;
  20 +
  21 +import java.util.List;
  22 +
  23 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  24 +
  25 +@Tag(name = "管理后台 - IoT 产品")
  26 +@RestController
  27 +@RequestMapping("/iot/product")
  28 +@Validated
  29 +public class IotProductController {
  30 +
  31 + @Resource
  32 + private IotProductService productService;
  33 +
  34 + @PostMapping("/create")
  35 + @Operation(summary = "创建产品")
  36 + @PreAuthorize("@ss.hasPermission('iot:product:create')")
  37 + public CommonResult<Long> createProduct(@Valid @RequestBody IotProductSaveReqVO createReqVO) {
  38 + return success(productService.createProduct(createReqVO));
  39 + }
  40 +
  41 + @PutMapping("/update")
  42 + @Operation(summary = "更新产品")
  43 + @PreAuthorize("@ss.hasPermission('iot:product:update')")
  44 + public CommonResult<Boolean> updateProduct(@Valid @RequestBody IotProductSaveReqVO updateReqVO) {
  45 + productService.updateProduct(updateReqVO);
  46 + return success(true);
  47 + }
  48 +
  49 + @PutMapping("/update-status")
  50 + @Operation(summary = "更新产品状态")
  51 + @Parameter(name = "id", description = "编号", required = true)
  52 + @Parameter(name = "status", description = "状态", required = true)
  53 + @PreAuthorize("@ss.hasPermission('iot:product:update')")
  54 + public CommonResult<Boolean> updateProductStatus(@RequestParam("id") Long id,
  55 + @RequestParam("status") Integer status) {
  56 + productService.updateProductStatus(id, status);
  57 + return success(true);
  58 + }
  59 +
  60 + @DeleteMapping("/delete")
  61 + @Operation(summary = "删除产品")
  62 + @Parameter(name = "id", description = "编号", required = true)
  63 + @PreAuthorize("@ss.hasPermission('iot:product:delete')")
  64 + public CommonResult<Boolean> deleteProduct(@RequestParam("id") Long id) {
  65 + productService.deleteProduct(id);
  66 + return success(true);
  67 + }
  68 +
  69 + @GetMapping("/get")
  70 + @Operation(summary = "获得产品")
  71 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  72 + @PreAuthorize("@ss.hasPermission('iot:product:query')")
  73 + public CommonResult<IotProductRespVO> getProduct(@RequestParam("id") Long id) {
  74 + IotProductDO product = productService.getProduct(id);
  75 + return success(BeanUtils.toBean(product, IotProductRespVO.class));
  76 + }
  77 +
  78 + @GetMapping("/page")
  79 + @Operation(summary = "获得产品分页")
  80 + @PreAuthorize("@ss.hasPermission('iot:product:query')")
  81 + public CommonResult<PageResult<IotProductRespVO>> getProductPage(@Valid IotProductPageReqVO pageReqVO) {
  82 + PageResult<IotProductDO> pageResult = productService.getProductPage(pageReqVO);
  83 + return success(BeanUtils.toBean(pageResult, IotProductRespVO.class));
  84 + }
  85 +
  86 + // TODO @haohao:改成 simple-list 哈
  87 + @GetMapping("/list-all-simple")
  88 + @Operation(summary = "获得所有产品列表")
  89 + @PreAuthorize("@ss.hasPermission('iot:product:query')")
  90 + public CommonResult<List<IotProductSimpleRespVO>> listAllSimpleProducts() {
  91 + List<IotProductDO> list = productService.getProductList();
  92 + return success(BeanUtils.toBean(list, IotProductSimpleRespVO.class));
  93 + }
  94 +
  95 +}
0 \ No newline at end of file 96 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.product.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +@Schema(description = "管理后台 - IoT 产品分页 Request VO")
  10 +@Data
  11 +@EqualsAndHashCode(callSuper = true)
  12 +@ToString(callSuper = true)
  13 +public class IotProductPageReqVO extends PageParam {
  14 +
  15 + @Schema(description = "产品名称", example = "李四")
  16 + private String name;
  17 +
  18 + @Schema(description = "产品标识")
  19 + private String productKey;
  20 +
  21 +}
0 \ No newline at end of file 22 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.product.vo;
  2 +
  3 +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
  4 +import com.alibaba.excel.annotation.ExcelProperty;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import lombok.Data;
  7 +
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Schema(description = "管理后台 - IoT 产品 Response VO")
  11 +@Data
  12 +@ExcelIgnoreUnannotated
  13 +public class IotProductRespVO {
  14 +
  15 + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26087")
  16 + @ExcelProperty("产品编号")
  17 + private Long id;
  18 +
  19 + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
  20 + @ExcelProperty("产品名称")
  21 + private String name;
  22 +
  23 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  24 + @ExcelProperty("创建时间")
  25 + private LocalDateTime createTime;
  26 +
  27 + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED)
  28 + @ExcelProperty("产品标识")
  29 + private String productKey;
  30 +
  31 + @Schema(description = "接入网关协议", example = "2")
  32 + @ExcelProperty("接入网关协议")
  33 + private Integer protocolType;
  34 +
  35 + @Schema(description = "协议编号(脚本解析 id)", requiredMode = Schema.RequiredMode.REQUIRED, example = "13177")
  36 + @ExcelProperty("协议编号(脚本解析 id)")
  37 + private Long protocolId;
  38 +
  39 + @Schema(description = "产品所属品类标识符", example = "14237")
  40 + @ExcelProperty("产品所属品类标识符")
  41 + private Long categoryId;
  42 +
  43 + @Schema(description = "产品描述", example = "你猜")
  44 + @ExcelProperty("产品描述")
  45 + private String description;
  46 +
  47 + @Schema(description = "数据校验级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  48 + @ExcelProperty("数据校验级别")
  49 + private Integer validateType;
  50 +
  51 + @Schema(description = "产品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  52 + @ExcelProperty("产品状态")
  53 + private Integer status;
  54 +
  55 + @Schema(description = "设备类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  56 + @ExcelProperty("设备类型")
  57 + private Integer deviceType;
  58 +
  59 + @Schema(description = "联网方式", example = "2")
  60 + @ExcelProperty("联网方式")
  61 + private Integer netType;
  62 +
  63 + @Schema(description = "数据格式")
  64 + @ExcelProperty("数据格式")
  65 + private Integer dataFormat;
  66 +
  67 +}
0 \ No newline at end of file 68 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.product.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  4 +import cn.iocoder.yudao.module.iot.enums.product.*;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import jakarta.validation.constraints.NotEmpty;
  7 +import jakarta.validation.constraints.NotNull;
  8 +import lombok.Data;
  9 +
  10 +@Schema(description = "管理后台 - IoT 产品新增/修改 Request VO")
  11 +@Data
  12 +public class IotProductSaveReqVO {
  13 +
  14 + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.AUTO, example = "1")
  15 + private Long id;
  16 +
  17 + @Schema(description = "产品Key", requiredMode = Schema.RequiredMode.AUTO, example = "12345abc")
  18 + private String productKey;
  19 +
  20 + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "温湿度")
  21 + @NotEmpty(message = "产品名称不能为空")
  22 + private String name;
  23 +
  24 + @Schema(description = "设备类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
  25 + @InEnum(value = IotProductDeviceTypeEnum.class, message = "设备类型必须是 {value}")
  26 + @NotNull(message = "设备类型不能为空")
  27 + private Integer deviceType;
  28 +
  29 + @Schema(description = "联网方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
  30 + @InEnum(value = IotNetTypeEnum.class, message = "联网方式必须是 {value}")
  31 + private Integer netType;
  32 +
  33 + @Schema(description = "接入网关协议", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
  34 + @InEnum(value = IotProtocolTypeEnum.class, message = "接入网关协议必须是 {value}")
  35 + private Integer protocolType;
  36 +
  37 + @Schema(description = "数据格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
  38 + @InEnum(value = IotDataFormatEnum.class, message = "数据格式必须是 {value}")
  39 + @NotNull(message = "数据格式不能为空")
  40 + private Integer dataFormat;
  41 +
  42 + @Schema(description = "数据校验级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
  43 + @InEnum(value = IotValidateTypeEnum.class, message = "数据校验级别必须是 {value}")
  44 + @NotNull(message = "数据校验级别不能为空")
  45 + private Integer validateType;
  46 +
  47 + @Schema(description = "产品描述", example = "描述")
  48 + private String description;
  49 +
  50 +}
0 \ No newline at end of file 51 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSimpleRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.product.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +@Schema(description = "管理后台 - IoT 产品 Response VO")
  7 +@Data
  8 +public class IotProductSimpleRespVO {
  9 +
  10 + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26087")
  11 + private Long id;
  12 +
  13 + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
  14 + private String name;
  15 +
  16 +}
0 \ No newline at end of file 17 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http 0 → 100644
  1 +### 请求 /iot/think-model-function/create 接口 => 成功
  2 +POST {{baseUrl}}/iot/think-model-function/create
  3 +Content-Type: application/json
  4 +tenant-id: {{adminTenentId}}
  5 +Authorization: Bearer {{token}}
  6 +
  7 +{
  8 + "productId": 1001,
  9 + "productKey": "smart-sensor-001",
  10 + "identifier": "Temperature",
  11 + "name": "温度",
  12 + "description": "当前温度值",
  13 + "type": 1,
  14 + "property": {
  15 + "identifier": "Temperature",
  16 + "name": "温度",
  17 + "accessMode": "r",
  18 + "required": true,
  19 + "dataType": {
  20 + "type": "float",
  21 + "specs": {
  22 + "min": -10.0,
  23 + "max": 100.0,
  24 + "step": 0.1,
  25 + "unit": "℃"
  26 + }
  27 + },
  28 + "description": "当前温度值"
  29 + }
  30 +}
  31 +
  32 +### 请求 /iot/think-model-function/create 接口 => 成功
  33 +POST {{baseUrl}}/iot/think-model-function/create
  34 +Content-Type: application/json
  35 +tenant-id: {{adminTenentId}}
  36 +Authorization: Bearer {{token}}
  37 +
  38 +{
  39 + "productId": 1001,
  40 + "productKey": "smart-sensor-001",
  41 + "identifier": "Humidity",
  42 + "name": "湿度",
  43 + "description": "当前湿度值",
  44 + "type": 1,
  45 + "property": {
  46 + "identifier": "Humidity",
  47 + "name": "湿度",
  48 + "accessMode": "r",
  49 + "required": true,
  50 + "dataType": {
  51 + "type": "float",
  52 + "specs": {
  53 + "min": 0.0,
  54 + "max": 100.0,
  55 + "step": 0.1,
  56 + "unit": "%"
  57 + }
  58 + },
  59 + "description": "当前湿度值"
  60 + }
  61 +}
  62 +
  63 +
  64 +
  65 +
  66 +### 请求 /iot/think-model-function/update 接口 => 成功
  67 +PUT {{baseUrl}}/iot/think-model-function/update
  68 +Content-Type: application/json
  69 +tenant-id: {{adminTenentId}}
  70 +Authorization: Bearer {{token}}
  71 +
  72 +{
  73 + "id": 11,
  74 + "productId": 1001,
  75 + "productKey": "smart-sensor-001",
  76 + "identifier": "Temperature",
  77 + "name": "温度",
  78 + "description": "当前温度值",
  79 + "type": 1,
  80 + "property": {
  81 + "identifier": "Temperature",
  82 + "name": "温度",
  83 + "accessMode": "r",
  84 + "required": true,
  85 + "dataType": {
  86 + "type": "float",
  87 + "specs": {
  88 + "min": -111.0,
  89 + "max": 222.0,
  90 + "step": 0.1,
  91 + "unit": "℃"
  92 + }
  93 + },
  94 + "description": "当前温度值"
  95 + }
  96 +}
  97 +
  98 +### 请求 /iot/think-model-function/delete 接口 => 成功
  99 +DELETE {{baseUrl}}/iot/think-model-function/delete?id=7
  100 +tenant-id: {{adminTenentId}}
  101 +Authorization: Bearer {{token}}
  102 +
  103 +### 请求 /iot/think-model-function/get 接口 => 成功
  104 +GET {{baseUrl}}/iot/think-model-function/get?id=10
  105 +tenant-id: {{adminTenentId}}
  106 +Authorization: Bearer {{token}}
  107 +
  108 +
  109 +### 请求 /iot/think-model-function/list-by-product-id 接口 => 成功
  110 +GET {{baseUrl}}/iot/think-model-function/list-by-product-id?productId=1001
  111 +tenant-id: {{adminTenentId}}
  112 +Authorization: Bearer {{token}}
0 \ No newline at end of file 113 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionPageReqVO;
  7 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO;
  8 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
  9 +import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert;
  10 +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
  11 +import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService;
  12 +import io.swagger.v3.oas.annotations.Operation;
  13 +import io.swagger.v3.oas.annotations.Parameter;
  14 +import io.swagger.v3.oas.annotations.tags.Tag;
  15 +import jakarta.annotation.Resource;
  16 +import jakarta.validation.Valid;
  17 +import org.springframework.security.access.prepost.PreAuthorize;
  18 +import org.springframework.validation.annotation.Validated;
  19 +import org.springframework.web.bind.annotation.*;
  20 +
  21 +import java.util.List;
  22 +
  23 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  24 +
  25 +@Tag(name = "管理后台 - IoT 产品物模型")
  26 +@RestController
  27 +@RequestMapping("/iot/think-model-function")
  28 +@Validated
  29 +public class IotThinkModelFunctionController {
  30 +
  31 + @Resource
  32 + private IotThinkModelFunctionService thinkModelFunctionService;
  33 +
  34 + @PostMapping("/create")
  35 + @Operation(summary = "创建产品物模型")
  36 + @PreAuthorize("@ss.hasPermission('iot:think-model-function:create')")
  37 + public CommonResult<Long> createThinkModelFunction(@Valid @RequestBody IotThinkModelFunctionSaveReqVO createReqVO) {
  38 + return success(thinkModelFunctionService.createThinkModelFunction(createReqVO));
  39 + }
  40 +
  41 + @PutMapping("/update")
  42 + @Operation(summary = "更新产品物模型")
  43 + @PreAuthorize("@ss.hasPermission('iot:think-model-function:update')")
  44 + public CommonResult<Boolean> updateThinkModelFunction(@Valid @RequestBody IotThinkModelFunctionSaveReqVO updateReqVO) {
  45 + thinkModelFunctionService.updateThinkModelFunction(updateReqVO);
  46 + return success(true);
  47 + }
  48 +
  49 + @DeleteMapping("/delete")
  50 + @Operation(summary = "删除产品物模型")
  51 + @Parameter(name = "id", description = "编号", required = true)
  52 + @PreAuthorize("@ss.hasPermission('iot:think-model-function:delete')")
  53 + public CommonResult<Boolean> deleteThinkModelFunction(@RequestParam("id") Long id) {
  54 + thinkModelFunctionService.deleteThinkModelFunction(id);
  55 + return success(true);
  56 + }
  57 +
  58 + @GetMapping("/get")
  59 + @Operation(summary = "获得产品物模型")
  60 + @Parameter(name = "id", description = "编号", required = true)
  61 + @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')")
  62 + public CommonResult<IotThinkModelFunctionRespVO> getThinkModelFunction(@RequestParam("id") Long id) {
  63 + IotThinkModelFunctionDO function = thinkModelFunctionService.getThinkModelFunction(id);
  64 + return success(IotThinkModelFunctionConvert.INSTANCE.convert(function));
  65 + }
  66 +
  67 + @GetMapping("/list-by-product-id")
  68 + @Operation(summary = "获得产品物模型")
  69 + @Parameter(name = "productId", description = "产品ID", required = true, example = "1024")
  70 + @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')")
  71 + public CommonResult<List<IotThinkModelFunctionRespVO>> getThinkModelFunctionListByProductId(@RequestParam("productId") Long productId) {
  72 + List<IotThinkModelFunctionDO> list = thinkModelFunctionService.getThinkModelFunctionListByProductId(productId);
  73 + return success(IotThinkModelFunctionConvert.INSTANCE.convertList(list));
  74 + }
  75 +
  76 + @GetMapping("/page")
  77 + @Operation(summary = "获得产品物模型分页")
  78 + @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')")
  79 + public CommonResult<PageResult<IotThinkModelFunctionRespVO>> getThinkModelFunctionPage(@Valid IotThinkModelFunctionPageReqVO pageReqVO) {
  80 + PageResult<IotThinkModelFunctionDO> pageResult = thinkModelFunctionService.getThinkModelFunctionPage(pageReqVO);
  81 + return success(BeanUtils.toBean(pageResult, IotThinkModelFunctionRespVO.class));
  82 + }
  83 +
  84 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
  2 +
  3 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArgument;
  4 +import lombok.Data;
  5 +import java.util.List;
  6 +
  7 +@Data
  8 +public class ThingModelEvent {
  9 +
  10 + /**
  11 + * 事件标识符
  12 + */
  13 + private String identifier;
  14 + /**
  15 + * 事件名称
  16 + */
  17 + private String name;
  18 + /**
  19 + * 事件描述
  20 + */
  21 + private String description;
  22 +
  23 + /**
  24 + * 事件类型
  25 + *
  26 + * "info"、"alert"、"error"
  27 + */
  28 + private String type;
  29 + private List<ThingModelArgument> outputData;
  30 + private String method;
  31 +
  32 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
  2 +
  3 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelDataType;
  4 +import lombok.Data;
  5 +
  6 +@Data
  7 +public class ThingModelProperty {
  8 +
  9 + /**
  10 + * 属性标识符
  11 + */
  12 + private String identifier;
  13 + /**
  14 + * 属性名称
  15 + */
  16 + private String name;
  17 + /**
  18 + * 属性描述
  19 + */
  20 + private String description;
  21 +
  22 + private String accessMode; // "rw"、"r"、"w"
  23 + private Boolean required;
  24 + // TODO @haohao:这个是不是 dataSpecs 和 dataSpecsList?https://help.aliyun.com/zh/iot/developer-reference/api-a99t11
  25 + private ThingModelDataType dataType;
  26 +
  27 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
  2 +
  3 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArgument;
  4 +import lombok.Data;
  5 +import java.util.List;
  6 +
  7 +@Data
  8 +public class ThingModelService {
  9 +
  10 + /**
  11 + * 服务标识符
  12 + */
  13 + private String identifier;
  14 + /**
  15 + * 服务名称
  16 + */
  17 + private String name;
  18 + /**
  19 + * 服务描述
  20 + */
  21 + private String description;
  22 +
  23 + /**
  24 + * 调用类型
  25 + *
  26 + * "sync"、"async"
  27 + */
  28 + private String callType;
  29 + private List<ThingModelArgument> inputData;
  30 + private List<ThingModelArgument> outputData;
  31 + private String method;
  32 +
  33 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArgument.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
  2 +
  3 +import lombok.Data;
  4 +
  5 +@Data
  6 +public class ThingModelArgument {
  7 +
  8 + private String identifier;
  9 + private String name;
  10 + private ThingModelDataType dataType;
  11 + /**
  12 + * 用于区分输入或输出参数,"input" 或 "output"
  13 + */
  14 + private String direction;
  15 + private String description;
  16 +
  17 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArraySpecs.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
  2 +
  3 +import lombok.Data;
  4 +
  5 +@Data
  6 +public class ThingModelArraySpecs {
  7 +
  8 + /**
  9 + * 数组长度
  10 + */
  11 + private int size;
  12 + /**
  13 + * 数组元素的类型
  14 + */
  15 + private ThingModelDataType item;
  16 +
  17 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArrayType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
  2 +
  3 +import lombok.Data;
  4 +
  5 +// TODO @haohao:这个是不是和别的类,不太统一哈
  6 +@Data
  7 +public class ThingModelArrayType extends ThingModelDataType {
  8 +
  9 + private ThingModelArraySpecs specs;
  10 +
  11 +}
  12 +
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelBoolType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
  2 +
  3 +import lombok.Data;
  4 +import lombok.EqualsAndHashCode;
  5 +
  6 +@Data
  7 +@EqualsAndHashCode(callSuper = true)
  8 +public class ThingModelBoolType extends ThingModelDataType {
  9 +
  10 + // Bool 类型一般不需要额外的 specs
  11 +
  12 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDataType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonSubTypes;
  4 +import com.fasterxml.jackson.annotation.JsonTypeInfo;
  5 +import lombok.Data;
  6 +
  7 +@Data
  8 +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true)
  9 +@JsonSubTypes({
  10 + @JsonSubTypes.Type(value = ThingModelIntType.class, name = "int"),
  11 + @JsonSubTypes.Type(value = ThingModelFloatType.class, name = "float"),
  12 + @JsonSubTypes.Type(value = ThingModelDoubleType.class, name = "double"),
  13 + @JsonSubTypes.Type(value = ThingModelTextType.class, name = "text"),
  14 + @JsonSubTypes.Type(value = ThingModelDateType.class, name = "date"),
  15 + @JsonSubTypes.Type(value = ThingModelBoolType.class, name = "bool"),
  16 + @JsonSubTypes.Type(value = ThingModelEnumType.class, name = "enum"),
  17 + @JsonSubTypes.Type(value = ThingModelStructType.class, name = "struct"),
  18 + @JsonSubTypes.Type(value = ThingModelArrayType.class, name = "array")
  19 +})
  20 +public abstract class ThingModelDataType {
  21 +
  22 + private String type;
  23 +
  24 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDateType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
  2 +
  3 +import lombok.Data;
  4 +
  5 +@Data
  6 +public class ThingModelDateType extends ThingModelDataType {
  7 +
  8 + // Date 类型一般不需要额外的 specs
  9 +
  10 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDoubleType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
  2 +
  3 +import lombok.Data;
  4 +
  5 +@Data
  6 +public class ThingModelDoubleType extends ThingModelDataType {
  7 + private ThingModelDoubleSpecs specs;
  8 +}
  9 +
  10 +@Data
  11 +class ThingModelDoubleSpecs {
  12 +
  13 + private Double min;
  14 + private Double max;
  15 + private Double step;
  16 + private String unit;
  17 +
  18 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelEnumType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.util.Map;
  6 +
  7 +@Data
  8 +public class ThingModelEnumType extends ThingModelDataType {
  9 +
  10 + /**
  11 + * 枚举值和描述的键值对
  12 + */
  13 + private Map<String, String> specs;
  14 +
  15 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelFloatType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
  2 +
  3 +import lombok.Data;
  4 +import lombok.EqualsAndHashCode;
  5 +
  6 +@Data
  7 +@EqualsAndHashCode(callSuper = true)
  8 +public class ThingModelFloatType extends ThingModelDataType {
  9 + private ThingModelFloatSpecs specs;
  10 +}
  11 +
  12 +@Data
  13 +class ThingModelFloatSpecs {
  14 +
  15 + private Float min;
  16 + private Float max;
  17 + private Float step;
  18 + private String unit;
  19 +
  20 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelIntType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
  2 +
  3 +import lombok.Data;
  4 +
  5 +@Data
  6 +public class ThingModelIntType extends ThingModelDataType {
  7 + private ThingModelIntSpecs specs;
  8 +}
  9 +
  10 +@Data
  11 +class ThingModelIntSpecs {
  12 +
  13 + private Integer min;
  14 + private Integer max;
  15 + private Integer step;
  16 + private String unit;
  17 +
  18 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructField.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
  2 +
  3 +import lombok.Data;
  4 +
  5 +@Data
  6 +public class ThingModelStructField {
  7 +
  8 + private String identifier;
  9 + private String name;
  10 + private ThingModelDataType dataType;
  11 + private String description;
  12 +
  13 +}
0 \ No newline at end of file 14 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.util.List;
  6 +
  7 +@Data
  8 +public class ThingModelStructType extends ThingModelDataType {
  9 +
  10 + private List<ThingModelStructField> specs;
  11 +
  12 +}
  13 +
  14 +
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelTextType.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType;
  2 +
  3 +import lombok.Data;
  4 +
  5 +@Data
  6 +public class ThingModelTextType extends ThingModelDataType {
  7 +
  8 + private ThingModelTextSpecs specs;
  9 +
  10 +}
  11 +
  12 +@Data
  13 +class ThingModelTextSpecs {
  14 +
  15 + /**
  16 + * 最大长度
  17 + */
  18 + private Integer length;
  19 +
  20 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  5 +import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum;
  6 +import io.swagger.v3.oas.annotations.media.Schema;
  7 +import jakarta.validation.constraints.NotNull;
  8 +import lombok.Data;
  9 +import lombok.EqualsAndHashCode;
  10 +import lombok.ToString;
  11 +
  12 +@Schema(description = "管理后台 - IoT 产品物模型分页 Request VO")
  13 +@Data
  14 +@EqualsAndHashCode(callSuper = true)
  15 +@ToString(callSuper = true)
  16 +public class IotThinkModelFunctionPageReqVO extends PageParam {
  17 +
  18 + @Schema(description = "功能标识")
  19 + private String identifier;
  20 +
  21 + @Schema(description = "功能名称", example = "张三")
  22 + private String name;
  23 +
  24 + @Schema(description = "功能类型", example = "1")
  25 + @InEnum(IotProductFunctionTypeEnum.class)
  26 + private Integer type;
  27 +
  28 + @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED)
  29 + @NotNull(message = "产品ID不能为空")
  30 + private Long productId;
  31 +
  32 +}
0 \ No newline at end of file 33 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
  2 +
  3 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
  4 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
  5 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
  6 +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
  7 +import com.alibaba.excel.annotation.ExcelProperty;
  8 +import io.swagger.v3.oas.annotations.media.Schema;
  9 +import lombok.Data;
  10 +
  11 +import java.time.LocalDateTime;
  12 +import java.util.List;
  13 +
  14 +@Schema(description = "管理后台 - IoT 产品物模型 Response VO")
  15 +@Data
  16 +@ExcelIgnoreUnannotated
  17 +public class IotThinkModelFunctionRespVO {
  18 +
  19 + @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "21816")
  20 + @ExcelProperty("产品ID")
  21 + private Long id;
  22 +
  23 + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED)
  24 + private Long productId;
  25 +
  26 + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED)
  27 + @ExcelProperty("产品标识")
  28 + private String productKey;
  29 +
  30 + @Schema(description = "功能标识", requiredMode = Schema.RequiredMode.REQUIRED)
  31 + private String identifier;
  32 +
  33 + @Schema(description = "功能名称", requiredMode = Schema.RequiredMode.REQUIRED)
  34 + private String name;
  35 +
  36 + @Schema(description = "功能描述", requiredMode = Schema.RequiredMode.REQUIRED)
  37 + private String description;
  38 +
  39 + @Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED)
  40 + private Integer type;
  41 +
  42 + @Schema(description = "属性", requiredMode = Schema.RequiredMode.REQUIRED)
  43 + private ThingModelProperty property;
  44 +
  45 + @Schema(description = "服务", requiredMode = Schema.RequiredMode.REQUIRED)
  46 + private ThingModelEvent event;
  47 +
  48 + @Schema(description = "事件", requiredMode = Schema.RequiredMode.REQUIRED)
  49 + private ThingModelService service;
  50 +
  51 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  52 + @ExcelProperty("创建时间")
  53 + private LocalDateTime createTime;
  54 +
  55 +}
0 \ No newline at end of file 56 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  4 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
  5 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
  7 +import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum;
  8 +import io.swagger.v3.oas.annotations.media.Schema;
  9 +import jakarta.validation.constraints.NotEmpty;
  10 +import jakarta.validation.constraints.NotNull;
  11 +import lombok.Data;
  12 +
  13 +@Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO")
  14 +@Data
  15 +public class IotThinkModelFunctionSaveReqVO {
  16 +
  17 + @Schema(description = "编号", example = "1")
  18 + private Long id;
  19 +
  20 + @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED)
  21 + @NotNull(message = "产品ID不能为空")
  22 + private Long productId;
  23 +
  24 + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED)
  25 + @NotEmpty(message = "产品标识不能为空")
  26 + private String productKey;
  27 +
  28 + @Schema(description = "功能标识", requiredMode = Schema.RequiredMode.REQUIRED)
  29 + @NotEmpty(message = "功能标识不能为空")
  30 + private String identifier;
  31 +
  32 + @Schema(description = "功能名称", requiredMode = Schema.RequiredMode.REQUIRED)
  33 + @NotEmpty(message = "功能名称不能为空")
  34 + private String name;
  35 +
  36 + @Schema(description = "功能描述", requiredMode = Schema.RequiredMode.REQUIRED)
  37 + private String description;
  38 +
  39 + @Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED)
  40 + @NotNull(message = "功能类型不能为空")
  41 + @InEnum(IotProductFunctionTypeEnum.class)
  42 + private Integer type;
  43 +
  44 + @Schema(description = "属性", requiredMode = Schema.RequiredMode.REQUIRED)
  45 + private ThingModelProperty property;
  46 +
  47 + @Schema(description = "服务", requiredMode = Schema.RequiredMode.REQUIRED)
  48 + private ThingModelService service;
  49 +
  50 + @Schema(description = "事件", requiredMode = Schema.RequiredMode.REQUIRED)
  51 + private ThingModelEvent event;
  52 +
  53 +}
0 \ No newline at end of file 54 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/package-info.java 0 → 100644
  1 +/**
  2 + * 提供 RESTful API 给前端:
  3 + * 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目
  4 + * 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分
  5 + */
  6 +package cn.iocoder.yudao.module.iot.controller;
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/package-info.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.convert;
0 \ No newline at end of file 2 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.convert.thinkmodelfunction;
  2 +
  3 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
  4 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
  5 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO;
  7 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
  8 +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
  9 +import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum;
  10 +import org.mapstruct.Mapper;
  11 +import org.mapstruct.Mapping;
  12 +import org.mapstruct.factory.Mappers;
  13 +
  14 +import java.util.List;
  15 +import java.util.Objects;
  16 +
  17 +@Mapper
  18 +public interface IotThinkModelFunctionConvert {
  19 +
  20 + IotThinkModelFunctionConvert INSTANCE = Mappers.getMapper(IotThinkModelFunctionConvert.class);
  21 +
  22 + // 将 SaveReqVO 转换为 DO
  23 + @Mapping(target = "property", expression = "java(convertToProperty(bean))")
  24 + @Mapping(target = "event", expression = "java(convertToEvent(bean))")
  25 + @Mapping(target = "service", expression = "java(convertToService(bean))")
  26 + IotThinkModelFunctionDO convert(IotThinkModelFunctionSaveReqVO bean);
  27 +
  28 + default ThingModelProperty convertToProperty(IotThinkModelFunctionSaveReqVO bean) {
  29 + if (Objects.equals(bean.getType(), IotProductFunctionTypeEnum.PROPERTY.getType())) {
  30 + return bean.getProperty();
  31 + }
  32 + return null;
  33 + }
  34 +
  35 + default ThingModelEvent convertToEvent(IotThinkModelFunctionSaveReqVO bean) {
  36 + if (Objects.equals(bean.getType(), IotProductFunctionTypeEnum.EVENT.getType())) {
  37 + return bean.getEvent();
  38 + }
  39 + return null;
  40 + }
  41 +
  42 + default ThingModelService convertToService(IotThinkModelFunctionSaveReqVO bean) {
  43 + if (Objects.equals(bean.getType(), IotProductFunctionTypeEnum.SERVICE.getType())) {
  44 + return bean.getService();
  45 + }
  46 + return null;
  47 + }
  48 +
  49 + // 将 DO 转换为 RespVO
  50 + @Mapping(target = "property", source = "property")
  51 + @Mapping(target = "event", source = "event")
  52 + @Mapping(target = "service", source = "service")
  53 + IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean);
  54 +
  55 + // 批量转换
  56 + List<IotThinkModelFunctionRespVO> convertList(List<IotThinkModelFunctionDO> list);
  57 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.dal.dataobject.device;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
  5 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
  6 +import com.baomidou.mybatisplus.annotation.KeySequence;
  7 +import com.baomidou.mybatisplus.annotation.TableId;
  8 +import com.baomidou.mybatisplus.annotation.TableName;
  9 +import lombok.*;
  10 +
  11 +import java.math.BigDecimal;
  12 +import java.time.LocalDateTime;
  13 +
  14 +/**
  15 + * IoT 设备 DO
  16 + *
  17 + * @author haohao
  18 + */
  19 +@TableName("iot_device")
  20 +@KeySequence("iot_device_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  21 +@Data
  22 +@EqualsAndHashCode(callSuper = true)
  23 +@ToString(callSuper = true)
  24 +@Builder
  25 +@NoArgsConstructor
  26 +@AllArgsConstructor
  27 +public class IotDeviceDO extends BaseDO {
  28 +
  29 + /**
  30 + * 设备 ID,主键,自增
  31 + */
  32 + @TableId
  33 + private Long id;
  34 + /**
  35 + * 设备唯一标识符,全局唯一,用于识别设备
  36 + */
  37 + private String deviceKey;
  38 + /**
  39 + * 设备名称,在产品内唯一,用于标识设备
  40 + */
  41 + private String deviceName;
  42 + /**
  43 + * 设备备注名称
  44 + */
  45 + private String nickname;
  46 + /**
  47 + * 设备序列号
  48 + */
  49 + private String serialNumber;
  50 +
  51 + /**
  52 + * 产品编号
  53 + * <p>
  54 + * 关联 {@link IotProductDO#getId()}
  55 + */
  56 + private Long productId;
  57 + /**
  58 + * 产品标识
  59 + * <p>
  60 + * 冗余 {@link IotProductDO#getProductKey()}
  61 + */
  62 + private String productKey;
  63 + /**
  64 + * 设备类型
  65 + * <p>
  66 + * 冗余 {@link IotProductDO#getDeviceType()}
  67 + */
  68 + private Integer deviceType;
  69 +
  70 + /**
  71 + * 设备状态
  72 + * <p>
  73 + * 枚举 {@link IotDeviceStatusEnum}
  74 + */
  75 + private Integer status;
  76 + /**
  77 + * 网关设备编号
  78 + * <p>
  79 + * 子设备需要关联的网关设备 ID
  80 + * <p>
  81 + * 关联 {@link IotDeviceDO#getId()}
  82 + */
  83 + private Long gatewayId;
  84 +
  85 + /**
  86 + * 设备状态最后更新时间
  87 + */
  88 + private LocalDateTime statusLastUpdateTime;
  89 + /**
  90 + * 最后上线时间
  91 + */
  92 + private LocalDateTime lastOnlineTime;
  93 + /**
  94 + * 最后离线时间
  95 + */
  96 + private LocalDateTime lastOfflineTime;
  97 + /**
  98 + * 设备激活时间
  99 + */
  100 + private LocalDateTime activeTime;
  101 +
  102 + /**
  103 + * 设备的 IP 地址
  104 + */
  105 + private String ip;
  106 + /**
  107 + * 设备的固件版本
  108 + */
  109 + private String firmwareVersion;
  110 +
  111 + /**
  112 + * 设备密钥,用于设备认证,需安全存储
  113 + */
  114 + private String deviceSecret;
  115 + /**
  116 + * MQTT 客户端 ID
  117 + */
  118 + private String mqttClientId;
  119 + /**
  120 + * MQTT 用户名
  121 + */
  122 + private String mqttUsername;
  123 + /**
  124 + * MQTT 密码
  125 + */
  126 + private String mqttPassword;
  127 + /**
  128 + * 认证类型(如一机一密、动态注册)
  129 + */
  130 + // TODO @haohao:是不是要枚举哈
  131 + private String authType;
  132 +
  133 + /**
  134 + * 设备位置的纬度
  135 + */
  136 + private BigDecimal latitude;
  137 + /**
  138 + * 设备位置的经度
  139 + */
  140 + private BigDecimal longitude;
  141 + /**
  142 + * 地区编码
  143 + * <p>
  144 + * 关联 Area 的 id
  145 + */
  146 + private Integer areaId;
  147 + /**
  148 + * 设备详细地址
  149 + */
  150 + private String address;
  151 +
  152 +}
0 \ No newline at end of file 153 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.dal.dataobject.product;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import com.baomidou.mybatisplus.annotation.KeySequence;
  5 +import com.baomidou.mybatisplus.annotation.TableId;
  6 +import com.baomidou.mybatisplus.annotation.TableName;
  7 +import lombok.*;
  8 +
  9 +/**
  10 + * IoT 产品 DO
  11 + *
  12 + * @author ahh
  13 + */
  14 +@TableName("iot_product")
  15 +@KeySequence("iot_product_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  16 +@Data
  17 +@EqualsAndHashCode(callSuper = true)
  18 +@ToString(callSuper = true)
  19 +@Builder
  20 +@NoArgsConstructor
  21 +@AllArgsConstructor
  22 +public class IotProductDO extends BaseDO {
  23 +
  24 + /**
  25 + * 产品ID
  26 + */
  27 + @TableId
  28 + private Long id;
  29 + /**
  30 + * 产品名称
  31 + */
  32 + private String name;
  33 + // TODO @haohao:这个字段,要不改成 identifier,和阿里云更统一些
  34 + /**
  35 + * 产品标识
  36 + */
  37 + private String productKey;
  38 + /**
  39 + * 产品所属品类编号
  40 + * <p>
  41 + * TODO 外键:后续加
  42 + */
  43 + private Long categoryId;
  44 + /**
  45 + * 产品描述
  46 + */
  47 + private String description;
  48 +
  49 + /**
  50 + * 产品状态
  51 + * <p>
  52 + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum}
  53 + */
  54 + private Integer status;
  55 + /**
  56 + * 设备类型
  57 + * <p>
  58 + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum}
  59 + */
  60 + private Integer deviceType;
  61 + /**
  62 + * 联网方式
  63 + * <p>
  64 + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotNetTypeEnum}
  65 + */
  66 + private Integer netType;
  67 +
  68 + /**
  69 + * 接入网关协议
  70 + * <p>
  71 + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotProtocolTypeEnum}
  72 + */
  73 + private Integer protocolType;
  74 + /**
  75 + * 协议编号
  76 + * <p>
  77 + * TODO 外键:后续加
  78 + */
  79 + private Long protocolId;
  80 + /**
  81 + * 数据格式
  82 + * <p>
  83 + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotDataFormatEnum}
  84 + */
  85 + private Integer dataFormat;
  86 + /**
  87 + * 数据校验级别
  88 + * <p>
  89 + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotValidateTypeEnum}
  90 + */
  91 + private Integer validateType;
  92 +
  93 +}
0 \ No newline at end of file 94 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
  5 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
  7 +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
  8 +import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum;
  9 +import com.baomidou.mybatisplus.annotation.KeySequence;
  10 +import com.baomidou.mybatisplus.annotation.TableField;
  11 +import com.baomidou.mybatisplus.annotation.TableId;
  12 +import com.baomidou.mybatisplus.annotation.TableName;
  13 +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
  14 +import lombok.AllArgsConstructor;
  15 +import lombok.Builder;
  16 +import lombok.Data;
  17 +import lombok.NoArgsConstructor;
  18 +
  19 +/**
  20 + * IoT 产品物模型功能 DO
  21 + * <p>
  22 + * 每个 {@link IotProductDO} 和 {@link IotThinkModelFunctionDO} 是“一对多”的关系,它的每个属性、事件、服务都对应一条记录
  23 + *
  24 + * @author 芋道源码
  25 + */
  26 +@TableName(value = "iot_think_model_function", autoResultMap = true)
  27 +@KeySequence("iot_think_model_function_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  28 +@Data
  29 +@Builder
  30 +@NoArgsConstructor
  31 +@AllArgsConstructor
  32 +public class IotThinkModelFunctionDO extends BaseDO {
  33 +
  34 + /**
  35 + * 物模型功能编号
  36 + */
  37 + @TableId
  38 + private Long id;
  39 +
  40 + /**
  41 + * 功能标识
  42 + */
  43 + private String identifier;
  44 + /**
  45 + * 功能名称
  46 + */
  47 + private String name;
  48 + /**
  49 + * 功能描述
  50 + */
  51 + private String description;
  52 +
  53 + /**
  54 + * 产品标识
  55 + * <p>
  56 + * 关联 {@link IotProductDO#getId()}
  57 + */
  58 + private Long productId;
  59 + /**
  60 + * 产品标识
  61 + * <p>
  62 + * 关联 {@link IotProductDO#getProductKey()}
  63 + */
  64 + private String productKey;
  65 +
  66 + /**
  67 + * 功能类型
  68 + * <p>
  69 + * 枚举 {@link IotProductFunctionTypeEnum}
  70 + */
  71 + private Integer type;
  72 +
  73 + /**
  74 + * 属性
  75 + */
  76 + @TableField(typeHandler = JacksonTypeHandler.class)
  77 + private ThingModelProperty property;
  78 +
  79 + /**
  80 + * 事件
  81 + */
  82 + @TableField(typeHandler = JacksonTypeHandler.class)
  83 + private ThingModelEvent event;
  84 +
  85 + /**
  86 + * 服务
  87 + */
  88 + @TableField(typeHandler = JacksonTypeHandler.class)
  89 + private ThingModelService service;
  90 +
  91 +}
0 \ No newline at end of file 92 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.dal.mysql.device;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO;
  7 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +/**
  11 + * IoT 设备 Mapper
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Mapper
  16 +public interface IotDeviceMapper extends BaseMapperX<IotDeviceDO> {
  17 +
  18 + default PageResult<IotDeviceDO> selectPage(IotDevicePageReqVO reqVO) {
  19 + return selectPage(reqVO, new LambdaQueryWrapperX<IotDeviceDO>()
  20 + .eqIfPresent(IotDeviceDO::getDeviceKey, reqVO.getDeviceKey())
  21 + .likeIfPresent(IotDeviceDO::getDeviceName, reqVO.getDeviceName())
  22 + .eqIfPresent(IotDeviceDO::getProductId, reqVO.getProductId())
  23 + .eqIfPresent(IotDeviceDO::getProductKey, reqVO.getProductKey())
  24 + .eqIfPresent(IotDeviceDO::getDeviceType, reqVO.getDeviceType())
  25 + .likeIfPresent(IotDeviceDO::getNickname, reqVO.getNickname())
  26 + .eqIfPresent(IotDeviceDO::getGatewayId, reqVO.getGatewayId())
  27 + .eqIfPresent(IotDeviceDO::getStatus, reqVO.getStatus())
  28 + .betweenIfPresent(IotDeviceDO::getStatusLastUpdateTime, reqVO.getStatusLastUpdateTime())
  29 + .betweenIfPresent(IotDeviceDO::getLastOnlineTime, reqVO.getLastOnlineTime())
  30 + .betweenIfPresent(IotDeviceDO::getLastOfflineTime, reqVO.getLastOfflineTime())
  31 + .betweenIfPresent(IotDeviceDO::getActiveTime, reqVO.getActiveTime())
  32 + .eqIfPresent(IotDeviceDO::getDeviceSecret, reqVO.getDeviceSecret())
  33 + .eqIfPresent(IotDeviceDO::getMqttClientId, reqVO.getMqttClientId())
  34 + .likeIfPresent(IotDeviceDO::getMqttUsername, reqVO.getMqttUsername())
  35 + .eqIfPresent(IotDeviceDO::getMqttPassword, reqVO.getMqttPassword())
  36 + .eqIfPresent(IotDeviceDO::getAuthType, reqVO.getAuthType())
  37 + .betweenIfPresent(IotDeviceDO::getCreateTime, reqVO.getCreateTime())
  38 + .orderByDesc(IotDeviceDO::getId));
  39 + }
  40 +
  41 + default IotDeviceDO selectByProductKeyAndDeviceName(String productKey, String deviceName) {
  42 + return selectOne(IotDeviceDO::getProductKey, productKey,
  43 + IotDeviceDO::getDeviceName, deviceName);
  44 + }
  45 +
  46 + default long selectCountByGatewayId(Long id) {
  47 + return selectCount(IotDeviceDO::getGatewayId, id);
  48 + }
  49 +
  50 + default Long selectCountByProductId(Long productId) {
  51 + return selectCount(IotDeviceDO::getProductId, productId);
  52 + }
  53 +}
0 \ No newline at end of file 54 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.dal.mysql.product;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductPageReqVO;
  7 +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +/**
  11 + * IoT 产品 Mapper
  12 + *
  13 + * @author ahh
  14 + */
  15 +@Mapper
  16 +public interface IotProductMapper extends BaseMapperX<IotProductDO> {
  17 +
  18 + default PageResult<IotProductDO> selectPage(IotProductPageReqVO reqVO) {
  19 + return selectPage(reqVO, new LambdaQueryWrapperX<IotProductDO>()
  20 + .likeIfPresent(IotProductDO::getName, reqVO.getName())
  21 + .likeIfPresent(IotProductDO::getProductKey, reqVO.getProductKey())
  22 + .orderByDesc(IotProductDO::getId));
  23 + }
  24 +
  25 + default IotProductDO selectByProductKey(String productKey) {
  26 + return selectOne(new LambdaQueryWrapperX<IotProductDO>().eq(IotProductDO::getProductKey, productKey));
  27 + }
  28 +
  29 +}
0 \ No newline at end of file 30 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionPageReqVO;
  7 +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +import java.util.List;
  11 +
  12 +/**
  13 + * IoT 产品物模型 Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface IotThinkModelFunctionMapper extends BaseMapperX<IotThinkModelFunctionDO> {
  19 +
  20 + default PageResult<IotThinkModelFunctionDO> selectPage(IotThinkModelFunctionPageReqVO reqVO) {
  21 + return selectPage(reqVO, new LambdaQueryWrapperX<IotThinkModelFunctionDO>()
  22 + .eqIfPresent(IotThinkModelFunctionDO::getIdentifier, reqVO.getIdentifier())
  23 + .likeIfPresent(IotThinkModelFunctionDO::getName, reqVO.getName())
  24 + .eqIfPresent(IotThinkModelFunctionDO::getType, reqVO.getType())
  25 + .eqIfPresent(IotThinkModelFunctionDO::getProductId, reqVO.getProductId())
  26 + .notIn(IotThinkModelFunctionDO::getIdentifier, "get", "set", "post")
  27 + .orderByDesc(IotThinkModelFunctionDO::getId));
  28 + }
  29 +
  30 + default IotThinkModelFunctionDO selectByProductIdAndIdentifier(Long productId, String identifier) {
  31 + return selectOne(IotThinkModelFunctionDO::getProductId, productId,
  32 + IotThinkModelFunctionDO::getIdentifier, identifier);
  33 + }
  34 +
  35 + default List<IotThinkModelFunctionDO> selectListByProductId(Long productId) {
  36 + return selectList(IotThinkModelFunctionDO::getProductId, productId);
  37 + }
  38 +
  39 + default List<IotThinkModelFunctionDO> selectListByProductIdAndType(Long productId, Integer type) {
  40 + return selectList(IotThinkModelFunctionDO::getProductId, productId,
  41 + IotThinkModelFunctionDO::getType, type);
  42 + }
  43 +
  44 + default List<IotThinkModelFunctionDO> selectListByProductIdAndIdentifiersAndTypes(Long productId,
  45 + List<String> identifiers,
  46 + List<Integer> types){
  47 + return selectList(new LambdaQueryWrapperX<IotThinkModelFunctionDO>()
  48 + .eq(IotThinkModelFunctionDO::getProductId, productId)
  49 + .in(IotThinkModelFunctionDO::getIdentifier, identifiers)
  50 + .in(IotThinkModelFunctionDO::getType, types));
  51 + }
  52 +
  53 + default IotThinkModelFunctionDO selectByProductIdAndName(Long productId, String name) {
  54 + return selectOne(IotThinkModelFunctionDO::getProductId, productId,
  55 + IotThinkModelFunctionDO::getName, name);
  56 + }
  57 +
  58 +}
0 \ No newline at end of file 59 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/callback/EmqxCallback.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.emq.callback;
  2 +
  3 +import cn.iocoder.yudao.module.iot.emq.client.EmqxClient;
  4 +import cn.iocoder.yudao.module.iot.emq.service.EmqxService;
  5 +import jakarta.annotation.Resource;
  6 +import lombok.extern.slf4j.Slf4j;
  7 +import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
  8 +import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
  9 +import org.eclipse.paho.client.mqttv3.MqttMessage;
  10 +import org.springframework.context.annotation.Lazy;
  11 +import org.springframework.stereotype.Component;
  12 +
  13 +// TODO @芋艿:详细再瞅瞅
  14 +/**
  15 + * 用于处理MQTT连接的回调,如连接断开、消息到达、消息发布完成、连接完成等事件。
  16 + *
  17 + * @author ahh
  18 + */
  19 +@Slf4j
  20 +@Component
  21 +public class EmqxCallback implements MqttCallbackExtended {
  22 +
  23 + @Lazy
  24 + @Resource
  25 + private EmqxService emqxService;
  26 +
  27 + @Lazy
  28 + @Resource
  29 + private EmqxClient emqxClient;
  30 +
  31 + @Override
  32 + public void connectionLost(Throwable throwable) {
  33 + log.info("MQTT 连接断开", throwable);
  34 + }
  35 +
  36 + @Override
  37 + public void messageArrived(String topic, MqttMessage mqttMessage) {
  38 + emqxService.subscribeCallback(topic, mqttMessage);
  39 + }
  40 +
  41 + @Override
  42 + public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
  43 + log.info("消息发送成功: {}", iMqttDeliveryToken.getMessageId());
  44 + }
  45 +
  46 + @Override
  47 + public void connectComplete(boolean reconnect, String serverURI) {
  48 + log.info("MQTT 已连接到服务器: {}", serverURI);
  49 + emqxService.subscribe(emqxClient.getMqttClient());
  50 + }
  51 +}
  52 +
  53 +
  54 +
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/client/EmqxClient.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.emq.client;
  2 +
  3 +import cn.iocoder.yudao.module.iot.emq.callback.EmqxCallback;
  4 +import cn.iocoder.yudao.module.iot.emq.config.MqttConfig;
  5 +import jakarta.annotation.Resource;
  6 +import lombok.Data;
  7 +import lombok.extern.slf4j.Slf4j;
  8 +import org.eclipse.paho.client.mqttv3.MqttClient;
  9 +import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
  10 +import org.eclipse.paho.client.mqttv3.MqttException;
  11 +import org.eclipse.paho.client.mqttv3.MqttMessage;
  12 +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
  13 +import org.springframework.stereotype.Component;
  14 +
  15 +/**
  16 + * MQTT客户端类,负责建立与MQTT服务器的连接,提供发布消息和订阅主题的功能
  17 + *
  18 + * @author ahh
  19 + */
  20 +@Slf4j
  21 +@Data
  22 +@Component
  23 +public class EmqxClient {
  24 +
  25 + @Resource
  26 + private EmqxCallback emqxCallback;
  27 + @Resource
  28 + private MqttConfig mqttConfig;
  29 +
  30 + private MqttClient mqttClient;
  31 +
  32 + public void connect() {
  33 + if (mqttClient == null) {
  34 + createMqttClient();
  35 + }
  36 + try {
  37 + mqttClient.connect(createMqttOptions());
  38 + log.info("MQTT客户端连接成功");
  39 + } catch (MqttException e) {
  40 + log.error("MQTT客户端连接失败", e);
  41 + }
  42 + }
  43 +
  44 + private void createMqttClient() {
  45 + try {
  46 + mqttClient = new MqttClient(mqttConfig.getHostUrl(), "yudao" + mqttConfig.getClientId(), new MemoryPersistence());
  47 + mqttClient.setCallback(emqxCallback);
  48 + } catch (MqttException e) {
  49 + log.error("创建MQTT客户端失败", e);
  50 + }
  51 + }
  52 +
  53 + private MqttConnectOptions createMqttOptions() {
  54 + MqttConnectOptions options = new MqttConnectOptions();
  55 + options.setUserName(mqttConfig.getUsername());
  56 + options.setPassword(mqttConfig.getPassword().toCharArray());
  57 + options.setConnectionTimeout(mqttConfig.getTimeout());
  58 + options.setKeepAliveInterval(mqttConfig.getKeepalive());
  59 + options.setCleanSession(mqttConfig.isClearSession());
  60 + return options;
  61 + }
  62 +
  63 + public void publish(String topic, String message) {
  64 + try {
  65 + if (mqttClient == null || !mqttClient.isConnected()) {
  66 + connect();
  67 + }
  68 + mqttClient.publish(topic, new MqttMessage(message.getBytes()));
  69 + log.info("消息已发布到主题: {}", topic);
  70 + } catch (MqttException e) {
  71 + log.error("消息发布失败", e);
  72 + }
  73 + }
  74 +
  75 + public void subscribe(String topic) {
  76 + try {
  77 + if (mqttClient == null || !mqttClient.isConnected()) {
  78 + connect();
  79 + }
  80 + mqttClient.subscribe(topic);
  81 + log.info("订阅了主题: {}", topic);
  82 + } catch (MqttException e) {
  83 + log.error("订阅主题失败", e);
  84 + }
  85 + }
  86 +}
0 \ No newline at end of file 87 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/config/MqttConfig.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.emq.config;
  2 +
  3 +import lombok.Data;
  4 +import org.springframework.boot.context.properties.ConfigurationProperties;
  5 +import org.springframework.stereotype.Component;
  6 +
  7 +// TODO @芋艿:详细再瞅瞅
  8 +
  9 +/**
  10 + * 配置类,用于读取MQTT连接的配置信息,如用户名、密码、连接地址等
  11 + *
  12 + * @author ahh
  13 + */
  14 +@Data
  15 +@Component
  16 +@ConfigurationProperties("iot.emq")
  17 +public class MqttConfig {
  18 +
  19 + /**
  20 + * 用户名
  21 + */
  22 + private String username;
  23 + /**
  24 + * 密码
  25 + */
  26 + private String password;
  27 +
  28 + /**
  29 + * 连接地址
  30 + */
  31 + private String hostUrl;
  32 +
  33 + /**
  34 + * 客户Id
  35 + */
  36 + private String clientId;
  37 +
  38 + /**
  39 + * 默认连接话题
  40 + */
  41 + private String defaultTopic;
  42 +
  43 + /**
  44 + * 超时时间
  45 + */
  46 + private int timeout;
  47 +
  48 + /**
  49 + * 保持连接数
  50 + */
  51 + private int keepalive;
  52 +
  53 + /**
  54 + * 是否清除session
  55 + */
  56 + private boolean clearSession;
  57 +
  58 + /**
  59 + * 是否共享订阅
  60 + */
  61 + private boolean isShared;
  62 +
  63 + /**
  64 + * 分组共享订阅
  65 + */
  66 + private boolean isSharedGroup;
  67 +
  68 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.emq.service;
  2 +
  3 +import org.eclipse.paho.client.mqttv3.MqttClient;
  4 +import org.eclipse.paho.client.mqttv3.MqttMessage;
  5 +
  6 +// TODO @芋艿:在瞅瞅
  7 +/**
  8 + * 用于处理MQTT消息的具体业务逻辑,如订阅回调
  9 + *
  10 + * @author ahh
  11 + */
  12 +public interface EmqxService {
  13 +
  14 + /**
  15 + * 订阅回调
  16 + *
  17 + * @param topic 主题
  18 + * @param mqttMessage 消息
  19 + */
  20 + void subscribeCallback(String topic, MqttMessage mqttMessage);
  21 +
  22 + /**
  23 + * 订阅主题
  24 + *
  25 + * @param client MQTT 客户端
  26 + */
  27 + void subscribe(MqttClient client);
  28 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.emq.service;
  2 +
  3 +import lombok.extern.slf4j.Slf4j;
  4 +import org.eclipse.paho.client.mqttv3.MqttClient;
  5 +import org.eclipse.paho.client.mqttv3.MqttMessage;
  6 +import org.springframework.stereotype.Service;
  7 +
  8 +// TODO @芋艿:在瞅瞅
  9 +
  10 +/**
  11 + * 用于处理MQTT消息的具体业务逻辑,如订阅回调
  12 + *
  13 + * @author ahh
  14 + */
  15 +@Slf4j
  16 +@Service
  17 +public class EmqxServiceImpl implements EmqxService {
  18 +
  19 + // TODO 多线程处理消息
  20 + @Override
  21 + public void subscribeCallback(String topic, MqttMessage mqttMessage) {
  22 + log.info("收到消息,主题: {}, 内容: {}", topic, new String(mqttMessage.getPayload()));
  23 + // 根据不同的主题,处理不同的业务逻辑
  24 + if (topic.contains("/property/post")) {
  25 + // 设备上报数据
  26 + }
  27 + }
  28 +
  29 + @Override
  30 + public void subscribe(MqttClient client) {
  31 + try {
  32 + // 订阅默认主题,可以根据需要修改
  33 +// client.subscribe("$share/yudao/+/+/#", 1);
  34 + log.info("订阅默认主题成功");
  35 + } catch (Exception e) {
  36 + log.error("订阅默认主题失败", e);
  37 + }
  38 + }
  39 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/start/EmqxStart.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.emq.start;
  2 +
  3 +import cn.iocoder.yudao.module.iot.emq.client.EmqxClient;
  4 +import jakarta.annotation.Resource;
  5 +import org.springframework.boot.ApplicationArguments;
  6 +import org.springframework.boot.ApplicationRunner;
  7 +import org.springframework.stereotype.Component;
  8 +
  9 +// TODO @芋艿:在瞅瞅
  10 +
  11 +/**
  12 + * 用于在应用启动时自动连接MQTT服务器
  13 + *
  14 + * @author ahh
  15 + */
  16 +@Component
  17 +public class EmqxStart implements ApplicationRunner {
  18 +
  19 + @Resource
  20 + private EmqxClient emqxClient;
  21 +
  22 + @Override
  23 + public void run(ApplicationArguments applicationArguments) {
  24 + emqxClient.connect();
  25 + }
  26 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/package-info.java 0 → 100644
  1 +/**
  2 + * 属于 iot 模块的 framework 封装
  3 + *
  4 + * @author ahh
  5 + */
  6 +package cn.iocoder.yudao.module.iot.framework;
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/web/config/IotWebConfiguration.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.framework.web.config;
  2 +
  3 +import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration;
  4 +import org.springdoc.core.models.GroupedOpenApi;
  5 +import org.springframework.context.annotation.Bean;
  6 +import org.springframework.context.annotation.Configuration;
  7 +
  8 +/**
  9 + * iot 模块的 web 组件的 Configuration
  10 + *
  11 + * @author ahh
  12 + */
  13 +@Configuration(proxyBeanMethods = false)
  14 +public class IotWebConfiguration {
  15 +
  16 + /**
  17 + * iot 模块的 API 分组
  18 + */
  19 + @Bean
  20 + public GroupedOpenApi iotGroupedOpenApi() {
  21 + return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("iot");
  22 + }
  23 +
  24 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/web/package-info.java 0 → 100644
  1 +/**
  2 + * iot 模块的 web 拓展封装
  3 + */
  4 +package cn.iocoder.yudao.module.iot.framework.web;
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.service.device;
  2 +
  3 +import cn.hutool.core.util.IdUtil;
  4 +import cn.hutool.core.util.StrUtil;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  7 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO;
  8 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO;
  9 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceStatusUpdateReqVO;
  10 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
  11 +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
  12 +import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper;
  13 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
  14 +import cn.iocoder.yudao.module.iot.service.product.IotProductService;
  15 +import jakarta.annotation.Resource;
  16 +import lombok.extern.slf4j.Slf4j;
  17 +import org.springframework.stereotype.Service;
  18 +import org.springframework.transaction.annotation.Transactional;
  19 +import org.springframework.validation.annotation.Validated;
  20 +
  21 +import java.time.LocalDateTime;
  22 +import java.util.UUID;
  23 +
  24 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  25 +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
  26 +
  27 +/**
  28 + * IoT 设备 Service 实现类
  29 + *
  30 + * @author 芋道源码
  31 + */
  32 +@Service
  33 +@Validated
  34 +@Slf4j
  35 +public class DeviceServiceImpl implements IotDeviceService {
  36 +
  37 + @Resource
  38 + private IotDeviceMapper deviceMapper;
  39 + @Resource
  40 + private IotProductService productService;
  41 +
  42 + /**
  43 + * 创建 IoT 设备
  44 + *
  45 + * @param createReqVO 创建请求 VO
  46 + * @return 设备 ID
  47 + */
  48 + @Override
  49 + @Transactional(rollbackFor = Exception.class)
  50 + public Long createDevice(IotDeviceSaveReqVO createReqVO) {
  51 + // 1.1 校验产品是否存在
  52 + IotProductDO product = productService.getProduct(createReqVO.getProductId());
  53 + if (product == null) {
  54 + throw exception(PRODUCT_NOT_EXISTS);
  55 + }
  56 + // 1.2 校验设备名称在同一产品下是否唯一
  57 + if (StrUtil.isBlank(createReqVO.getDeviceName())) {
  58 + createReqVO.setDeviceName(generateUniqueDeviceName(product.getProductKey()));
  59 + } else {
  60 + validateDeviceNameUnique(product.getProductKey(), createReqVO.getDeviceName());
  61 + }
  62 +
  63 + // 2.1 转换 VO 为 DO
  64 + IotDeviceDO device = BeanUtils.toBean(createReqVO, IotDeviceDO.class)
  65 + .setProductKey(product.getProductKey())
  66 + .setDeviceType(product.getDeviceType());
  67 + // 2.2 生成并设置必要的字段
  68 + device.setDeviceKey(generateUniqueDeviceKey());
  69 + device.setDeviceSecret(generateDeviceSecret());
  70 + device.setMqttClientId(generateMqttClientId());
  71 + device.setMqttUsername(generateMqttUsername(device.getDeviceName(), device.getProductKey()));
  72 + device.setMqttPassword(generateMqttPassword());
  73 + // 2.3 设置设备状态为未激活
  74 + device.setStatus(IotDeviceStatusEnum.INACTIVE.getStatus());
  75 + device.setStatusLastUpdateTime(LocalDateTime.now());
  76 + // 2.4 插入到数据库
  77 + deviceMapper.insert(device);
  78 + return device.getId();
  79 + }
  80 +
  81 + /**
  82 + * 校验设备名称在同一产品下是否唯一
  83 + *
  84 + * @param productKey 产品 Key
  85 + * @param deviceName 设备名称
  86 + */
  87 + private void validateDeviceNameUnique(String productKey, String deviceName) {
  88 + IotDeviceDO existingDevice = deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName);
  89 + if (existingDevice != null) {
  90 + throw exception(DEVICE_NAME_EXISTS);
  91 + }
  92 + }
  93 +
  94 + /**
  95 + * 生成唯一的 deviceKey
  96 + *
  97 + * @return 生成的 deviceKey
  98 + */
  99 + private String generateUniqueDeviceKey() {
  100 + return UUID.randomUUID().toString();
  101 + }
  102 +
  103 + /**
  104 + * 生成 deviceSecret
  105 + *
  106 + * @return 生成的 deviceSecret
  107 + */
  108 + private String generateDeviceSecret() {
  109 + return IdUtil.fastSimpleUUID();
  110 + }
  111 +
  112 + /**
  113 + * 生成 MQTT Client ID
  114 + *
  115 + * @return 生成的 MQTT Client ID
  116 + */
  117 + private String generateMqttClientId() {
  118 + return UUID.randomUUID().toString();
  119 + }
  120 +
  121 + /**
  122 + * 生成 MQTT Username
  123 + *
  124 + * @param deviceName 设备名称
  125 + * @param productKey 产品 Key
  126 + * @return 生成的 MQTT Username
  127 + */
  128 + private String generateMqttUsername(String deviceName, String productKey) {
  129 + return deviceName + "&" + productKey;
  130 + }
  131 +
  132 + /**
  133 + * 生成 MQTT Password
  134 + *
  135 + * @return 生成的 MQTT Password
  136 + */
  137 + private String generateMqttPassword() {
  138 + // TODO @haohao:【后续优化】在实际应用中,建议使用更安全的方法生成 MQTT Password,如加密或哈希
  139 + return UUID.randomUUID().toString();
  140 + }
  141 +
  142 + /**
  143 + * 生成唯一的 DeviceName
  144 + *
  145 + * @param productKey 产品标识
  146 + * @return 生成的唯一 DeviceName
  147 + */
  148 + private String generateUniqueDeviceName(String productKey) {
  149 + for (int i = 0; i < Short.MAX_VALUE; i++) {
  150 + String deviceName = IdUtil.fastSimpleUUID().substring(0, 20);
  151 + if (deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName) != null) {
  152 + return deviceName;
  153 + }
  154 + }
  155 + throw new IllegalArgumentException("生成 DeviceName 失败");
  156 + }
  157 +
  158 + @Override
  159 + @Transactional(rollbackFor = Exception.class)
  160 + public void updateDevice(IotDeviceSaveReqVO updateReqVO) {
  161 + // 1. 校验存在
  162 + validateDeviceExists(updateReqVO.getId());
  163 +
  164 + // 2. 更新到数据库
  165 + IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class)
  166 + .setDeviceName(null).setProductId(null); // 设备名称 和 产品 ID 不能修改
  167 + deviceMapper.updateById(updateObj);
  168 + }
  169 +
  170 + @Override
  171 + @Transactional(rollbackFor = Exception.class)
  172 + public void deleteDevice(Long id) {
  173 + // 1.1 校验存在
  174 + IotDeviceDO device = validateDeviceExists(id);
  175 + // 1.2 如果是网关设备,检查是否有子设备
  176 + if (device.getGatewayId() != null && deviceMapper.selectCountByGatewayId(id) > 0) {
  177 + throw exception(DEVICE_HAS_CHILDREN);
  178 + }
  179 +
  180 + // 2. 删除设备
  181 + deviceMapper.deleteById(id);
  182 + }
  183 +
  184 + /**
  185 + * 校验设备是否存在
  186 + *
  187 + * @param id 设备 ID
  188 + * @return 设备对象
  189 + */
  190 + private IotDeviceDO validateDeviceExists(Long id) {
  191 + IotDeviceDO device = deviceMapper.selectById(id);
  192 + if (device == null) {
  193 + throw exception(DEVICE_NOT_EXISTS);
  194 + }
  195 + return device;
  196 + }
  197 +
  198 + @Override
  199 + public IotDeviceDO getDevice(Long id) {
  200 + IotDeviceDO device = deviceMapper.selectById(id);
  201 + if (device == null) {
  202 + throw exception(DEVICE_NOT_EXISTS);
  203 + }
  204 + return device;
  205 + }
  206 +
  207 + @Override
  208 + public PageResult<IotDeviceDO> getDevicePage(IotDevicePageReqVO pageReqVO) {
  209 + return deviceMapper.selectPage(pageReqVO);
  210 + }
  211 +
  212 + @Override
  213 + public void updateDeviceStatus(IotDeviceStatusUpdateReqVO updateReqVO) {
  214 + // 校验存在
  215 + validateDeviceExists(updateReqVO.getId());
  216 +
  217 + // 更新状态和更新时间
  218 + IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class);
  219 + deviceMapper.updateById(updateObj);
  220 + }
  221 +
  222 + @Override
  223 + public Long getDeviceCountByProductId(Long productId) {
  224 + return deviceMapper.selectCountByProductId(productId);
  225 + }
  226 +
  227 +}
0 \ No newline at end of file 228 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.service.device;
  2 +
  3 +import jakarta.validation.*;
  4 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.*;
  5 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +
  8 +/**
  9 + * IoT 设备 Service 接口
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +public interface IotDeviceService {
  14 +
  15 + /**
  16 + * 创建设备
  17 + *
  18 + * @param createReqVO 创建信息
  19 + * @return 编号
  20 + */
  21 + Long createDevice(@Valid IotDeviceSaveReqVO createReqVO);
  22 +
  23 + /**
  24 + * 更新设备
  25 + *
  26 + * @param updateReqVO 更新信息
  27 + */
  28 + void updateDevice(@Valid IotDeviceSaveReqVO updateReqVO);
  29 +
  30 + /**
  31 + * 删除设备
  32 + *
  33 + * @param id 编号
  34 + */
  35 + void deleteDevice(Long id);
  36 +
  37 + /**
  38 + * 获得设备
  39 + *
  40 + * @param id 编号
  41 + * @return IoT 设备
  42 + */
  43 + IotDeviceDO getDevice(Long id);
  44 +
  45 + /**
  46 + * 获得设备分页
  47 + *
  48 + * @param pageReqVO 分页查询
  49 + * @return IoT 设备分页
  50 + */
  51 + PageResult<IotDeviceDO> getDevicePage(IotDevicePageReqVO pageReqVO);
  52 +
  53 + /**
  54 + * 更新设备状态
  55 + *
  56 + * @param updateReqVO 更新信息
  57 + */
  58 + void updateDeviceStatus(IotDeviceStatusUpdateReqVO updateReqVO);
  59 +
  60 + /**
  61 + * 获得设备数量
  62 + *
  63 + * @param productId 产品编号
  64 + * @return 设备数量
  65 + */
  66 + Long getDeviceCountByProductId(Long productId);
  67 +}
0 \ No newline at end of file 68 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.service.product;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductPageReqVO;
  5 +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSaveReqVO;
  6 +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
  7 +import jakarta.validation.Valid;
  8 +
  9 +import java.util.List;
  10 +
  11 +/**
  12 + * IoT 产品 Service 接口
  13 + *
  14 + * @author ahh
  15 + */
  16 +public interface IotProductService {
  17 +
  18 + /**
  19 + * 创建产品
  20 + *
  21 + * @param createReqVO 创建信息
  22 + * @return 编号
  23 + */
  24 + Long createProduct(@Valid IotProductSaveReqVO createReqVO);
  25 +
  26 + /**
  27 + * 更新产品
  28 + *
  29 + * @param updateReqVO 更新信息
  30 + */
  31 + void updateProduct(@Valid IotProductSaveReqVO updateReqVO);
  32 +
  33 + /**
  34 + * 删除产品
  35 + *
  36 + * @param id 编号
  37 + */
  38 + void deleteProduct(Long id);
  39 +
  40 + /**
  41 + * 获得产品
  42 + *
  43 + * @param id 编号
  44 + * @return 产品
  45 + */
  46 + IotProductDO getProduct(Long id);
  47 +
  48 + /**
  49 + * 获得产品分页
  50 + *
  51 + * @param pageReqVO 分页查询
  52 + * @return 产品分页
  53 + */
  54 + PageResult<IotProductDO> getProductPage(IotProductPageReqVO pageReqVO);
  55 +
  56 + /**
  57 + * 更新产品状态
  58 + *
  59 + * @param id 编号
  60 + * @param status 状态
  61 + */
  62 + void updateProductStatus(Long id, Integer status);
  63 +
  64 + /**
  65 + * 获得所有产品
  66 + *
  67 + * @return 产品列表
  68 + */
  69 + List<IotProductDO> getProductList();
  70 +
  71 +}
0 \ No newline at end of file 72 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.service.product;
  2 +
  3 +import cn.hutool.core.util.StrUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductPageReqVO;
  7 +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSaveReqVO;
  8 +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
  9 +import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper;
  10 +import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum;
  11 +import jakarta.annotation.Resource;
  12 +import org.springframework.stereotype.Service;
  13 +import org.springframework.validation.annotation.Validated;
  14 +
  15 +import java.util.List;
  16 +import java.util.Objects;
  17 +import java.util.UUID;
  18 +
  19 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  20 +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
  21 +
  22 +/**
  23 + * IoT 产品 Service 实现类
  24 + *
  25 + * @author ahh
  26 + */
  27 +@Service
  28 +@Validated
  29 +public class IotProductServiceImpl implements IotProductService {
  30 +
  31 + @Resource
  32 + private IotProductMapper productMapper;
  33 +
  34 + @Override
  35 + public Long createProduct(IotProductSaveReqVO createReqVO) {
  36 + // 1. 生成 ProductKey
  37 + createProductKey(createReqVO);
  38 + // 2. 插入
  39 + IotProductDO product = BeanUtils.toBean(createReqVO, IotProductDO.class);
  40 + productMapper.insert(product);
  41 + return product.getId();
  42 + }
  43 +
  44 + /**
  45 + * 创建 ProductKey
  46 + *
  47 + * @param createReqVO 创建信息
  48 + */
  49 + private void createProductKey(IotProductSaveReqVO createReqVO) {
  50 + String productKey = createReqVO.getProductKey();
  51 + // 1. productKey为空,生成随机的 11 位字符串
  52 + if (StrUtil.isEmpty(productKey)) {
  53 + productKey = UUID.randomUUID().toString().replace("-", "").substring(0, 11);
  54 + }
  55 + // 2. 校验唯一性
  56 + if (productMapper.selectByProductKey(productKey) != null) {
  57 + throw exception(PRODUCT_IDENTIFICATION_EXISTS);
  58 + }
  59 + createReqVO.setProductKey(productKey);
  60 + }
  61 +
  62 + @Override
  63 + public void updateProduct(IotProductSaveReqVO updateReqVO) {
  64 + updateReqVO.setProductKey(null); // 不更新产品标识
  65 + // 1.1 校验存在
  66 + IotProductDO iotProductDO = validateProductExists(updateReqVO.getId());
  67 + // 1.2 发布状态不可更新
  68 + validateProductStatus(iotProductDO);
  69 + // 2. 更新
  70 + IotProductDO updateObj = BeanUtils.toBean(updateReqVO, IotProductDO.class);
  71 + productMapper.updateById(updateObj);
  72 + }
  73 +
  74 + @Override
  75 + public void deleteProduct(Long id) {
  76 + // 1.1 校验存在
  77 + IotProductDO iotProductDO = validateProductExists(id);
  78 + // 1.2 发布状态不可删除
  79 + validateProductStatus(iotProductDO);
  80 + // 2. 删除
  81 + productMapper.deleteById(id);
  82 + }
  83 +
  84 + private IotProductDO validateProductExists(Long id) {
  85 + IotProductDO iotProductDO = productMapper.selectById(id);
  86 + if (iotProductDO == null) {
  87 + throw exception(PRODUCT_NOT_EXISTS);
  88 + }
  89 + return iotProductDO;
  90 + }
  91 +
  92 + private void validateProductStatus(IotProductDO iotProductDO) {
  93 + if (Objects.equals(iotProductDO.getStatus(), IotProductStatusEnum.PUBLISHED.getType())) {
  94 + throw exception(PRODUCT_STATUS_NOT_DELETE);
  95 + }
  96 + }
  97 +
  98 + @Override
  99 + public IotProductDO getProduct(Long id) {
  100 + return productMapper.selectById(id);
  101 + }
  102 +
  103 + @Override
  104 + public PageResult<IotProductDO> getProductPage(IotProductPageReqVO pageReqVO) {
  105 + return productMapper.selectPage(pageReqVO);
  106 + }
  107 +
  108 + @Override
  109 + public void updateProductStatus(Long id, Integer status) {
  110 + // 1. 校验存在
  111 + validateProductExists(id);
  112 + // 2. 更新
  113 + IotProductDO updateObj = IotProductDO.builder().id(id).status(status).build();
  114 + productMapper.updateById(updateObj);
  115 + }
  116 +
  117 + @Override
  118 + public List<IotProductDO> getProductList() {
  119 + return productMapper.selectList();
  120 + }
  121 +
  122 +}
0 \ No newline at end of file 123 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.service.thinkmodelfunction;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionPageReqVO;
  5 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
  6 +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
  7 +import jakarta.validation.Valid;
  8 +
  9 +import java.util.List;
  10 +
  11 +/**
  12 + * IoT 产品物模型 Service 接口
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +public interface IotThinkModelFunctionService {
  17 +
  18 + /**
  19 + * 创建产品物模型
  20 + *
  21 + * @param createReqVO 创建信息
  22 + * @return 编号
  23 + */
  24 + Long createThinkModelFunction(@Valid IotThinkModelFunctionSaveReqVO createReqVO);
  25 +
  26 +
  27 + /**
  28 + * 更新产品物模型
  29 + *
  30 + * @param updateReqVO 更新信息
  31 + */
  32 + void updateThinkModelFunction(@Valid IotThinkModelFunctionSaveReqVO updateReqVO);
  33 +
  34 + /**
  35 + * 删除产品物模型
  36 + *
  37 + * @param id 编号
  38 + */
  39 + void deleteThinkModelFunction(Long id);
  40 +
  41 + /**
  42 + * 获得产品物模型
  43 + *
  44 + * @param id 编号
  45 + * @return 产品物模型
  46 + */
  47 + IotThinkModelFunctionDO getThinkModelFunction(Long id);
  48 +
  49 + /**
  50 + * 获得产品物模型列表
  51 + *
  52 + * @param productId 产品编号
  53 + * @return 产品物模型列表
  54 + */
  55 + List<IotThinkModelFunctionDO> getThinkModelFunctionListByProductId(Long productId);
  56 +
  57 + /**
  58 + * 获得产品物模型分页
  59 + *
  60 + * @param pageReqVO 分页查询
  61 + * @return 产品物模型分页
  62 + */
  63 + PageResult<IotThinkModelFunctionDO> getThinkModelFunctionPage(IotThinkModelFunctionPageReqVO pageReqVO);
  64 +
  65 +}
0 \ No newline at end of file 66 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.service.thinkmodelfunction;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.ObjectUtil;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  7 +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
  8 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
  9 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
  10 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
  11 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArgument;
  12 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArraySpecs;
  13 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArrayType;
  14 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelTextType;
  15 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionPageReqVO;
  16 +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
  17 +import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert;
  18 +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
  19 +import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper;
  20 +import cn.iocoder.yudao.module.iot.enums.product.IotAccessModeEnum;
  21 +import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum;
  22 +import jakarta.annotation.Resource;
  23 +import lombok.extern.slf4j.Slf4j;
  24 +import org.springframework.stereotype.Service;
  25 +import org.springframework.transaction.annotation.Transactional;
  26 +import org.springframework.validation.annotation.Validated;
  27 +
  28 +import java.util.*;
  29 +import java.util.stream.Collectors;
  30 +
  31 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  32 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
  33 +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
  34 +
  35 +/**
  36 + * IoT 产品物模型 Service 实现类
  37 + *
  38 + * @author 芋道源码
  39 + */
  40 +@Service
  41 +@Validated
  42 +@Slf4j
  43 +public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionService {
  44 +
  45 + @Resource
  46 + private IotThinkModelFunctionMapper thinkModelFunctionMapper;
  47 +
  48 + @Override
  49 + @Transactional(rollbackFor = Exception.class)
  50 + public Long createThinkModelFunction(IotThinkModelFunctionSaveReqVO createReqVO) {
  51 + // 1. 校验功能标识符在同一产品下是否唯一
  52 + validateIdentifierUnique(createReqVO.getProductId(), createReqVO.getIdentifier());
  53 +
  54 + // 2. 功能名称在同一产品下是否唯一
  55 + validateNameUnique(createReqVO.getProductId(), createReqVO.getName());
  56 +
  57 + // 3. 系统保留字段,不能用于标识符定义
  58 + validateNotDefaultEventAndService(createReqVO.getIdentifier());
  59 +
  60 + // 3. 插入数据库
  61 + IotThinkModelFunctionDO function = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO);
  62 + thinkModelFunctionMapper.insert(function);
  63 +
  64 + // 4. 如果创建的是属性,需要更新默认的事件和服务
  65 + if (Objects.equals(createReqVO.getType(), IotProductFunctionTypeEnum.PROPERTY.getType())) {
  66 + createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey());
  67 + }
  68 + return function.getId();
  69 + }
  70 +
  71 + private void validateNotDefaultEventAndService(String identifier) {
  72 + // set, get, post, property, event, time, value 是系统保留字段,不能用于标识符定义
  73 + if (CollUtil.containsAny(Arrays.asList("set", "get", "post", "property", "event", "time", "value"), Collections.singletonList(identifier))) {
  74 + throw exception(THINK_MODEL_FUNCTION_IDENTIFIER_INVALID);
  75 + }
  76 +// if (CollUtil.containsAny(Arrays.asList("post", "set", "get"), identifier)) {
  77 +// throw exception(THINK_MODEL_FUNCTION_IDENTIFIER_INVALID);
  78 +// }
  79 + }
  80 +
  81 + private void validateNameUnique(Long productId, String name) {
  82 + IotThinkModelFunctionDO function = thinkModelFunctionMapper.selectByProductIdAndName(productId, name);
  83 + if (function != null) {
  84 + throw exception(THINK_MODEL_FUNCTION_NAME_EXISTS);
  85 + }
  86 + }
  87 +
  88 + private void validateIdentifierUnique(Long productId, String identifier) {
  89 + IotThinkModelFunctionDO function = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier);
  90 + if (function != null) {
  91 + throw exception(THINK_MODEL_FUNCTION_IDENTIFIER_EXISTS);
  92 + }
  93 + }
  94 +
  95 + @Override
  96 + @Transactional(rollbackFor = Exception.class)
  97 + public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) {
  98 + // 1. 校验功能是否存在
  99 + validateThinkModelFunctionExists(updateReqVO.getId());
  100 +
  101 + // 2. 校验功能标识符是否唯一
  102 + validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier());
  103 +
  104 + // 3. 更新数据库
  105 + IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO);
  106 + thinkModelFunctionMapper.updateById(thinkModelFunction);
  107 +
  108 + // 4. 如果更新的是属性,需要更新默认的事件和服务
  109 + if (Objects.equals(updateReqVO.getType(), IotProductFunctionTypeEnum.PROPERTY.getType())) {
  110 + createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey());
  111 + }
  112 + }
  113 +
  114 + private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) {
  115 + IotThinkModelFunctionDO function = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier);
  116 + if (function != null && ObjectUtil.notEqual(function.getId(), id)) {
  117 + throw exception(THINK_MODEL_FUNCTION_IDENTIFIER_EXISTS);
  118 + }
  119 + }
  120 +
  121 + @Override
  122 + @Transactional(rollbackFor = Exception.class)
  123 + public void deleteThinkModelFunction(Long id) {
  124 + // 1. 校验功能是否存在
  125 + IotThinkModelFunctionDO functionDO = thinkModelFunctionMapper.selectById(id);
  126 + if (functionDO == null) {
  127 + throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS);
  128 + }
  129 +
  130 + // 2. 删除功能
  131 + thinkModelFunctionMapper.deleteById(id);
  132 +
  133 + // 3. 如果删除的是属性,需要更新默认的事件和服务
  134 + if (Objects.equals(functionDO.getType(), IotProductFunctionTypeEnum.PROPERTY.getType())) {
  135 + createDefaultEventsAndServices(functionDO.getProductId(), functionDO.getProductKey());
  136 + }
  137 + }
  138 +
  139 + /**
  140 + * 校验功能是否存在
  141 + *
  142 + * @param id 功能编号
  143 + */
  144 + private void validateThinkModelFunctionExists(Long id) {
  145 + if (thinkModelFunctionMapper.selectById(id) == null) {
  146 + throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS);
  147 + }
  148 + }
  149 +
  150 + @Override
  151 + public IotThinkModelFunctionDO getThinkModelFunction(Long id) {
  152 + return thinkModelFunctionMapper.selectById(id);
  153 + }
  154 +
  155 + @Override
  156 + public List<IotThinkModelFunctionDO> getThinkModelFunctionListByProductId(Long productId) {
  157 + return thinkModelFunctionMapper.selectListByProductId(productId);
  158 + }
  159 +
  160 + @Override
  161 + public PageResult<IotThinkModelFunctionDO> getThinkModelFunctionPage(IotThinkModelFunctionPageReqVO pageReqVO) {
  162 + return thinkModelFunctionMapper.selectPage(pageReqVO);
  163 + }
  164 +
  165 + /**
  166 + * 创建默认的事件和服务
  167 + */
  168 + public void createDefaultEventsAndServices(Long productId, String productKey) {
  169 + // 1. 获取当前属性列表
  170 + List<IotThinkModelFunctionDO> propertyList = thinkModelFunctionMapper
  171 + .selectListByProductIdAndType(productId, IotProductFunctionTypeEnum.PROPERTY.getType());
  172 +
  173 + // 2. 生成新的事件和服务列表
  174 + List<IotThinkModelFunctionDO> newFunctionList = new ArrayList<>();
  175 + // 生成属性上报事件
  176 + ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList);
  177 + if (propertyPostEvent != null) {
  178 + IotThinkModelFunctionDO eventFunction = buildEventFunctionDO(productId, productKey, propertyPostEvent);
  179 + newFunctionList.add(eventFunction);
  180 + }
  181 + // 生成属性设置服务
  182 + ThingModelService propertySetService = generatePropertySetService(propertyList);
  183 + if (propertySetService != null) {
  184 + IotThinkModelFunctionDO setServiceFunction = buildServiceFunctionDO(productId, productKey, propertySetService);
  185 + newFunctionList.add(setServiceFunction);
  186 + }
  187 + // 生成属性获取服务
  188 + ThingModelService propertyGetService = generatePropertyGetService(propertyList);
  189 + if (propertyGetService != null) {
  190 + IotThinkModelFunctionDO getServiceFunction = buildServiceFunctionDO(productId, productKey, propertyGetService);
  191 + newFunctionList.add(getServiceFunction);
  192 + }
  193 +
  194 + // 3. 获取数据库中的默认的旧事件和服务列表
  195 + List<IotThinkModelFunctionDO> oldFunctionList = thinkModelFunctionMapper.selectListByProductIdAndIdentifiersAndTypes(
  196 + productId,
  197 + Arrays.asList("post", "set", "get"),
  198 + Arrays.asList(IotProductFunctionTypeEnum.EVENT.getType(), IotProductFunctionTypeEnum.SERVICE.getType())
  199 + );
  200 +
  201 + // 3.1 使用 diffList 方法比较新旧列表
  202 + List<List<IotThinkModelFunctionDO>> diffResult = diffList(oldFunctionList, newFunctionList,
  203 + // 继续使用 identifier 和 type 进行比较:这样可以准确地匹配对应的功能对象。
  204 + (oldFunc, newFunc) -> Objects.equals(oldFunc.getIdentifier(), newFunc.getIdentifier())
  205 + && Objects.equals(oldFunc.getType(), newFunc.getType()));
  206 + List<IotThinkModelFunctionDO> createList = diffResult.get(0); // 需要新增的
  207 + List<IotThinkModelFunctionDO> updateList = diffResult.get(1); // 需要更新的
  208 + List<IotThinkModelFunctionDO> deleteList = diffResult.get(2); // 需要删除的
  209 +
  210 + // 3.2 批量执行数据库操作
  211 + // 新增数据库中的新事件和服务列表
  212 + if (CollUtil.isNotEmpty(createList)) {
  213 + thinkModelFunctionMapper.insertBatch(createList);
  214 + }
  215 + // 更新数据库中的事件和服务列表
  216 + if (CollUtil.isNotEmpty(updateList)) {
  217 + // 首先,为每个需要更新的对象设置其对应的 ID
  218 + updateList.forEach(updateFunc -> {
  219 + IotThinkModelFunctionDO oldFunc = findFunctionByIdentifierAndType(
  220 + oldFunctionList, updateFunc.getIdentifier(), updateFunc.getType());
  221 + if (oldFunc != null) {
  222 + updateFunc.setId(oldFunc.getId());
  223 + }
  224 + });
  225 + // 过滤掉没有设置 ID 的对象
  226 + List<IotThinkModelFunctionDO> validUpdateList = updateList.stream()
  227 + .filter(func -> func.getId() != null)
  228 + .collect(Collectors.toList());
  229 + // 执行批量更新
  230 + if (CollUtil.isNotEmpty(validUpdateList)) {
  231 + thinkModelFunctionMapper.updateBatch(validUpdateList);
  232 + }
  233 + }
  234 +
  235 + // 删除数据库中的旧事件和服务列表
  236 + if (CollUtil.isNotEmpty(deleteList)) {
  237 + Set<Long> idsToDelete = CollectionUtils.convertSet(deleteList, IotThinkModelFunctionDO::getId);
  238 + thinkModelFunctionMapper.deleteByIds(idsToDelete);
  239 + }
  240 + }
  241 +
  242 + /**
  243 + * 根据标识符和类型查找功能对象
  244 + */
  245 + private IotThinkModelFunctionDO findFunctionByIdentifierAndType(List<IotThinkModelFunctionDO> functionList,
  246 + String identifier, Integer type) {
  247 + return CollUtil.findOne(functionList, func ->
  248 + Objects.equals(func.getIdentifier(), identifier) && Objects.equals(func.getType(), type));
  249 + }
  250 +
  251 + /**
  252 + * 构建事件功能对象
  253 + */
  254 + private IotThinkModelFunctionDO buildEventFunctionDO(Long productId, String productKey, ThingModelEvent event) {
  255 + return new IotThinkModelFunctionDO()
  256 + .setProductId(productId)
  257 + .setProductKey(productKey)
  258 + .setIdentifier(event.getIdentifier())
  259 + .setName(event.getName())
  260 + .setDescription(event.getDescription())
  261 + .setType(IotProductFunctionTypeEnum.EVENT.getType())
  262 + .setEvent(event);
  263 + }
  264 +
  265 + /**
  266 + * 构建服务功能对象
  267 + */
  268 + private IotThinkModelFunctionDO buildServiceFunctionDO(Long productId, String productKey, ThingModelService service) {
  269 + return new IotThinkModelFunctionDO()
  270 + .setProductId(productId)
  271 + .setProductKey(productKey)
  272 + .setIdentifier(service.getIdentifier())
  273 + .setName(service.getName())
  274 + .setDescription(service.getDescription())
  275 + .setType(IotProductFunctionTypeEnum.SERVICE.getType())
  276 + .setService(service);
  277 + }
  278 +
  279 + /**
  280 + * 生成属性上报事件
  281 + */
  282 + private ThingModelEvent generatePropertyPostEvent(List<IotThinkModelFunctionDO> propertyList) {
  283 + if (CollUtil.isEmpty(propertyList)) {
  284 + return null;
  285 + }
  286 +
  287 + ThingModelEvent event = new ThingModelEvent()
  288 + .setIdentifier("post")
  289 + .setName("属性上报")
  290 + .setType("info")
  291 + .setDescription("属性上报事件")
  292 + .setMethod("thing.event.property.post");
  293 +
  294 + // 将属性列表转换为事件的输出参数
  295 + List<ThingModelArgument> outputData = new ArrayList<>();
  296 + for (IotThinkModelFunctionDO functionDO : propertyList) {
  297 + ThingModelProperty property = functionDO.getProperty();
  298 + ThingModelArgument arg = new ThingModelArgument()
  299 + .setIdentifier(property.getIdentifier())
  300 + .setName(property.getName())
  301 + .setDataType(property.getDataType())
  302 + .setDescription(property.getDescription())
  303 + .setDirection("output"); // 设置为输出参数
  304 + outputData.add(arg);
  305 + }
  306 + event.setOutputData(outputData);
  307 + return event;
  308 + }
  309 +
  310 + /**
  311 + * 生成属性设置服务
  312 + */
  313 + private ThingModelService generatePropertySetService(List<IotThinkModelFunctionDO> propertyList) {
  314 + if (propertyList == null || propertyList.isEmpty()) {
  315 + return null;
  316 + }
  317 +
  318 + List<ThingModelArgument> inputData = new ArrayList<>();
  319 + for (IotThinkModelFunctionDO functionDO : propertyList) {
  320 + ThingModelProperty property = functionDO.getProperty();
  321 + if (IotAccessModeEnum.WRITE.getMode().equals(property.getAccessMode()) || IotAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) {
  322 + ThingModelArgument arg = new ThingModelArgument()
  323 + .setIdentifier(property.getIdentifier())
  324 + .setName(property.getName())
  325 + .setDataType(property.getDataType())
  326 + .setDescription(property.getDescription())
  327 + .setDirection("input"); // 设置为输入参数
  328 + inputData.add(arg);
  329 + }
  330 + }
  331 + if (inputData.isEmpty()) {
  332 + // 如果没有可写属性,不生成属性设置服务
  333 + return null;
  334 + }
  335 +
  336 + // 属性设置服务一般不需要输出参数
  337 + return new ThingModelService()
  338 + .setIdentifier("set")
  339 + .setName("属性设置")
  340 + .setCallType("async")
  341 + .setDescription("属性设置服务")
  342 + .setMethod("thing.service.property.set")
  343 + .setInputData(inputData)
  344 + // 属性设置服务一般不需要输出参数
  345 + .setOutputData(new ArrayList<>());
  346 + }
  347 +
  348 + /**
  349 + * 生成属性获取服务
  350 + */
  351 + private ThingModelService generatePropertyGetService(List<IotThinkModelFunctionDO> propertyList) {
  352 + if (propertyList == null || propertyList.isEmpty()) {
  353 + return null;
  354 + }
  355 +
  356 + List<ThingModelArgument> outputData = new ArrayList<>();
  357 + for (IotThinkModelFunctionDO functionDO : propertyList) {
  358 + ThingModelProperty property = functionDO.getProperty();
  359 + if (ObjectUtils.equalsAny(property.getAccessMode(),
  360 + IotAccessModeEnum.READ.getMode(), IotAccessModeEnum.READ_WRITE.getMode())) {
  361 + ThingModelArgument arg = new ThingModelArgument()
  362 + .setIdentifier(property.getIdentifier())
  363 + .setName(property.getName())
  364 + .setDataType(property.getDataType())
  365 + .setDescription(property.getDescription())
  366 + .setDirection("output"); // 设置为输出参数
  367 + outputData.add(arg);
  368 + }
  369 + }
  370 + if (outputData.isEmpty()) {
  371 + // 如果没有可读属性,不生成属性获取服务
  372 + return null;
  373 + }
  374 +
  375 + ThingModelService service = new ThingModelService()
  376 + .setIdentifier("get")
  377 + .setName("属性获取")
  378 + .setCallType("async")
  379 + .setDescription("属性获取服务")
  380 + .setMethod("thing.service.property.get");
  381 +
  382 + // 定义输入参数:属性标识符列表
  383 + ThingModelArgument inputArg = new ThingModelArgument()
  384 + .setIdentifier("properties")
  385 + .setName("属性标识符列表")
  386 + .setDescription("需要获取的属性标识符列表")
  387 + .setDirection("input"); // 设置为输入参数
  388 +
  389 + // 创建数组类型,元素类型为文本类型(字符串)
  390 + ThingModelArrayType arrayType = new ThingModelArrayType();
  391 + arrayType.setType("array");
  392 + ThingModelArraySpecs arraySpecs = new ThingModelArraySpecs();
  393 + ThingModelTextType textType = new ThingModelTextType();
  394 + textType.setType("text");
  395 + arraySpecs.setItem(textType);
  396 + arrayType.setSpecs(arraySpecs);
  397 + inputArg.setDataType(arrayType);
  398 +
  399 + service.setInputData(Collections.singletonList(inputArg));
  400 + service.setOutputData(outputData);
  401 + return service;
  402 + }
  403 +
  404 +}
yudao-server/pom.xml
@@ -33,11 +33,11 @@ @@ -33,11 +33,11 @@
33 </dependency> 33 </dependency>
34 34
35 <!-- 会员中心。默认注释,保证编译速度 --> 35 <!-- 会员中心。默认注释,保证编译速度 -->
36 - <dependency>  
37 - <groupId>cn.iocoder.boot</groupId>  
38 - <artifactId>yudao-module-member-biz</artifactId>  
39 - <version>${revision}</version>  
40 - </dependency> 36 +<!-- <dependency>-->
  37 +<!-- <groupId>cn.iocoder.boot</groupId>-->
  38 +<!-- <artifactId>yudao-module-member-biz</artifactId>-->
  39 +<!-- <version>${revision}</version>-->
  40 +<!-- </dependency>-->
41 41
42 <!-- 数据报表。默认注释,保证编译速度 --> 42 <!-- 数据报表。默认注释,保证编译速度 -->
43 <!-- <dependency>--> 43 <!-- <dependency>-->
@@ -52,11 +52,11 @@ @@ -52,11 +52,11 @@
52 <!-- <version>${revision}</version>--> 52 <!-- <version>${revision}</version>-->
53 <!-- </dependency>--> 53 <!-- </dependency>-->
54 <!-- 支付服务。默认注释,保证编译速度 --> 54 <!-- 支付服务。默认注释,保证编译速度 -->
55 - <dependency>  
56 - <groupId>cn.iocoder.boot</groupId>  
57 - <artifactId>yudao-module-pay-biz</artifactId>  
58 - <version>${revision}</version>  
59 - </dependency> 55 +<!-- <dependency>-->
  56 +<!-- <groupId>cn.iocoder.boot</groupId>-->
  57 +<!-- <artifactId>yudao-module-pay-biz</artifactId>-->
  58 +<!-- <version>${revision}</version>-->
  59 +<!-- </dependency>-->
60 60
61 <!-- 微信公众号模块。默认注释,保证编译速度 --> 61 <!-- 微信公众号模块。默认注释,保证编译速度 -->
62 <!-- <dependency>--> 62 <!-- <dependency>-->
@@ -66,26 +66,26 @@ @@ -66,26 +66,26 @@
66 <!-- </dependency>--> 66 <!-- </dependency>-->
67 67
68 <!-- 商城相关模块。默认注释,保证编译速度--> 68 <!-- 商城相关模块。默认注释,保证编译速度-->
69 - <dependency>  
70 - <groupId>cn.iocoder.boot</groupId>  
71 - <artifactId>yudao-module-promotion-biz</artifactId>  
72 - <version>${revision}</version>  
73 - </dependency>  
74 - <dependency>  
75 - <groupId>cn.iocoder.boot</groupId>  
76 - <artifactId>yudao-module-product-biz</artifactId>  
77 - <version>${revision}</version>  
78 - </dependency>  
79 - <dependency>  
80 - <groupId>cn.iocoder.boot</groupId>  
81 - <artifactId>yudao-module-trade-biz</artifactId>  
82 - <version>${revision}</version>  
83 - </dependency>  
84 - <dependency>  
85 - <groupId>cn.iocoder.boot</groupId>  
86 - <artifactId>yudao-module-statistics-biz</artifactId>  
87 - <version>${revision}</version>  
88 - </dependency> 69 +<!-- <dependency>-->
  70 +<!-- <groupId>cn.iocoder.boot</groupId>-->
  71 +<!-- <artifactId>yudao-module-promotion-biz</artifactId>-->
  72 +<!-- <version>${revision}</version>-->
  73 +<!-- </dependency>-->
  74 +<!-- <dependency>-->
  75 +<!-- <groupId>cn.iocoder.boot</groupId>-->
  76 +<!-- <artifactId>yudao-module-product-biz</artifactId>-->
  77 +<!-- <version>${revision}</version>-->
  78 +<!-- </dependency>-->
  79 +<!-- <dependency>-->
  80 +<!-- <groupId>cn.iocoder.boot</groupId>-->
  81 +<!-- <artifactId>yudao-module-trade-biz</artifactId>-->
  82 +<!-- <version>${revision}</version>-->
  83 +<!-- </dependency>-->
  84 +<!-- <dependency>-->
  85 +<!-- <groupId>cn.iocoder.boot</groupId>-->
  86 +<!-- <artifactId>yudao-module-statistics-biz</artifactId>-->
  87 +<!-- <version>${revision}</version>-->
  88 +<!-- </dependency>-->
89 89
90 <!-- CRM 相关模块。默认注释,保证编译速度 --> 90 <!-- CRM 相关模块。默认注释,保证编译速度 -->
91 <!-- <dependency>--> 91 <!-- <dependency>-->
@@ -108,6 +108,13 @@ @@ -108,6 +108,13 @@
108 <!-- <version>${revision}</version>--> 108 <!-- <version>${revision}</version>-->
109 <!-- </dependency>--> 109 <!-- </dependency>-->
110 110
  111 + <!-- IoT 物联网相关模块。默认注释,保证编译速度 -->
  112 +<!-- <dependency>-->
  113 +<!-- <groupId>cn.iocoder.boot</groupId>-->
  114 +<!-- <artifactId>yudao-module-iot-biz</artifactId>-->
  115 +<!-- <version>${revision}</version>-->
  116 +<!-- </dependency>-->
  117 +
111 <!-- spring boot 配置所需依赖 --> 118 <!-- spring boot 配置所需依赖 -->
112 <dependency> 119 <dependency>
113 <groupId>org.springframework.boot</groupId> 120 <groupId>org.springframework.boot</groupId>
yudao-server/src/main/java/cn/iocoder/yudao/server/controller/DefaultController.java
@@ -65,4 +65,10 @@ public class DefaultController { @@ -65,4 +65,10 @@ public class DefaultController {
65 "[AI 大模型 yudao-module-ai - 已禁用][参考 https://doc.iocoder.cn/ai/build/ 开启]"); 65 "[AI 大模型 yudao-module-ai - 已禁用][参考 https://doc.iocoder.cn/ai/build/ 开启]");
66 } 66 }
67 67
  68 + @RequestMapping(value = {"/admin-api/iot/**"})
  69 + public CommonResult<Boolean> iot404() {
  70 + return CommonResult.error(NOT_IMPLEMENTED.getCode(),
  71 + "[IOT 物联网 yudao-module-iot - 已禁用][参考 https://doc.iocoder.cn/iot/build/ 开启]");
  72 + }
  73 +
68 } 74 }
yudao-server/src/main/resources/application-dev.yaml
@@ -193,4 +193,23 @@ justauth: @@ -193,4 +193,23 @@ justauth:
193 cache: 193 cache:
194 type: REDIS 194 type: REDIS
195 prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE:: 195 prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE::
196 - timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟  
197 \ No newline at end of file 196 \ No newline at end of file
  197 + timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟
  198 +
  199 +
  200 +--- #################### iot相关配置 TODO 芋艿:再瞅瞅 ####################
  201 +iot:
  202 + emq:
  203 + # 账号
  204 + username: anhaohao
  205 + # 密码
  206 + password: ahh@123456
  207 + # 主机地址
  208 + hostUrl: tcp://chaojiniu.top:1883
  209 + # 客户端Id,不能相同,采用随机数 ${random.value}
  210 + client-id: ${random.int}
  211 + # 默认主题
  212 + default-topic: test
  213 + # 保持连接
  214 + keepalive: 60
  215 + # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
  216 + clearSession: true
198 \ No newline at end of file 217 \ No newline at end of file
yudao-server/src/main/resources/application-local.yaml
@@ -45,8 +45,8 @@ spring: @@ -45,8 +45,8 @@ spring:
45 primary: master 45 primary: master
46 datasource: 46 datasource:
47 master: 47 master:
48 - url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例  
49 - # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true # MySQL Connector/J 5.X 连接的示例 48 + url: jdbc:mysql://127.0.0.1:3307/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
  49 + # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai # MySQL Connector/J 5.X 连接的示例
50 # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例 50 # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例
51 # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 51 # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
52 # url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ruoyi-vue-pro;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true;useUnicode=true;characterEncoding=utf-8 # SQLServer 连接的示例 52 # url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ruoyi-vue-pro;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true;useUnicode=true;characterEncoding=utf-8 # SQLServer 连接的示例
@@ -54,7 +54,7 @@ spring: @@ -54,7 +54,7 @@ spring:
54 # url: jdbc:kingbase8://127.0.0.1:54321/test # 人大金仓 KingbaseES 连接的示例 54 # url: jdbc:kingbase8://127.0.0.1:54321/test # 人大金仓 KingbaseES 连接的示例
55 # url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例 55 # url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例
56 username: root 56 username: root
57 - password: 123456 57 + password: ahh@123456
58 # username: sa # SQL Server 连接的示例 58 # username: sa # SQL Server 连接的示例
59 # password: Yudao@2024 # SQL Server 连接的示例 59 # password: Yudao@2024 # SQL Server 连接的示例
60 # username: SYSDBA # DM 连接的示例 60 # username: SYSDBA # DM 连接的示例
@@ -63,9 +63,9 @@ spring: @@ -63,9 +63,9 @@ spring:
63 # password: Yudao@2024 # OpenGauss 连接的示例 63 # password: Yudao@2024 # OpenGauss 连接的示例
64 slave: # 模拟从库,可根据自己需要修改 64 slave: # 模拟从库,可根据自己需要修改
65 lazy: true # 开启懒加载,保证启动速度 65 lazy: true # 开启懒加载,保证启动速度
66 - url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true 66 + url: jdbc:mysql://127.0.0.1:3307/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
67 username: root 67 username: root
68 - password: 123456 68 + password: ahh@123456
69 69
70 # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 70 # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
71 data: 71 data:
@@ -174,6 +174,7 @@ logging: @@ -174,6 +174,7 @@ logging:
174 cn.iocoder.yudao.module.statistics.dal.mysql: debug 174 cn.iocoder.yudao.module.statistics.dal.mysql: debug
175 cn.iocoder.yudao.module.crm.dal.mysql: debug 175 cn.iocoder.yudao.module.crm.dal.mysql: debug
176 cn.iocoder.yudao.module.erp.dal.mysql: debug 176 cn.iocoder.yudao.module.erp.dal.mysql: debug
  177 + cn.iocoder.yudao.module.iot.dal.mysql: debug
177 cn.iocoder.yudao.module.ai.dal.mysql: debug 178 cn.iocoder.yudao.module.ai.dal.mysql: debug
178 org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 芋艿:先禁用,Spring Boot 3.X 存在部分错误的 WARN 提示 179 org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 芋艿:先禁用,Spring Boot 3.X 存在部分错误的 WARN 提示
179 180
@@ -254,3 +255,20 @@ justauth: @@ -254,3 +255,20 @@ justauth:
254 prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE:: 255 prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE::
255 timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟 256 timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟
256 257
  258 +--- #################### iot相关配置 TODO 芋艿:再瞅瞅 ####################
  259 +iot:
  260 + emq:
  261 + # 账号
  262 + username: anhaohao
  263 + # 密码
  264 + password: ahh@123456
  265 + # 主机地址
  266 + hostUrl: tcp://chaojiniu.top:1883
  267 + # 客户端Id,不能相同,采用随机数 ${random.value}
  268 + client-id: ${random.int}
  269 + # 默认主题
  270 + default-topic: test
  271 + # 保持连接
  272 + keepalive: 60
  273 + # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
  274 + clearSession: true
257 \ No newline at end of file 275 \ No newline at end of file