From b47176c96efb681cdff9660c9a2fa101564c61f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Tue, 6 Aug 2024 22:17:29 +0800 Subject: [PATCH 01/31] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9Aiot=20?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=20=E9=9B=86=E6=88=90=20emqx=20=E6=8E=A5?= =?UTF-8?q?=E6=94=B6=20mqtt=20=E6=8E=A5=E6=94=B6=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 3 +- yudao-dependencies/pom.xml | 8 ++ .../banner/core/BannerApplicationRunner.java | 4 + .../core/handler/GlobalExceptionHandler.java | 6 + yudao-module-iot/pom.xml | 24 ++++ yudao-module-iot/yudao-module-iot-api/pom.xml | 26 ++++ .../yudao/module/iot/api/package-info.java | 4 + yudao-module-iot/yudao-module-iot-biz/pom.xml | 57 ++++++++ .../module/iot/controller/package-info.java | 6 + .../module/iot/emq/callback/EmqxCallback.java | 53 +++++++ .../module/iot/emq/client/EmqxClient.java | 86 ++++++++++++ .../module/iot/emq/config/MqttConfig.java | 66 +++++++++ .../module/iot/emq/service/EmqxService.java | 34 +++++ .../yudao/module/iot/emq/start/EmqxStart.java | 24 ++++ .../module/iot/framework/package-info.java | 6 + .../web/config/IotWebConfiguration.java | 24 ++++ .../iot/framework/web/package-info.java | 4 + yudao-server/pom.xml | 131 +++++++++--------- .../server/controller/DefaultController.java | 6 + .../src/main/resources/application-dev.yaml | 21 ++- .../src/main/resources/application-local.yaml | 25 +++- 21 files changed, 550 insertions(+), 68 deletions(-) create mode 100644 yudao-module-iot/pom.xml create mode 100644 yudao-module-iot/yudao-module-iot-api/pom.xml create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/pom.xml create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/package-info.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/callback/EmqxCallback.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/client/EmqxClient.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/config/MqttConfig.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/start/EmqxStart.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/package-info.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/web/config/IotWebConfiguration.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/web/package-info.java diff --git a/pom.xml b/pom.xml index 528769bc9..c64337f34 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,8 @@ yudao-module-system yudao-module-infra - + yudao-module-iot + diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index badfc84f9..07d144f53 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -64,6 +64,7 @@ 2.9.2 2.7.0 3.0.6 + 1.2.5 3.5.0 4.11.0 @@ -621,6 +622,13 @@ ${xercesImpl.version} + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + ${mqtt.version} + + diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java index d60473a48..c8b0dbd66 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java +++ b/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 { if (isNotPresent("cn.iocoder.yudao.module.ai.framework.web.config.AiWebConfiguration")) { System.out.println("[AI 大模型 yudao-module-ai - 已禁用][参考 https://doc.iocoder.cn/ai/build/ 开启]"); } + // IOT 物联网 + if (isNotPresent("cn.iocoder.yudao.module.iot.framework.web.config.IotWebConfiguration")) { + System.out.println("[IOT 物联网 yudao-module-iot - 已禁用][参考 https://doc.iocoder.cn/iot/build/ 开启]"); + } }); } diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java index 3b0a17fa4..39f2ff87f 100644 --- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java +++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java @@ -360,6 +360,12 @@ public class GlobalExceptionHandler { return CommonResult.error(NOT_IMPLEMENTED.getCode(), "[AI 大模型 yudao-module-ai - 表结构未导入][参考 https://doc.iocoder.cn/ai/build/ 开启]"); } + // 9. IOT 物联网 + if (message.contains("iot_")) { + log.error("[IOT 物联网 yudao-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]"); + return CommonResult.error(NOT_IMPLEMENTED.getCode(), + "[IOT 物联网 yudao-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]"); + } return null; } diff --git a/yudao-module-iot/pom.xml b/yudao-module-iot/pom.xml new file mode 100644 index 000000000..96f8d181f --- /dev/null +++ b/yudao-module-iot/pom.xml @@ -0,0 +1,24 @@ + + + + yudao + cn.iocoder.boot + ${revision} + + + yudao-module-iot-api + yudao-module-iot-biz + + 4.0.0 + + yudao-module-iot + pom + + ${project.artifactId} + + 物联网模块 + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/pom.xml b/yudao-module-iot/yudao-module-iot-api/pom.xml new file mode 100644 index 000000000..8a75b09bf --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/pom.xml @@ -0,0 +1,26 @@ + + + + yudao-module-iot + cn.iocoder.boot + ${revision} + + 4.0.0 + yudao-module-iot-api + jar + + ${project.artifactId} + + 物联网 模块 API,暴露给其它模块调用 + + + + + cn.iocoder.boot + yudao-common + + + + diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java new file mode 100644 index 000000000..65d049636 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java @@ -0,0 +1,4 @@ +/** + * iot API 包,定义暴露给其它模块的 API + */ +package cn.iocoder.yudao.module.iot.api; diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml new file mode 100644 index 000000000..4615bce9f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -0,0 +1,57 @@ + + + + yudao-module-iot + cn.iocoder.boot + ${revision} + + 4.0.0 + jar + + yudao-module-iot-biz + + ${project.artifactId} + + 物联网 模块,主要实现 产品管理、设备管理、协议管理等功能。 + + + + + cn.iocoder.boot + yudao-module-iot-api + ${revision} + + + + + cn.iocoder.boot + yudao-spring-boot-starter-web + + + + cn.iocoder.boot + yudao-spring-boot-starter-security + + + + + cn.iocoder.boot + yudao-spring-boot-starter-mybatis + + + + + cn.iocoder.boot + yudao-spring-boot-starter-test + + + + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + + + + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/package-info.java new file mode 100644 index 000000000..5d2990e1b --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/package-info.java @@ -0,0 +1,6 @@ +/** + * 提供 RESTful API 给前端: + * 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目 + * 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分 + */ +package cn.iocoder.yudao.module.iot.controller; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/callback/EmqxCallback.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/callback/EmqxCallback.java new file mode 100644 index 000000000..a34863a17 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/callback/EmqxCallback.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.iot.emq.callback; + +import cn.iocoder.yudao.module.iot.emq.client.EmqxClient; +import cn.iocoder.yudao.module.iot.emq.service.EmqxService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; +import org.eclipse.paho.client.mqttv3.MqttCallbackExtended; +import org.eclipse.paho.client.mqttv3.MqttMessage; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +/** + * 用于处理MQTT连接的回调,如连接断开、消息到达、消息发布完成、连接完成等事件。 + * + * @author ahh + */ +@Slf4j +@Component +public class EmqxCallback implements MqttCallbackExtended { + + @Lazy + @Resource + private EmqxService emqxService; + + @Lazy + @Resource + private EmqxClient emqxClient; + + @Override + public void connectionLost(Throwable throwable) { + log.info("MQTT 连接断开", throwable); + } + + @Override + public void messageArrived(String topic, MqttMessage mqttMessage) { + emqxService.subscribeCallback(topic, mqttMessage); + } + + @Override + public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { + log.info("消息发送成功: {}", iMqttDeliveryToken.getMessageId()); + } + + @Override + public void connectComplete(boolean reconnect, String serverURI) { + log.info("MQTT 已连接到服务器: {}", serverURI); + emqxService.subscribe(emqxClient.getMqttClient()); + } +} + + + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/client/EmqxClient.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/client/EmqxClient.java new file mode 100644 index 000000000..461a748d2 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/client/EmqxClient.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.iot.emq.client; + +import cn.iocoder.yudao.module.iot.emq.callback.EmqxCallback; +import cn.iocoder.yudao.module.iot.emq.config.MqttConfig; +import jakarta.annotation.Resource; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.eclipse.paho.client.mqttv3.MqttMessage; +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; +import org.springframework.stereotype.Component; + +/** + * MQTT客户端类,负责建立与MQTT服务器的连接,提供发布消息和订阅主题的功能 + * + * @author ahh + */ +@Slf4j +@Data +@Component +public class EmqxClient { + + @Resource + private EmqxCallback emqxCallback; + @Resource + private MqttConfig mqttConfig; + + private MqttClient mqttClient; + + public void connect() { + if (mqttClient == null) { + createMqttClient(); + } + try { + mqttClient.connect(createMqttOptions()); + log.info("MQTT客户端连接成功"); + } catch (MqttException e) { + log.error("MQTT客户端连接失败", e); + } + } + + private void createMqttClient() { + try { + mqttClient = new MqttClient(mqttConfig.getHostUrl(), "yudao-" + mqttConfig.getClientId(), new MemoryPersistence()); + mqttClient.setCallback(emqxCallback); + } catch (MqttException e) { + log.error("创建MQTT客户端失败", e); + } + } + + private MqttConnectOptions createMqttOptions() { + MqttConnectOptions options = new MqttConnectOptions(); + options.setUserName(mqttConfig.getUsername()); + options.setPassword(mqttConfig.getPassword().toCharArray()); + options.setConnectionTimeout(mqttConfig.getTimeout()); + options.setKeepAliveInterval(mqttConfig.getKeepalive()); + options.setCleanSession(mqttConfig.isClearSession()); + return options; + } + + public void publish(String topic, String message) { + try { + if (mqttClient == null || !mqttClient.isConnected()) { + connect(); + } + mqttClient.publish(topic, new MqttMessage(message.getBytes())); + log.info("消息已发布到主题: {}", topic); + } catch (MqttException e) { + log.error("消息发布失败", e); + } + } + + public void subscribe(String topic) { + try { + if (mqttClient == null || !mqttClient.isConnected()) { + connect(); + } + mqttClient.subscribe(topic); + log.info("订阅了主题: {}", topic); + } catch (MqttException e) { + log.error("订阅主题失败", e); + } + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/config/MqttConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/config/MqttConfig.java new file mode 100644 index 000000000..ae1557c23 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/config/MqttConfig.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.iot.emq.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 配置类,用于读取MQTT连接的配置信息,如用户名、密码、连接地址等 + * + * @author ahh + */ +@Data +@Component +@ConfigurationProperties("iot.emq") +public class MqttConfig { + + /** + * 用户名 + */ + private String username; + /** + * 密码 + */ + private String password; + + /** + * 连接地址 + */ + private String hostUrl; + + /** + * 客户Id + */ + private String clientId; + + /** + * 默认连接话题 + */ + private String defaultTopic; + + /** + * 超时时间 + */ + private int timeout; + + /** + * 保持连接数 + */ + private int keepalive; + + /** + * 是否清除session + */ + private boolean clearSession; + + /** + * 是否共享订阅 + */ + private boolean isShared; + + /** + * 分组共享订阅 + */ + private boolean isSharedGroup; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxService.java new file mode 100644 index 000000000..b323d929c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxService.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.iot.emq.service; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttMessage; +import org.springframework.stereotype.Service; + +/** + * 用于处理MQTT消息的具体业务逻辑,如订阅回调 + * + * @author ahh + */ +@Slf4j +@Service +public class EmqxService { + + public void subscribeCallback(String topic, MqttMessage mqttMessage) { + log.info("收到消息,主题: {}, 内容: {}", topic, new String(mqttMessage.getPayload())); + // 根据不同的主题,处理不同的业务逻辑 + if (topic.contains("/property/post")) { + // 设备上报数据 + } + } + + public void subscribe(MqttClient client) { + try { + // 订阅默认主题,可以根据需要修改 + client.subscribe("$share/yudao/+/+/#", 1); + log.info("订阅默认主题成功"); + } catch (Exception e) { + log.error("订阅默认主题失败", e); + } + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/start/EmqxStart.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/start/EmqxStart.java new file mode 100644 index 000000000..f954cb588 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/start/EmqxStart.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.iot.emq.start; + +import cn.iocoder.yudao.module.iot.emq.client.EmqxClient; +import jakarta.annotation.Resource; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; + +/** + * 用于在应用启动时自动连接MQTT服务器 + * + * @author ahh + */ +@Component +public class EmqxStart implements ApplicationRunner { + + @Resource + private EmqxClient emqxClient; + + @Override + public void run(ApplicationArguments applicationArguments) { + emqxClient.connect(); + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/package-info.java new file mode 100644 index 000000000..9d8ffe73d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/package-info.java @@ -0,0 +1,6 @@ +/** + * 属于 iot 模块的 framework 封装 + * + * @author 芋道源码 + */ +package cn.iocoder.yudao.module.iot.framework; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/web/config/IotWebConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/web/config/IotWebConfiguration.java new file mode 100644 index 000000000..890e60c7c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/web/config/IotWebConfiguration.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.iot.framework.web.config; + +import cn.iocoder.yudao.framework.swagger.config.YudaoSwaggerAutoConfiguration; +import org.springdoc.core.models.GroupedOpenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * iot 模块的 web 组件的 Configuration + * + * @author 芋道源码 + */ +@Configuration(proxyBeanMethods = false) +public class IotWebConfiguration { + + /** + * iot 模块的 API 分组 + */ + @Bean + public GroupedOpenApi iotGroupedOpenApi() { + return YudaoSwaggerAutoConfiguration.buildGroupedOpenApi("iot"); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/web/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/web/package-info.java new file mode 100644 index 000000000..aafcca274 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/web/package-info.java @@ -0,0 +1,4 @@ +/** + * iot 模块的 web 拓展封装 + */ +package cn.iocoder.yudao.module.iot.framework.web; diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml index 3b16fa192..6ed31f148 100644 --- a/yudao-server/pom.xml +++ b/yudao-server/pom.xml @@ -1,6 +1,6 @@ - cn.iocoder.boot @@ -33,80 +33,87 @@ - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + + + + + cn.iocoder.boot + yudao-module-iot-biz + ${revision} + diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/DefaultController.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/DefaultController.java index 3f4bae04f..2bf6e5277 100644 --- a/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/DefaultController.java +++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/controller/DefaultController.java @@ -65,4 +65,10 @@ public class DefaultController { "[AI 大模型 yudao-module-ai - 已禁用][参考 https://doc.iocoder.cn/ai/build/ 开启]"); } + @RequestMapping(value = {"/admin-api/iot/**"}) + public CommonResult iot404() { + return CommonResult.error(NOT_IMPLEMENTED.getCode(), + "[IOT 物联网 yudao-module-iot - 已禁用][参考 https://doc.iocoder.cn/iot/build/ 开启]"); + } + } diff --git a/yudao-server/src/main/resources/application-dev.yaml b/yudao-server/src/main/resources/application-dev.yaml index 46399b802..3e7f4e76a 100644 --- a/yudao-server/src/main/resources/application-dev.yaml +++ b/yudao-server/src/main/resources/application-dev.yaml @@ -193,4 +193,23 @@ justauth: cache: type: REDIS prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE:: - timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟 \ No newline at end of file + timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟 + + +--- #################### iot相关配置 #################### +iot: + emq: + # 账号 + username: anhaohao + # 密码 + password: ahh@123456 + # 主机地址 + hostUrl: tcp://chaojiniu.top:1883 + # 客户端Id,不能相同,采用随机数 ${random.value} + client-id: ${random.int} + # 默认主题 + default-topic: test + # 保持连接 + keepalive: 60 + # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息) + clearSession: true \ No newline at end of file diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index 935ca8064..20110708c 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -45,7 +45,7 @@ spring: primary: master datasource: master: - url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例 + 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 连接的示例 # 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 连接的示例 # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例 # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 @@ -54,7 +54,7 @@ spring: # url: jdbc:kingbase8://127.0.0.1:54321/test # 人大金仓 KingbaseES 连接的示例 # url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例 username: root - password: 123456 + password: ahh@123456 # username: sa # SQL Server 连接的示例 # password: Yudao@2024 # SQL Server 连接的示例 # username: SYSDBA # DM 连接的示例 @@ -63,9 +63,9 @@ spring: # password: Yudao@2024 # OpenGauss 连接的示例 slave: # 模拟从库,可根据自己需要修改 lazy: true # 开启懒加载,保证启动速度 - url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + url: jdbc:mysql://127.0.0.1:3307/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true username: root - password: 123456 + password: ahh@123456 # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: @@ -249,3 +249,20 @@ justauth: prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE:: timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟 +--- #################### iot相关配置 #################### +iot: + emq: + # 账号 + username: anhaohao + # 密码 + password: ahh@123456 + # 主机地址 + hostUrl: tcp://chaojiniu.top:1883 + # 客户端Id,不能相同,采用随机数 ${random.value} + client-id: ${random.int} + # 默认主题 + default-topic: test + # 保持连接 + keepalive: 60 + # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息) + clearSession: true \ No newline at end of file From 3f01ba7538dd7533a43f3e66ee6c66b5b48b9c50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Tue, 6 Aug 2024 22:30:08 +0800 Subject: [PATCH 02/31] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9A=E4=BC=98?= =?UTF-8?q?=E5=8C=96=20EmqxService=20=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/emq/client/EmqxClient.java | 2 +- .../module/iot/emq/service/EmqxService.java | 35 +++++++----------- .../iot/emq/service/EmqxServiceImpl.java | 37 +++++++++++++++++++ 3 files changed, 52 insertions(+), 22 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/client/EmqxClient.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/client/EmqxClient.java index 461a748d2..de24585b0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/client/EmqxClient.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/client/EmqxClient.java @@ -43,7 +43,7 @@ public class EmqxClient { private void createMqttClient() { try { - mqttClient = new MqttClient(mqttConfig.getHostUrl(), "yudao-" + mqttConfig.getClientId(), new MemoryPersistence()); + mqttClient = new MqttClient(mqttConfig.getHostUrl(), "yudao" + mqttConfig.getClientId(), new MemoryPersistence()); mqttClient.setCallback(emqxCallback); } catch (MqttException e) { log.error("创建MQTT客户端失败", e); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxService.java index b323d929c..1658dc376 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxService.java @@ -1,34 +1,27 @@ package cn.iocoder.yudao.module.iot.emq.service; -import lombok.extern.slf4j.Slf4j; import org.eclipse.paho.client.mqttv3.MqttClient; import org.eclipse.paho.client.mqttv3.MqttMessage; -import org.springframework.stereotype.Service; /** * 用于处理MQTT消息的具体业务逻辑,如订阅回调 * * @author ahh */ -@Slf4j -@Service -public class EmqxService { +public interface EmqxService { - public void subscribeCallback(String topic, MqttMessage mqttMessage) { - log.info("收到消息,主题: {}, 内容: {}", topic, new String(mqttMessage.getPayload())); - // 根据不同的主题,处理不同的业务逻辑 - if (topic.contains("/property/post")) { - // 设备上报数据 - } - } + /** + * 订阅回调 + * + * @param topic 主题 + * @param mqttMessage 消息 + */ + void subscribeCallback(String topic, MqttMessage mqttMessage); - public void subscribe(MqttClient client) { - try { - // 订阅默认主题,可以根据需要修改 - client.subscribe("$share/yudao/+/+/#", 1); - log.info("订阅默认主题成功"); - } catch (Exception e) { - log.error("订阅默认主题失败", e); - } - } + /** + * 订阅主题 + * + * @param client MQTT 客户端 + */ + void subscribe(MqttClient client); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java new file mode 100644 index 000000000..a18bb73e1 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.iot.emq.service; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.paho.client.mqttv3.MqttClient; +import org.eclipse.paho.client.mqttv3.MqttMessage; +import org.springframework.stereotype.Service; + +/** + * 用于处理MQTT消息的具体业务逻辑,如订阅回调 + * + * @author ahh + */ +@Slf4j +@Service +public class EmqxServiceImpl implements EmqxService { + + // TODO 多线程处理消息 + @Override + public void subscribeCallback(String topic, MqttMessage mqttMessage) { + log.info("收到消息,主题: {}, 内容: {}", topic, new String(mqttMessage.getPayload())); + // 根据不同的主题,处理不同的业务逻辑 + if (topic.contains("/property/post")) { + // 设备上报数据 + } + } + + @Override + public void subscribe(MqttClient client) { + try { + // 订阅默认主题,可以根据需要修改 + client.subscribe("$share/yudao/+/+/#", 1); + log.info("订阅默认主题成功"); + } catch (Exception e) { + log.error("订阅默认主题失败", e); + } + } +} From 36a828866bcc0ba57fba16316a322204b79b3b9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sat, 17 Aug 2024 19:41:42 +0800 Subject: [PATCH 03/31] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9Aiot=20?= =?UTF-8?q?=E4=BA=A7=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 4 +- .../module/iot/enums/ErrorCodeConstants.java | 15 ++ .../iot/enums/ProductDataFormatEnum.java | 37 ++++ .../iot/enums/ProductDeviceTypeConstants.java | 13 ++ .../enums/ProductProtocolTypeConstants.java | 13 ++ .../module/iot/enums/ProductStatusEnum.java | 34 ++++ yudao-module-iot/yudao-module-iot-biz/pom.xml | 6 + .../admin/product/ProductController.java | 93 +++++++++ .../admin/product/vo/ProductPageReqVO.java | 58 ++++++ .../admin/product/vo/ProductRespVO.java | 71 +++++++ .../admin/product/vo/ProductSaveReqVO.java | 54 ++++++ .../iot/dal/dataobject/product/ProductDO.java | 79 ++++++++ .../iot/dal/mysql/product/ProductMapper.java | 42 +++++ .../iot/service/product/ProductService.java | 55 ++++++ .../service/product/ProductServiceImpl.java | 95 ++++++++++ .../mapper/product/ProductMapper.xml | 12 ++ .../product/ProductServiceImplTest.java | 178 ++++++++++++++++++ yudao-server/pom.xml | 20 +- .../src/main/resources/application-local.yaml | 1 + 19 files changed, 868 insertions(+), 12 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductDataFormatEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductDeviceTypeConstants.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductProtocolTypeConstants.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductStatusEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/ProductController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductPageReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/ProductDO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/product/ProductMapper.xml create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImplTest.java diff --git a/pom.xml b/pom.xml index c64337f34..2b21cf122 100644 --- a/pom.xml +++ b/pom.xml @@ -17,12 +17,12 @@ yudao-module-infra yudao-module-iot - + yudao-module-bpm - + yudao-module-crm diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java new file mode 100644 index 000000000..6a21de7cb --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.iot.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; + +/** + * iot 错误码枚举类 + *

+ * iot 系统,使用 1-050-000-000 段 + */ +public interface ErrorCodeConstants { + + // ========== 产品相关 1-050-001-000 ============ + ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_050_001_000, "产品不存在"); + ErrorCode PRODUCT_IDENTIFICATION_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在"); +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductDataFormatEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductDataFormatEnum.java new file mode 100644 index 000000000..be3470982 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductDataFormatEnum.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.iot.enums; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 产品数据格式枚举类 + * 1. 标准数据格式(JSON)2. 透传/自定义 + */ +@AllArgsConstructor +@Getter +public enum ProductDataFormatEnum implements IntArrayValuable { + + JSON(1, "标准数据格式(JSON)"), + SCRIPT(2, "透传/自定义"); + + /** + * 类型 + */ + private final Integer type; + + /** + * 描述 + */ + private final String description; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductDataFormatEnum::getType).toArray(); + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductDeviceTypeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductDeviceTypeConstants.java new file mode 100644 index 000000000..d44a47102 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductDeviceTypeConstants.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.module.iot.enums; + +/** + * 产品设备类型常量 + */ +public interface ProductDeviceTypeConstants { + + // ========== 产品设备类型 ============ + String DEVICE = "device"; // 直连设备 + String GATEWAY = "gateway"; // 网关设备 + String GATEWAY_SUB = "gateway_sub"; // 网关子设备 + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductProtocolTypeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductProtocolTypeConstants.java new file mode 100644 index 000000000..fe033bf5d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductProtocolTypeConstants.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.module.iot.enums; + +/** + * 产品传输协议类型常量 + */ +public interface ProductProtocolTypeConstants { + + // ========== 产品传输协议类型 ============ + String MQTT = "mqtt"; // MQTT + String COAP = "coap"; // COAP + String HTTP = "http"; // HTTP + String HTTPS = "https"; // HTTPS +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductStatusEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductStatusEnum.java new file mode 100644 index 000000000..94ec21f61 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductStatusEnum.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.iot.enums; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 产品状态枚举类 + * 禁用 启用 + */ +@AllArgsConstructor +@Getter +public enum ProductStatusEnum implements IntArrayValuable { + + DISABLE(0, "禁用"), + ENABLE(1, "启用"); + + /** + * 类型 + */ + private final Integer type; + + /** + * 描述 + */ + private final String description; + + public static final int[] ARRAYS = {1, 2}; + + @Override + public int[] array() { + return ARRAYS; + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index 4615bce9f..25a97a1b1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -47,6 +47,12 @@ yudao-spring-boot-starter-test + + + cn.iocoder.boot + yudao-spring-boot-starter-excel + + org.eclipse.paho diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/ProductController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/ProductController.java new file mode 100644 index 000000000..739e13320 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/ProductController.java @@ -0,0 +1,93 @@ +package cn.iocoder.yudao.module.iot.controller.admin.product; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.ProductDO; +import cn.iocoder.yudao.module.iot.service.product.ProductService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - iot 产品") +@RestController +@RequestMapping("/iot/product") +@Validated +public class ProductController { + + @Resource + private ProductService productService; + + @PostMapping("/create") + @Operation(summary = "创建产品") + @PreAuthorize("@ss.hasPermission('iot:product:create')") + public CommonResult createProduct(@Valid @RequestBody ProductSaveReqVO createReqVO) { + return success(productService.createProduct(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新产品") + @PreAuthorize("@ss.hasPermission('iot:product:update')") + public CommonResult updateProduct(@Valid @RequestBody ProductSaveReqVO updateReqVO) { + productService.updateProduct(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除产品") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:product:delete')") + public CommonResult deleteProduct(@RequestParam("id") Long id) { + productService.deleteProduct(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得产品") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:product:query')") + public CommonResult getProduct(@RequestParam("id") Long id) { + ProductDO product = productService.getProduct(id); + return success(BeanUtils.toBean(product, ProductRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得产品分页") + @PreAuthorize("@ss.hasPermission('iot:product:query')") + public CommonResult> getProductPage(@Valid ProductPageReqVO pageReqVO) { + PageResult pageResult = productService.getProductPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, ProductRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出产品 Excel") + @PreAuthorize("@ss.hasPermission('iot:product:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportProductExcel(@Valid ProductPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = productService.getProductPage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "产品.xls", "数据", ProductRespVO.class, + BeanUtils.toBean(list, ProductRespVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductPageReqVO.java new file mode 100644 index 000000000..11404eaf5 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductPageReqVO.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.iot.controller.admin.product.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - iot 产品分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ProductPageReqVO extends PageParam { + + @Schema(description = "产品名称", example = "李四") + private String name; + + @Schema(description = "产品标识") + private String identification; + + @Schema(description = "设备类型:device、gatway、gatway_sub", example = "1") + private String deviceType; + + @Schema(description = "厂商名称", example = "李四") + private String manufacturerName; + + @Schema(description = "产品型号") + private String model; + + @Schema(description = "数据格式:1. 标准数据格式(JSON)2. 透传/自定义,脚本解析") + private Integer dataFormat; + + @Schema(description = "设备接入平台的协议类型,默认为MQTT", example = "2") + private String protocolType; + + @Schema(description = "产品描述", example = "随便") + private String description; + + @Schema(description = "产品状态 (0: 启用, 1: 停用)", example = "2") + private Integer status; + + @Schema(description = "物模型定义") + private String metadata; + + @Schema(description = "消息协议ID") + private Long messageProtocol; + + @Schema(description = "消息协议名称", example = "芋艿") + private String protocolName; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductRespVO.java new file mode 100644 index 000000000..e5d251c02 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductRespVO.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.iot.controller.admin.product.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; + +@Schema(description = "管理后台 - iot 产品 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ProductRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "778") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @ExcelProperty("产品名称") + private String name; + + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("产品标识") + private String identification; + + @Schema(description = "设备类型:device、gatway、gatway_sub", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("设备类型:device、gatway、gatway_sub") + private String deviceType; + + @Schema(description = "厂商名称", example = "李四") + @ExcelProperty("厂商名称") + private String manufacturerName; + + @Schema(description = "产品型号") + @ExcelProperty("产品型号") + private String model; + + @Schema(description = "数据格式:1. 标准数据格式(JSON)2. 透传/自定义,脚本解析") + @ExcelProperty("数据格式:1. 标准数据格式(JSON)2. 透传/自定义,脚本解析") + private Integer dataFormat; + + @Schema(description = "设备接入平台的协议类型,默认为MQTT", example = "2") + @ExcelProperty("设备接入平台的协议类型,默认为MQTT") + private String protocolType; + + @Schema(description = "产品描述", example = "随便") + @ExcelProperty("产品描述") + private String description; + + @Schema(description = "产品状态 (0: 启用, 1: 停用)", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("产品状态 (0: 启用, 1: 停用)") + private Integer status; + + @Schema(description = "物模型定义", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("物模型定义") + private String metadata; + + @Schema(description = "消息协议ID", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("消息协议ID") + private Long messageProtocol; + + @Schema(description = "消息协议名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + @ExcelProperty("消息协议名称") + private String protocolName; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java new file mode 100644 index 000000000..305dd651a --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.iot.controller.admin.product.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; + +@Schema(description = "管理后台 - iot 产品新增/修改 Request VO") +@Data +public class ProductSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "778") + private Long id; + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "温湿度") + @NotEmpty(message = "产品名称不能为空") + private String name; + + @Schema(description = "产品标识", example = "123456") + private String identification; + + @Schema(description = "设备类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "device") + @NotEmpty(message = "设备类型不能为空") + private String deviceType; + + @Schema(description = "数据格式:1. 标准数据格式(JSON)2. 透传/自定义", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotEmpty(message = "数据格式不能为空") + private Integer dataFormat; + + @Schema(description = "设备接入平台的协议类型,默认为MQTT", requiredMode = Schema.RequiredMode.REQUIRED, example = "mqtt") + @NotEmpty(message = "设备接入平台的协议类型不能为空") + private String protocolType; + + @Schema(description = "厂商名称", example = "电信") + private String manufacturerName; + + @Schema(description = "产品型号", example = "wsd-01") + private String model; + + @Schema(description = "产品描述", example = "随便") + private String description; + +// @Schema(description = "产品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") +// private Integer status; +// +// @Schema(description = "物模型定义", requiredMode = Schema.RequiredMode.REQUIRED) +// private String metadata; +// +// @Schema(description = "消息协议ID", requiredMode = Schema.RequiredMode.REQUIRED) +// private Long messageProtocol; +// +// @Schema(description = "消息协议名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") +// private String protocolName; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/ProductDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/ProductDO.java new file mode 100644 index 000000000..c7c775b11 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/ProductDO.java @@ -0,0 +1,79 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.product; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * iot 产品 DO + * + * @author 芋道源码 + */ +@TableName("iot_product") +@KeySequence("iot_product_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ProductDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 产品名称 + */ + private String name; + /** + * 产品标识 + */ + private String identification; + /** + * 设备类型:device、gatway、gatway_sub + */ + private String deviceType; + /** + * 厂商名称 + */ + private String manufacturerName; + /** + * 产品型号 + */ + private String model; + /** + * 数据格式:1. 标准数据格式(JSON)2. 透传/自定义,脚本解析 + */ + private Integer dataFormat; + /** + * 设备接入平台的协议类型,默认为MQTT + */ + private String protocolType; + /** + * 产品描述 + */ + private String description; + /** + * 产品状态 (0: 启用, 1: 停用) + */ + private Integer status; + /** + * 物模型定义 + */ + private String metadata; + /** + * 消息协议ID + */ + private Long messageProtocol; + /** + * 消息协议名称 + */ + private String protocolName; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java new file mode 100644 index 000000000..525ae5335 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.product; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.ProductDO; +import jakarta.validation.constraints.NotEmpty; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.*; + +/** + * iot 产品 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface ProductMapper extends BaseMapperX { + + default PageResult selectPage(ProductPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(ProductDO::getName, reqVO.getName()) + .eqIfPresent(ProductDO::getIdentification, reqVO.getIdentification()) + .eqIfPresent(ProductDO::getDeviceType, reqVO.getDeviceType()) + .likeIfPresent(ProductDO::getManufacturerName, reqVO.getManufacturerName()) + .eqIfPresent(ProductDO::getModel, reqVO.getModel()) + .eqIfPresent(ProductDO::getDataFormat, reqVO.getDataFormat()) + .eqIfPresent(ProductDO::getProtocolType, reqVO.getProtocolType()) + .eqIfPresent(ProductDO::getDescription, reqVO.getDescription()) + .eqIfPresent(ProductDO::getStatus, reqVO.getStatus()) + .eqIfPresent(ProductDO::getMetadata, reqVO.getMetadata()) + .eqIfPresent(ProductDO::getMessageProtocol, reqVO.getMessageProtocol()) + .likeIfPresent(ProductDO::getProtocolName, reqVO.getProtocolName()) + .betweenIfPresent(ProductDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(ProductDO::getId)); + } + + default ProductDO selectByIdentification(String identification){ + return selectOne(new LambdaQueryWrapperX().eq(ProductDO::getIdentification, identification)); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java new file mode 100644 index 000000000..5895e1677 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.iot.service.product; + +import java.util.*; +import jakarta.validation.*; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.ProductDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +/** + * iot 产品 Service 接口 + * + * @author 芋道源码 + */ +public interface ProductService { + + /** + * 创建iot 产品 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProduct(@Valid ProductSaveReqVO createReqVO); + + /** + * 更新iot 产品 + * + * @param updateReqVO 更新信息 + */ + void updateProduct(@Valid ProductSaveReqVO updateReqVO); + + /** + * 删除iot 产品 + * + * @param id 编号 + */ + void deleteProduct(Long id); + + /** + * 获得iot 产品 + * + * @param id 编号 + * @return iot 产品 + */ + ProductDO getProduct(Long id); + + /** + * 获得iot 产品分页 + * + * @param pageReqVO 分页查询 + * @return iot 产品分页 + */ + PageResult getProductPage(ProductPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java new file mode 100644 index 000000000..ea9130fc4 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java @@ -0,0 +1,95 @@ +package cn.iocoder.yudao.module.iot.service.product; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.ProductDO; +import cn.iocoder.yudao.module.iot.dal.mysql.product.ProductMapper; +import jakarta.annotation.Resource; +import jakarta.validation.constraints.NotEmpty; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_IDENTIFICATION_EXISTS; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS; + +/** + * iot 产品 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class ProductServiceImpl implements ProductService { + + @Resource + private ProductMapper productMapper; + + @Override + public Long createProduct(ProductSaveReqVO createReqVO) { + // 不传自动生成产品标识 + createIdentification(createReqVO); + // 校验产品标识是否重复 + validateProductIdentification(createReqVO.getIdentification()); + // 插入 + ProductDO product = BeanUtils.toBean(createReqVO, ProductDO.class); + productMapper.insert(product); + // 返回 + return product.getId(); + } + + private void validateProductIdentification(@NotEmpty(message = "产品标识不能为空") String identification) { + if (productMapper.selectByIdentification(identification) != null) { + throw exception(PRODUCT_IDENTIFICATION_EXISTS); + } + } + + private void createIdentification(ProductSaveReqVO createReqVO) { + if (StrUtil.isNotBlank(createReqVO.getIdentification())) { + return; + } + // 生成 19 位数字 + createReqVO.setIdentification(String.valueOf(IdUtil.getSnowflake(1, 1).nextId())); + } + + @Override + public void updateProduct(ProductSaveReqVO updateReqVO) { + // 校验存在 + validateProductExists(updateReqVO.getId()); + // 更新 + ProductDO updateObj = BeanUtils.toBean(updateReqVO, ProductDO.class); + productMapper.updateById(updateObj); + } + + @Override + public void deleteProduct(Long id) { + // 校验存在 + validateProductExists(id); + // 删除 + productMapper.deleteById(id); + } + + private void validateProductExists(Long id) { + if (productMapper.selectById(id) == null) { + throw exception(PRODUCT_NOT_EXISTS); + } + } + + @Override + public ProductDO getProduct(Long id) { + return productMapper.selectById(id); + } + + @Override + public PageResult getProductPage(ProductPageReqVO pageReqVO) { + return productMapper.selectPage(pageReqVO); + } + + public static void main(String[] args) { + System.out.println(String.valueOf(IdUtil.getSnowflake(1, 1).nextId())); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/product/ProductMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/product/ProductMapper.xml new file mode 100644 index 000000000..69352f8ea --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/product/ProductMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImplTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImplTest.java new file mode 100644 index 000000000..d49794b45 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImplTest.java @@ -0,0 +1,178 @@ +package cn.iocoder.yudao.module.iot.service.product; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +import jakarta.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.ProductDO; +import cn.iocoder.yudao.module.iot.dal.mysql.product.ProductMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import jakarta.annotation.Resource; +import org.springframework.context.annotation.Import; +import java.util.*; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.*; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link ProductServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(ProductServiceImpl.class) +public class ProductServiceImplTest extends BaseDbUnitTest { + + @Resource + private ProductServiceImpl productService; + + @Resource + private ProductMapper productMapper; + + @Test + public void testCreateProduct_success() { + // 准备参数 + ProductSaveReqVO createReqVO = randomPojo(ProductSaveReqVO.class).setId(null); + + // 调用 + Long productId = productService.createProduct(createReqVO); + // 断言 + assertNotNull(productId); + // 校验记录的属性是否正确 + ProductDO product = productMapper.selectById(productId); + assertPojoEquals(createReqVO, product, "id"); + } + + @Test + public void testUpdateProduct_success() { + // mock 数据 + ProductDO dbProduct = randomPojo(ProductDO.class); + productMapper.insert(dbProduct);// @Sql: 先插入出一条存在的数据 + // 准备参数 + ProductSaveReqVO updateReqVO = randomPojo(ProductSaveReqVO.class, o -> { + o.setId(dbProduct.getId()); // 设置更新的 ID + }); + + // 调用 + productService.updateProduct(updateReqVO); + // 校验是否更新正确 + ProductDO product = productMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, product); + } + + @Test + public void testUpdateProduct_notExists() { + // 准备参数 + ProductSaveReqVO updateReqVO = randomPojo(ProductSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> productService.updateProduct(updateReqVO), PRODUCT_NOT_EXISTS); + } + + @Test + public void testDeleteProduct_success() { + // mock 数据 + ProductDO dbProduct = randomPojo(ProductDO.class); + productMapper.insert(dbProduct);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbProduct.getId(); + + // 调用 + productService.deleteProduct(id); + // 校验数据不存在了 + assertNull(productMapper.selectById(id)); + } + + @Test + public void testDeleteProduct_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> productService.deleteProduct(id), PRODUCT_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetProductPage() { + // mock 数据 + ProductDO dbProduct = randomPojo(ProductDO.class, o -> { // 等会查询到 + o.setName(null); + o.setIdentification(null); + o.setDeviceType(null); + o.setManufacturerName(null); + o.setModel(null); + o.setDataFormat(null); + o.setProtocolType(null); + o.setDescription(null); + o.setStatus(null); + o.setMetadata(null); + o.setMessageProtocol(null); + o.setProtocolName(null); + o.setCreateTime(null); + }); + productMapper.insert(dbProduct); + // 测试 name 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setName(null))); + // 测试 identification 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setIdentification(null))); + // 测试 deviceType 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setDeviceType(null))); + // 测试 manufacturerName 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setManufacturerName(null))); + // 测试 model 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setModel(null))); + // 测试 dataFormat 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setDataFormat(null))); + // 测试 protocolType 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setProtocolType(null))); + // 测试 description 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setDescription(null))); + // 测试 status 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setStatus(null))); + // 测试 metadata 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setMetadata(null))); + // 测试 messageProtocol 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setMessageProtocol(null))); + // 测试 protocolName 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setProtocolName(null))); + // 测试 createTime 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setCreateTime(null))); + // 准备参数 + ProductPageReqVO reqVO = new ProductPageReqVO(); + reqVO.setName(null); + reqVO.setIdentification(null); + reqVO.setDeviceType(null); + reqVO.setManufacturerName(null); + reqVO.setModel(null); + reqVO.setDataFormat(null); + reqVO.setProtocolType(null); + reqVO.setDescription(null); + reqVO.setStatus(null); + reqVO.setMetadata(null); + reqVO.setMessageProtocol(null); + reqVO.setProtocolName(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = productService.getProductPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbProduct, pageResult.getList().get(0)); + } + +} \ No newline at end of file diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml index 6ed31f148..3fe8ef48d 100644 --- a/yudao-server/pom.xml +++ b/yudao-server/pom.xml @@ -46,11 +46,11 @@ - - - - - + + cn.iocoder.boot + yudao-module-bpm-biz + ${revision} + @@ -88,11 +88,11 @@ - - - - - + + cn.iocoder.boot + yudao-module-crm-biz + ${revision} + diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index 20110708c..27588d045 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -174,6 +174,7 @@ logging: cn.iocoder.yudao.module.statistics.dal.mysql: debug cn.iocoder.yudao.module.crm.dal.mysql: debug cn.iocoder.yudao.module.erp.dal.mysql: debug + cn.iocoder.yudao.module.iot.dal.mysql: debug org.springframework.context.support.PostProcessorRegistrationDelegate: ERROR # TODO 芋艿:先禁用,Spring Boot 3.X 存在部分错误的 WARN 提示 debug: false From 609cc719302c885dd8f1ab3d5146b6b16a27f281 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Fri, 6 Sep 2024 21:50:25 +0800 Subject: [PATCH 04/31] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9Aiot=20?= =?UTF-8?q?=E4=BA=A7=E5=93=81=20=E5=AD=97=E6=AE=B5=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/product/ProductController.java | 2 +- .../admin/product/vo/ProductPageReqVO.java | 63 ++++++------- .../admin/product/vo/ProductRespVO.java | 92 +++++++++---------- .../admin/product/vo/ProductSaveReqVO.java | 70 +++++++------- .../iot/dal/dataobject/product/ProductDO.java | 54 +++++------ .../iot/dal/mysql/product/ProductMapper.java | 25 ++--- .../iot/service/product/ProductService.java | 25 +++-- .../service/product/ProductServiceImpl.java | 27 +----- .../product/ProductServiceImplTest.java | 84 ++++++++--------- 9 files changed, 198 insertions(+), 244 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/ProductController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/ProductController.java index 739e13320..9acce0234 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/ProductController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/ProductController.java @@ -27,7 +27,7 @@ import java.util.List; import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -@Tag(name = "管理后台 - iot 产品") +@Tag(name = "管理后台 - IOT 产品") @RestController @RequestMapping("/iot/product") @Validated diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductPageReqVO.java index 11404eaf5..4479d5218 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductPageReqVO.java @@ -18,41 +18,38 @@ public class ProductPageReqVO extends PageParam { @Schema(description = "产品名称", example = "李四") private String name; - @Schema(description = "产品标识") - private String identification; - - @Schema(description = "设备类型:device、gatway、gatway_sub", example = "1") - private String deviceType; - - @Schema(description = "厂商名称", example = "李四") - private String manufacturerName; - - @Schema(description = "产品型号") - private String model; - - @Schema(description = "数据格式:1. 标准数据格式(JSON)2. 透传/自定义,脚本解析") - private Integer dataFormat; - - @Schema(description = "设备接入平台的协议类型,默认为MQTT", example = "2") - private String protocolType; - - @Schema(description = "产品描述", example = "随便") - private String description; - - @Schema(description = "产品状态 (0: 启用, 1: 停用)", example = "2") - private Integer status; - - @Schema(description = "物模型定义") - private String metadata; - - @Schema(description = "消息协议ID") - private Long messageProtocol; - - @Schema(description = "消息协议名称", example = "芋艿") - private String protocolName; - @Schema(description = "创建时间") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; + @Schema(description = "产品标识") + private String productKey; + + @Schema(description = "协议编号(脚本解析 id)", example = "13177") + private Long protocolId; + + @Schema(description = "产品所属品类标识符", example = "14237") + private Long categoryId; + + @Schema(description = "产品描述", example = "你猜") + private String description; + + @Schema(description = "数据校验级别, 0: 强校验, 1: 弱校验, 2: 免校验", example = "1") + private Integer validateType; + + @Schema(description = "产品状态, 0: DEVELOPMENT_STATUS, 1: RELEASE_STATUS", example = "1") + private Integer status; + + @Schema(description = "设备类型, 0: 直连设备, 1: 网关子设备, 2: 网关设备", example = "2") + private Integer deviceType; + + @Schema(description = "联网方式, 0: Wi-Fi, 1: Cellular, 2: Ethernet, 3: 其他", example = "2") + private Integer netType; + + @Schema(description = "接入网关协议, 0: modbus, 1: opc-ua, 2: customize, 3: ble, 4: zigbee", example = "2") + private Integer protocolType; + + @Schema(description = "数据格式, 0: 透传模式, 1: Alink JSON") + private Integer dataFormat; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductRespVO.java index e5d251c02..64aeeac13 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductRespVO.java @@ -12,60 +12,56 @@ import com.alibaba.excel.annotation.*; @ExcelIgnoreUnannotated public class ProductRespVO { - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "778") - @ExcelProperty("编号") - private Long id; - @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") @ExcelProperty("产品名称") private String name; - @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("产品标识") - private String identification; - - @Schema(description = "设备类型:device、gatway、gatway_sub", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @ExcelProperty("设备类型:device、gatway、gatway_sub") - private String deviceType; - - @Schema(description = "厂商名称", example = "李四") - @ExcelProperty("厂商名称") - private String manufacturerName; - - @Schema(description = "产品型号") - @ExcelProperty("产品型号") - private String model; - - @Schema(description = "数据格式:1. 标准数据格式(JSON)2. 透传/自定义,脚本解析") - @ExcelProperty("数据格式:1. 标准数据格式(JSON)2. 透传/自定义,脚本解析") - private Integer dataFormat; - - @Schema(description = "设备接入平台的协议类型,默认为MQTT", example = "2") - @ExcelProperty("设备接入平台的协议类型,默认为MQTT") - private String protocolType; - - @Schema(description = "产品描述", example = "随便") - @ExcelProperty("产品描述") - private String description; - - @Schema(description = "产品状态 (0: 启用, 1: 停用)", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @ExcelProperty("产品状态 (0: 启用, 1: 停用)") - private Integer status; - - @Schema(description = "物模型定义", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("物模型定义") - private String metadata; - - @Schema(description = "消息协议ID", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("消息协议ID") - private Long messageProtocol; - - @Schema(description = "消息协议名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") - @ExcelProperty("消息协议名称") - private String protocolName; - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("创建时间") private LocalDateTime createTime; + @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26087") + @ExcelProperty("产品ID") + private Long id; + + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("产品标识") + private String productKey; + + @Schema(description = "协议编号(脚本解析 id)", requiredMode = Schema.RequiredMode.REQUIRED, example = "13177") + @ExcelProperty("协议编号(脚本解析 id)") + private Long protocolId; + + @Schema(description = "产品所属品类标识符", example = "14237") + @ExcelProperty("产品所属品类标识符") + private Long categoryId; + + @Schema(description = "产品描述", example = "你猜") + @ExcelProperty("产品描述") + private String description; + + @Schema(description = "数据校验级别, 0: 强校验, 1: 弱校验, 2: 免校验", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("数据校验级别, 0: 强校验, 1: 弱校验, 2: 免校验") + private Integer validateType; + + @Schema(description = "产品状态, 0: DEVELOPMENT_STATUS, 1: RELEASE_STATUS", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("产品状态, 0: DEVELOPMENT_STATUS, 1: RELEASE_STATUS") + private Integer status; + + @Schema(description = "设备类型, 0: 直连设备, 1: 网关子设备, 2: 网关设备", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("设备类型, 0: 直连设备, 1: 网关子设备, 2: 网关设备") + private Integer deviceType; + + @Schema(description = "联网方式, 0: Wi-Fi, 1: Cellular, 2: Ethernet, 3: 其他", example = "2") + @ExcelProperty("联网方式, 0: Wi-Fi, 1: Cellular, 2: Ethernet, 3: 其他") + private Integer netType; + + @Schema(description = "接入网关协议, 0: modbus, 1: opc-ua, 2: customize, 3: ble, 4: zigbee", example = "2") + @ExcelProperty("接入网关协议, 0: modbus, 1: opc-ua, 2: customize, 3: ble, 4: zigbee") + private Integer protocolType; + + @Schema(description = "数据格式, 0: 透传模式, 1: Alink JSON") + @ExcelProperty("数据格式, 0: 透传模式, 1: Alink JSON") + private Integer dataFormat; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java index 305dd651a..68f1f4621 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java @@ -1,54 +1,54 @@ package cn.iocoder.yudao.module.iot.controller.admin.product.vo; import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotEmpty; -import lombok.Data; +import lombok.*; +import java.util.*; +import jakarta.validation.constraints.*; @Schema(description = "管理后台 - iot 产品新增/修改 Request VO") @Data public class ProductSaveReqVO { - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "778") - private Long id; - - @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "温湿度") + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") @NotEmpty(message = "产品名称不能为空") private String name; - @Schema(description = "产品标识", example = "123456") - private String identification; + @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26087") + private Long id; - @Schema(description = "设备类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "device") - @NotEmpty(message = "设备类型不能为空") - private String deviceType; + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "产品标识不能为空") + private String productKey; - @Schema(description = "数据格式:1. 标准数据格式(JSON)2. 透传/自定义", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @NotEmpty(message = "数据格式不能为空") - private Integer dataFormat; + @Schema(description = "协议编号(脚本解析 id)", requiredMode = Schema.RequiredMode.REQUIRED, example = "13177") + @NotNull(message = "协议编号(脚本解析 id)不能为空") + private Long protocolId; - @Schema(description = "设备接入平台的协议类型,默认为MQTT", requiredMode = Schema.RequiredMode.REQUIRED, example = "mqtt") - @NotEmpty(message = "设备接入平台的协议类型不能为空") - private String protocolType; + @Schema(description = "产品所属品类标识符", example = "14237") + private Long categoryId; - @Schema(description = "厂商名称", example = "电信") - private String manufacturerName; - - @Schema(description = "产品型号", example = "wsd-01") - private String model; - - @Schema(description = "产品描述", example = "随便") + @Schema(description = "产品描述", example = "你猜") private String description; -// @Schema(description = "产品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") -// private Integer status; -// -// @Schema(description = "物模型定义", requiredMode = Schema.RequiredMode.REQUIRED) -// private String metadata; -// -// @Schema(description = "消息协议ID", requiredMode = Schema.RequiredMode.REQUIRED) -// private Long messageProtocol; -// -// @Schema(description = "消息协议名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") -// private String protocolName; + @Schema(description = "数据校验级别, 0: 强校验, 1: 弱校验, 2: 免校验", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "数据校验级别, 0: 强校验, 1: 弱校验, 2: 免校验不能为空") + private Integer validateType; + + @Schema(description = "产品状态, 0: DEVELOPMENT_STATUS, 1: RELEASE_STATUS", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "产品状态, 0: DEVELOPMENT_STATUS, 1: RELEASE_STATUS不能为空") + private Integer status; + + @Schema(description = "设备类型, 0: 直连设备, 1: 网关子设备, 2: 网关设备", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "设备类型, 0: 直连设备, 1: 网关子设备, 2: 网关设备不能为空") + private Integer deviceType; + + @Schema(description = "联网方式, 0: Wi-Fi, 1: Cellular, 2: Ethernet, 3: 其他", example = "2") + private Integer netType; + + @Schema(description = "接入网关协议, 0: modbus, 1: opc-ua, 2: customize, 3: ble, 4: zigbee", example = "2") + private Integer protocolType; + + @Schema(description = "数据格式, 0: 透传模式, 1: Alink JSON") + private Integer dataFormat; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/ProductDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/ProductDO.java index c7c775b11..d6a79d8c5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/ProductDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/ProductDO.java @@ -22,58 +22,54 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; @AllArgsConstructor public class ProductDO extends BaseDO { - /** - * 编号 - */ - @TableId - private Long id; /** * 产品名称 */ private String name; + /** + * 产品ID + */ + @TableId + private Long id; /** * 产品标识 */ - private String identification; + private String productKey; /** - * 设备类型:device、gatway、gatway_sub + * 协议编号(脚本解析 id) */ - private String deviceType; + private Long protocolId; /** - * 厂商名称 + * 产品所属品类标识符 */ - private String manufacturerName; - /** - * 产品型号 - */ - private String model; - /** - * 数据格式:1. 标准数据格式(JSON)2. 透传/自定义,脚本解析 - */ - private Integer dataFormat; - /** - * 设备接入平台的协议类型,默认为MQTT - */ - private String protocolType; + private Long categoryId; /** * 产品描述 */ private String description; /** - * 产品状态 (0: 启用, 1: 停用) + * 数据校验级别, 0: 强校验, 1: 弱校验, 2: 免校验 + */ + private Integer validateType; + /** + * 产品状态, 0: DEVELOPMENT_STATUS, 1: RELEASE_STATUS */ private Integer status; /** - * 物模型定义 + * 设备类型, 0: 直连设备, 1: 网关子设备, 2: 网关设备 */ - private String metadata; + private Integer deviceType; /** - * 消息协议ID + * 联网方式, 0: Wi-Fi, 1: Cellular, 2: Ethernet, 3: 其他 */ - private Long messageProtocol; + private Integer netType; /** - * 消息协议名称 + * 接入网关协议, 0: modbus, 1: opc-ua, 2: customize, 3: ble, 4: zigbee */ - private String protocolName; + private Integer protocolType; + /** + * 数据格式, 0: 透传模式, 1: Alink JSON + */ + private Integer dataFormat; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java index 525ae5335..eac366756 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java @@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.module.iot.dal.dataobject.product.ProductDO; -import jakarta.validation.constraints.NotEmpty; import org.apache.ibatis.annotations.Mapper; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.*; @@ -21,22 +20,18 @@ public interface ProductMapper extends BaseMapperX { default PageResult selectPage(ProductPageReqVO reqVO) { return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(ProductDO::getName, reqVO.getName()) - .eqIfPresent(ProductDO::getIdentification, reqVO.getIdentification()) - .eqIfPresent(ProductDO::getDeviceType, reqVO.getDeviceType()) - .likeIfPresent(ProductDO::getManufacturerName, reqVO.getManufacturerName()) - .eqIfPresent(ProductDO::getModel, reqVO.getModel()) - .eqIfPresent(ProductDO::getDataFormat, reqVO.getDataFormat()) - .eqIfPresent(ProductDO::getProtocolType, reqVO.getProtocolType()) - .eqIfPresent(ProductDO::getDescription, reqVO.getDescription()) - .eqIfPresent(ProductDO::getStatus, reqVO.getStatus()) - .eqIfPresent(ProductDO::getMetadata, reqVO.getMetadata()) - .eqIfPresent(ProductDO::getMessageProtocol, reqVO.getMessageProtocol()) - .likeIfPresent(ProductDO::getProtocolName, reqVO.getProtocolName()) .betweenIfPresent(ProductDO::getCreateTime, reqVO.getCreateTime()) + .eqIfPresent(ProductDO::getProductKey, reqVO.getProductKey()) + .eqIfPresent(ProductDO::getProtocolId, reqVO.getProtocolId()) + .eqIfPresent(ProductDO::getCategoryId, reqVO.getCategoryId()) + .eqIfPresent(ProductDO::getDescription, reqVO.getDescription()) + .eqIfPresent(ProductDO::getValidateType, reqVO.getValidateType()) + .eqIfPresent(ProductDO::getStatus, reqVO.getStatus()) + .eqIfPresent(ProductDO::getDeviceType, reqVO.getDeviceType()) + .eqIfPresent(ProductDO::getNetType, reqVO.getNetType()) + .eqIfPresent(ProductDO::getProtocolType, reqVO.getProtocolType()) + .eqIfPresent(ProductDO::getDataFormat, reqVO.getDataFormat()) .orderByDesc(ProductDO::getId)); } - default ProductDO selectByIdentification(String identification){ - return selectOne(new LambdaQueryWrapperX().eq(ProductDO::getIdentification, identification)); - } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java index 5895e1677..049ba26ce 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java @@ -1,21 +1,20 @@ package cn.iocoder.yudao.module.iot.service.product; -import java.util.*; -import jakarta.validation.*; -import cn.iocoder.yudao.module.iot.controller.admin.product.vo.*; -import cn.iocoder.yudao.module.iot.dal.dataobject.product.ProductDO; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.ProductDO; +import jakarta.validation.Valid; /** - * iot 产品 Service 接口 + * IOT 产品 Service 接口 * * @author 芋道源码 */ public interface ProductService { /** - * 创建iot 产品 + * 创建产品 * * @param createReqVO 创建信息 * @return 编号 @@ -23,32 +22,32 @@ public interface ProductService { Long createProduct(@Valid ProductSaveReqVO createReqVO); /** - * 更新iot 产品 + * 更新产品 * * @param updateReqVO 更新信息 */ void updateProduct(@Valid ProductSaveReqVO updateReqVO); /** - * 删除iot 产品 + * 删除产品 * * @param id 编号 */ void deleteProduct(Long id); /** - * 获得iot 产品 + * 获得产品 * * @param id 编号 - * @return iot 产品 + * @return 产品 */ ProductDO getProduct(Long id); /** - * 获得iot 产品分页 + * 获得产品分页 * * @param pageReqVO 分页查询 - * @return iot 产品分页 + * @return 产品分页 */ PageResult getProductPage(ProductPageReqVO pageReqVO); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java index ea9130fc4..b4b1c5a51 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java @@ -1,7 +1,5 @@ package cn.iocoder.yudao.module.iot.service.product; -import cn.hutool.core.util.IdUtil; -import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductPageReqVO; @@ -9,16 +7,14 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.ProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.product.ProductMapper; import jakarta.annotation.Resource; -import jakarta.validation.constraints.NotEmpty; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_IDENTIFICATION_EXISTS; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS; /** - * iot 产品 Service 实现类 + * IOT 产品 Service 实现类 * * @author 芋道源码 */ @@ -31,10 +27,6 @@ public class ProductServiceImpl implements ProductService { @Override public Long createProduct(ProductSaveReqVO createReqVO) { - // 不传自动生成产品标识 - createIdentification(createReqVO); - // 校验产品标识是否重复 - validateProductIdentification(createReqVO.getIdentification()); // 插入 ProductDO product = BeanUtils.toBean(createReqVO, ProductDO.class); productMapper.insert(product); @@ -42,20 +34,6 @@ public class ProductServiceImpl implements ProductService { return product.getId(); } - private void validateProductIdentification(@NotEmpty(message = "产品标识不能为空") String identification) { - if (productMapper.selectByIdentification(identification) != null) { - throw exception(PRODUCT_IDENTIFICATION_EXISTS); - } - } - - private void createIdentification(ProductSaveReqVO createReqVO) { - if (StrUtil.isNotBlank(createReqVO.getIdentification())) { - return; - } - // 生成 19 位数字 - createReqVO.setIdentification(String.valueOf(IdUtil.getSnowflake(1, 1).nextId())); - } - @Override public void updateProduct(ProductSaveReqVO updateReqVO) { // 校验存在 @@ -89,7 +67,4 @@ public class ProductServiceImpl implements ProductService { return productMapper.selectPage(pageReqVO); } - public static void main(String[] args) { - System.out.println(String.valueOf(IdUtil.getSnowflake(1, 1).nextId())); - } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImplTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImplTest.java index d49794b45..244cda607 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImplTest.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImplTest.java @@ -111,61 +111,57 @@ public class ProductServiceImplTest extends BaseDbUnitTest { // mock 数据 ProductDO dbProduct = randomPojo(ProductDO.class, o -> { // 等会查询到 o.setName(null); - o.setIdentification(null); - o.setDeviceType(null); - o.setManufacturerName(null); - o.setModel(null); - o.setDataFormat(null); - o.setProtocolType(null); - o.setDescription(null); - o.setStatus(null); - o.setMetadata(null); - o.setMessageProtocol(null); - o.setProtocolName(null); o.setCreateTime(null); + o.setProductKey(null); + o.setProtocolId(null); + o.setCategoryId(null); + o.setDescription(null); + o.setValidateType(null); + o.setStatus(null); + o.setDeviceType(null); + o.setNetType(null); + o.setProtocolType(null); + o.setDataFormat(null); }); productMapper.insert(dbProduct); // 测试 name 不匹配 productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setName(null))); - // 测试 identification 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setIdentification(null))); - // 测试 deviceType 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setDeviceType(null))); - // 测试 manufacturerName 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setManufacturerName(null))); - // 测试 model 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setModel(null))); - // 测试 dataFormat 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setDataFormat(null))); - // 测试 protocolType 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setProtocolType(null))); - // 测试 description 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setDescription(null))); - // 测试 status 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setStatus(null))); - // 测试 metadata 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setMetadata(null))); - // 测试 messageProtocol 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setMessageProtocol(null))); - // 测试 protocolName 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setProtocolName(null))); // 测试 createTime 不匹配 productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setCreateTime(null))); + // 测试 productKey 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setProductKey(null))); + // 测试 protocolId 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setProtocolId(null))); + // 测试 categoryId 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setCategoryId(null))); + // 测试 description 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setDescription(null))); + // 测试 validateType 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setValidateType(null))); + // 测试 status 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setStatus(null))); + // 测试 deviceType 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setDeviceType(null))); + // 测试 netType 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setNetType(null))); + // 测试 protocolType 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setProtocolType(null))); + // 测试 dataFormat 不匹配 + productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setDataFormat(null))); // 准备参数 ProductPageReqVO reqVO = new ProductPageReqVO(); reqVO.setName(null); - reqVO.setIdentification(null); - reqVO.setDeviceType(null); - reqVO.setManufacturerName(null); - reqVO.setModel(null); - reqVO.setDataFormat(null); - reqVO.setProtocolType(null); - reqVO.setDescription(null); - reqVO.setStatus(null); - reqVO.setMetadata(null); - reqVO.setMessageProtocol(null); - reqVO.setProtocolName(null); reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setProductKey(null); + reqVO.setProtocolId(null); + reqVO.setCategoryId(null); + reqVO.setDescription(null); + reqVO.setValidateType(null); + reqVO.setStatus(null); + reqVO.setDeviceType(null); + reqVO.setNetType(null); + reqVO.setProtocolType(null); + reqVO.setDataFormat(null); // 调用 PageResult pageResult = productService.getProductPage(reqVO); From f7b62b4bcc666728c4455de3080df4a231e0c3cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Fri, 6 Sep 2024 23:14:53 +0800 Subject: [PATCH 05/31] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9A=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E4=BA=A7=E5=93=81=E7=94=9F=E6=88=90=20ProductKey?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/product/vo/ProductSaveReqVO.java | 53 ++++++++----------- .../service/product/ProductServiceImpl.java | 15 ++++++ 2 files changed, 37 insertions(+), 31 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java index 68f1f4621..9ecf8a2ce 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java @@ -9,46 +9,37 @@ import jakarta.validation.constraints.*; @Data public class ProductSaveReqVO { - @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.AUTO, example = "1") + private Long id; + + @Schema(description = "产品Key", requiredMode = Schema.RequiredMode.AUTO, example = "12345abc") + private String productKey; + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "温湿度") @NotEmpty(message = "产品名称不能为空") private String name; - @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26087") - private Long id; - - @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED) - @NotEmpty(message = "产品标识不能为空") - private String productKey; - - @Schema(description = "协议编号(脚本解析 id)", requiredMode = Schema.RequiredMode.REQUIRED, example = "13177") - @NotNull(message = "协议编号(脚本解析 id)不能为空") - private Long protocolId; - - @Schema(description = "产品所属品类标识符", example = "14237") - private Long categoryId; - - @Schema(description = "产品描述", example = "你猜") - private String description; - - @Schema(description = "数据校验级别, 0: 强校验, 1: 弱校验, 2: 免校验", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @NotNull(message = "数据校验级别, 0: 强校验, 1: 弱校验, 2: 免校验不能为空") - private Integer validateType; - - @Schema(description = "产品状态, 0: DEVELOPMENT_STATUS, 1: RELEASE_STATUS", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @NotNull(message = "产品状态, 0: DEVELOPMENT_STATUS, 1: RELEASE_STATUS不能为空") - private Integer status; - - @Schema(description = "设备类型, 0: 直连设备, 1: 网关子设备, 2: 网关设备", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @NotNull(message = "设备类型, 0: 直连设备, 1: 网关子设备, 2: 网关设备不能为空") + @Schema(description = "设备类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @NotNull(message = "设备类型不能为空") private Integer deviceType; - @Schema(description = "联网方式, 0: Wi-Fi, 1: Cellular, 2: Ethernet, 3: 其他", example = "2") + @Schema(description = "联网方式", requiredMode = Schema.RequiredMode.REQUIRED,example = "0") + @NotNull(message = "联网方式不能为空") private Integer netType; - @Schema(description = "接入网关协议, 0: modbus, 1: opc-ua, 2: customize, 3: ble, 4: zigbee", example = "2") + @Schema(description = "接入网关协议", requiredMode = Schema.RequiredMode.REQUIRED,example = "0") + @NotNull(message = "接入网关协议不能为空") private Integer protocolType; - @Schema(description = "数据格式, 0: 透传模式, 1: Alink JSON") + @Schema(description = "数据格式",requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @NotNull(message = "数据格式不能为空") private Integer dataFormat; + @Schema(description = "数据校验级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @NotNull(message = "数据校验级别不能为空") + private Integer validateType; + + @Schema(description = "产品描述", example = "描述") + private String description; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java index b4b1c5a51..b2ca76213 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java @@ -10,6 +10,8 @@ import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.UUID; + import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS; @@ -27,6 +29,8 @@ public class ProductServiceImpl implements ProductService { @Override public Long createProduct(ProductSaveReqVO createReqVO) { + // 生成 ProductKey + createProductKey(createReqVO); // 插入 ProductDO product = BeanUtils.toBean(createReqVO, ProductDO.class); productMapper.insert(product); @@ -34,6 +38,17 @@ public class ProductServiceImpl implements ProductService { return product.getId(); } + /** + * 创建 ProductKey + * + * @param createReqVO 创建信息 + */ + private void createProductKey(ProductSaveReqVO createReqVO) { + // 生成随机的 11 位字符串 + String productKey = UUID.randomUUID().toString().replace("-", "").substring(0, 11); + createReqVO.setProductKey(productKey); + } + @Override public void updateProduct(ProductSaveReqVO updateReqVO) { // 校验存在 From 037ab39ac74746e8cfc452b00cb593144bf4d6f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sat, 7 Sep 2024 09:45:47 +0800 Subject: [PATCH 06/31] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9A=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E4=BA=A7=E5=93=81=E6=9E=9A=E4=B8=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/enums/ProductDeviceTypeConstants.java | 13 ------ .../enums/ProductProtocolTypeConstants.java | 13 ------ .../IotDataFormatEnum.java} | 12 +++--- .../iot/enums/product/IotNetTypeEnum.java | 40 ++++++++++++++++++ .../product/IotProductDeviceTypeEnum.java | 38 +++++++++++++++++ .../IotProductStatusEnum.java} | 12 +++--- .../enums/product/IotProtocolTypeEnum.java | 41 +++++++++++++++++++ .../enums/product/IotValidateTypeEnum.java | 38 +++++++++++++++++ .../admin/product/vo/ProductSaveReqVO.java | 9 +++- .../iot/dal/mysql/product/ProductMapper.java | 8 ++-- 10 files changed, 179 insertions(+), 45 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductDeviceTypeConstants.java delete mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductProtocolTypeConstants.java rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/{ProductDataFormatEnum.java => product/IotDataFormatEnum.java} (61%) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/{ProductStatusEnum.java => product/IotProductStatusEnum.java} (62%) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProtocolTypeEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotValidateTypeEnum.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductDeviceTypeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductDeviceTypeConstants.java deleted file mode 100644 index d44a47102..000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductDeviceTypeConstants.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.iocoder.yudao.module.iot.enums; - -/** - * 产品设备类型常量 - */ -public interface ProductDeviceTypeConstants { - - // ========== 产品设备类型 ============ - String DEVICE = "device"; // 直连设备 - String GATEWAY = "gateway"; // 网关设备 - String GATEWAY_SUB = "gateway_sub"; // 网关子设备 - -} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductProtocolTypeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductProtocolTypeConstants.java deleted file mode 100644 index fe033bf5d..000000000 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductProtocolTypeConstants.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.iocoder.yudao.module.iot.enums; - -/** - * 产品传输协议类型常量 - */ -public interface ProductProtocolTypeConstants { - - // ========== 产品传输协议类型 ============ - String MQTT = "mqtt"; // MQTT - String COAP = "coap"; // COAP - String HTTP = "http"; // HTTP - String HTTPS = "https"; // HTTPS -} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductDataFormatEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotDataFormatEnum.java similarity index 61% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductDataFormatEnum.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotDataFormatEnum.java index be3470982..4b0f15e05 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductDataFormatEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotDataFormatEnum.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.enums; +package cn.iocoder.yudao.module.iot.enums.product; import cn.iocoder.yudao.framework.common.core.IntArrayValuable; import lombok.AllArgsConstructor; @@ -8,14 +8,14 @@ import java.util.Arrays; /** * 产品数据格式枚举类 - * 1. 标准数据格式(JSON)2. 透传/自定义 + * 数据格式, 0: 标准数据格式(JSON), 1: 透传/自定义 */ @AllArgsConstructor @Getter -public enum ProductDataFormatEnum implements IntArrayValuable { +public enum IotDataFormatEnum implements IntArrayValuable { - JSON(1, "标准数据格式(JSON)"), - SCRIPT(2, "透传/自定义"); + JSON(0, "标准数据格式(JSON)"), + CUSTOMIZE(1, "透传/自定义"); /** * 类型 @@ -27,7 +27,7 @@ public enum ProductDataFormatEnum implements IntArrayValuable { */ private final String description; - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductDataFormatEnum::getType).toArray(); + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotDataFormatEnum::getType).toArray(); @Override public int[] array() { diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java new file mode 100644 index 000000000..aef8999be --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.iot.enums.product; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * IOT 联网方式枚举类 + * 联网方式, 0: Wi-Fi, 1: Cellular, 2: Ethernet, 3: 其他 + */ +@AllArgsConstructor +@Getter +public enum IotNetTypeEnum implements IntArrayValuable { + + WIFI(0, "Wi-Fi"), + CELLULAR(1, "Cellular"), + ETHERNET(2, "Ethernet"), + OTHER(3, "其他"); + + + /** + * 类型 + */ + private final Integer type; + + /** + * 描述 + */ + private final String description; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotNetTypeEnum::getType).toArray(); + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java new file mode 100644 index 000000000..37ce0b5ad --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.iot.enums.product; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * IOT 产品设备类型 + * 设备类型, 0: 直连设备, 1: 网关子设备, 2: 网关设备 + */ +@AllArgsConstructor +@Getter +public enum IotProductDeviceTypeEnum implements IntArrayValuable { + + DIRECT(0, "直连设备"), + GATEWAY_CHILD(1, "网关子设备"), + GATEWAY(2, "网关设备"); + + /** + * 类型 + */ + private final Integer type; + + /** + * 描述 + */ + private final String description; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotProductDeviceTypeEnum::getType).toArray(); + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductStatusEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java similarity index 62% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductStatusEnum.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java index 94ec21f61..38316371b 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ProductStatusEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java @@ -1,19 +1,19 @@ -package cn.iocoder.yudao.module.iot.enums; +package cn.iocoder.yudao.module.iot.enums.product; import cn.iocoder.yudao.framework.common.core.IntArrayValuable; import lombok.AllArgsConstructor; import lombok.Getter; /** - * 产品状态枚举类 - * 禁用 启用 + * IOT 产品状态枚举类 + * 产品状态, 0: 未发布, 1: 已发布 */ @AllArgsConstructor @Getter -public enum ProductStatusEnum implements IntArrayValuable { +public enum IotProductStatusEnum implements IntArrayValuable { - DISABLE(0, "禁用"), - ENABLE(1, "启用"); + UNPUBLISHED(0, "未发布"), + PUBLISHED(1, "已发布"); /** * 类型 diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProtocolTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProtocolTypeEnum.java new file mode 100644 index 000000000..64644b213 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProtocolTypeEnum.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.iot.enums.product; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * IOT 接入网关协议枚举类 + * 接入网关协议, 0: 自定义, 1: Modbus, 2: OPC UA, 3: ZigBee, 4: BLE + */ +@AllArgsConstructor +@Getter +public enum IotProtocolTypeEnum implements IntArrayValuable { + + CUSTOM(0, "自定义"), + MODBUS(1, "Modbus"), + OPC_UA(2, "OPC UA"), + ZIGBEE(3, "ZigBee"), + BLE(4, "BLE"); + + + /** + * 类型 + */ + private final Integer type; + + /** + * 描述 + */ + private final String description; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotProtocolTypeEnum::getType).toArray(); + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotValidateTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotValidateTypeEnum.java new file mode 100644 index 000000000..3b27b0d36 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotValidateTypeEnum.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.iot.enums.product; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * IOT 数据校验级别枚举类 + * 数据校验级别, 0: 弱校验, 1: 免校验 + */ +@AllArgsConstructor +@Getter +public enum IotValidateTypeEnum implements IntArrayValuable { + + WEAK(0, "弱校验"), + NONE(1, "免校验"); + + + /** + * 类型 + */ + private final Integer type; + + /** + * 描述 + */ + private final String description; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotValidateTypeEnum::getType).toArray(); + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java index 9ecf8a2ce..ecbbb03c9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.product.vo; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.iot.enums.product.*; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; import java.util.*; @@ -20,22 +22,25 @@ public class ProductSaveReqVO { private String name; @Schema(description = "设备类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @InEnum(value = IotProductDeviceTypeEnum.class, message = "设备类型必须是 {value}") @NotNull(message = "设备类型不能为空") private Integer deviceType; @Schema(description = "联网方式", requiredMode = Schema.RequiredMode.REQUIRED,example = "0") - @NotNull(message = "联网方式不能为空") + @InEnum(value = IotNetTypeEnum.class, message = "联网方式必须是 {value}") private Integer netType; @Schema(description = "接入网关协议", requiredMode = Schema.RequiredMode.REQUIRED,example = "0") - @NotNull(message = "接入网关协议不能为空") + @InEnum(value = IotProtocolTypeEnum.class, message = "接入网关协议必须是 {value}") private Integer protocolType; @Schema(description = "数据格式",requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @InEnum(value = IotDataFormatEnum.class, message = "数据格式必须是 {value}") @NotNull(message = "数据格式不能为空") private Integer dataFormat; @Schema(description = "数据校验级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @InEnum(value = IotValidateTypeEnum.class, message = "数据校验级别必须是 {value}") @NotNull(message = "数据校验级别不能为空") private Integer validateType; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java index eac366756..b8e80b7a3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java @@ -1,13 +1,11 @@ package cn.iocoder.yudao.module.iot.dal.mysql.product; -import java.util.*; - import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.ProductDO; import org.apache.ibatis.annotations.Mapper; -import cn.iocoder.yudao.module.iot.controller.admin.product.vo.*; /** * iot 产品 Mapper @@ -21,7 +19,7 @@ public interface ProductMapper extends BaseMapperX { return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(ProductDO::getName, reqVO.getName()) .betweenIfPresent(ProductDO::getCreateTime, reqVO.getCreateTime()) - .eqIfPresent(ProductDO::getProductKey, reqVO.getProductKey()) + .likeIfPresent(ProductDO::getProductKey, reqVO.getProductKey()) .eqIfPresent(ProductDO::getProtocolId, reqVO.getProtocolId()) .eqIfPresent(ProductDO::getCategoryId, reqVO.getCategoryId()) .eqIfPresent(ProductDO::getDescription, reqVO.getDescription()) From c7b1cc9a436084ee78d416276f2fc351673a69c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sat, 7 Sep 2024 19:41:41 +0800 Subject: [PATCH 07/31] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9A=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E4=BA=A7=E5=93=81=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 1 + .../enums/product/IotProductStatusEnum.java | 4 ++-- .../admin/product/ProductController.java | 11 ++++++++++ .../iot/service/product/ProductService.java | 7 +++++++ .../service/product/ProductServiceImpl.java | 21 +++++++++++++++++++ 5 files changed, 42 insertions(+), 2 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 6a21de7cb..3fd09ce8e 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -12,4 +12,5 @@ public interface ErrorCodeConstants { // ========== 产品相关 1-050-001-000 ============ ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_050_001_000, "产品不存在"); ErrorCode PRODUCT_IDENTIFICATION_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在"); + ErrorCode PRODUCT_STATUS_NOT_DELETE = new ErrorCode(1_050_001_002, "产品状是发布状态,不允许删除"); } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java index 38316371b..b10cee46f 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java @@ -6,13 +6,13 @@ import lombok.Getter; /** * IOT 产品状态枚举类 - * 产品状态, 0: 未发布, 1: 已发布 + * 产品状态, 0: 开发中, 1: 已发布 */ @AllArgsConstructor @Getter public enum IotProductStatusEnum implements IntArrayValuable { - UNPUBLISHED(0, "未发布"), + UNPUBLISHED(0, "开发中"), PUBLISHED(1, "已发布"); /** diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/ProductController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/ProductController.java index 9acce0234..f6d7e494d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/ProductController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/ProductController.java @@ -51,6 +51,17 @@ public class ProductController { return success(true); } + @PutMapping("/update-status") + @Operation(summary = "更新产品状态") + @Parameter(name = "id", description = "编号", required = true) + @Parameter(name = "status", description = "状态", required = true) + @PreAuthorize("@ss.hasPermission('iot:product:update')") + public CommonResult updateProductStatus(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + productService.updateProductStatus(id, status); + return success(true); + } + @DeleteMapping("/delete") @Operation(summary = "删除产品") @Parameter(name = "id", description = "编号", required = true) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java index 049ba26ce..cc1ffce81 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java @@ -51,4 +51,11 @@ public interface ProductService { */ PageResult getProductPage(ProductPageReqVO pageReqVO); + /** + * 更新产品状态 + * + * @param id 编号 + * @param status 状态 + */ + void updateProductStatus(Long id, Integer status); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java index b2ca76213..b692faa71 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java @@ -6,14 +6,17 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.ProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.product.ProductMapper; +import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.Objects; import java.util.UUID; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_STATUS_NOT_DELETE; /** * IOT 产品 Service 实现类 @@ -62,6 +65,8 @@ public class ProductServiceImpl implements ProductService { public void deleteProduct(Long id) { // 校验存在 validateProductExists(id); + // 发布状态不可删除 + validateProductStatus(id); // 删除 productMapper.deleteById(id); } @@ -72,6 +77,13 @@ public class ProductServiceImpl implements ProductService { } } + private void validateProductStatus(Long id) { + ProductDO product = productMapper.selectById(id); + if (Objects.equals(product.getStatus(), IotProductStatusEnum.PUBLISHED.getType())) { + throw exception(PRODUCT_STATUS_NOT_DELETE); + } + } + @Override public ProductDO getProduct(Long id) { return productMapper.selectById(id); @@ -82,4 +94,13 @@ public class ProductServiceImpl implements ProductService { return productMapper.selectPage(pageReqVO); } + @Override + public void updateProductStatus(Long id, Integer status) { + // 校验存在 + validateProductExists(id); + // 更新 + ProductDO updateObj = ProductDO.builder().id(id).status(status).build(); + productMapper.updateById(updateObj); + } + } \ No newline at end of file From 10334f3fb69271ebacfeed4e1297aa6c0dcc30d9 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 7 Sep 2024 20:37:13 +0800 Subject: [PATCH 08/31] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IOT=EF=BC=9A=E4=BA=A7=E5=93=81=E7=9A=84?= =?UTF-8?q?=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-dependencies/pom.xml | 2 +- yudao-module-iot/pom.xml | 1 + .../yudao/module/iot/api/package-info.java | 4 +- .../iot/enums/product/IotDataFormatEnum.java | 9 +- .../iot/enums/product/IotNetTypeEnum.java | 7 +- .../product/IotProductDeviceTypeEnum.java | 5 +- .../enums/product/IotProductStatusEnum.java | 13 +- .../enums/product/IotProtocolTypeEnum.java | 7 +- .../enums/product/IotValidateTypeEnum.java | 7 +- yudao-module-iot/yudao-module-iot-biz/pom.xml | 5 +- .../admin/product/ProductController.java | 1 + .../admin/product/vo/ProductPageReqVO.java | 26 +-- .../admin/product/vo/ProductRespVO.java | 44 ++--- .../iot/dal/dataobject/product/ProductDO.java | 66 ++++--- .../iot/dal/mysql/product/ProductMapper.java | 2 +- .../module/iot/emq/callback/EmqxCallback.java | 1 + .../module/iot/emq/config/MqttConfig.java | 2 + .../module/iot/emq/service/EmqxService.java | 1 + .../iot/emq/service/EmqxServiceImpl.java | 2 + .../yudao/module/iot/emq/start/EmqxStart.java | 2 + .../module/iot/framework/package-info.java | 2 +- .../web/config/IotWebConfiguration.java | 2 +- .../iot/service/product/ProductService.java | 2 +- .../service/product/ProductServiceImpl.java | 13 +- .../mapper/product/ProductMapper.xml | 12 -- .../product/ProductServiceImplTest.java | 174 ------------------ .../src/main/resources/application-dev.yaml | 2 +- .../src/main/resources/application-local.yaml | 2 +- 28 files changed, 135 insertions(+), 281 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/product/ProductMapper.xml delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImplTest.java diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 07d144f53..bd0ad26bc 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -622,7 +622,7 @@ ${xercesImpl.version} - + org.eclipse.paho org.eclipse.paho.client.mqttv3 diff --git a/yudao-module-iot/pom.xml b/yudao-module-iot/pom.xml index 96f8d181f..069af1699 100644 --- a/yudao-module-iot/pom.xml +++ b/yudao-module-iot/pom.xml @@ -19,6 +19,7 @@ ${project.artifactId} 物联网模块 + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java index 65d049636..7da0c665b 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java @@ -1,4 +1,6 @@ /** - * iot API 包,定义暴露给其它模块的 API + * 占位 + * + * TODO 芋艿:后续删除 */ package cn.iocoder.yudao.module.iot.api; diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotDataFormatEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotDataFormatEnum.java index 4b0f15e05..8a1afa070 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotDataFormatEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotDataFormatEnum.java @@ -8,7 +8,9 @@ import java.util.Arrays; /** * 产品数据格式枚举类 - * 数据格式, 0: 标准数据格式(JSON), 1: 透传/自定义 + * + * @author ahh + * @see 阿里云 - 什么是消息解析 */ @AllArgsConstructor @Getter @@ -17,18 +19,17 @@ public enum IotDataFormatEnum implements IntArrayValuable { JSON(0, "标准数据格式(JSON)"), CUSTOMIZE(1, "透传/自定义"); + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotDataFormatEnum::getType).toArray(); + /** * 类型 */ private final Integer type; - /** * 描述 */ private final String description; - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotDataFormatEnum::getType).toArray(); - @Override public int[] array() { return ARRAYS; diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java index aef8999be..718e86d13 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java @@ -8,7 +8,8 @@ import java.util.Arrays; /** * IOT 联网方式枚举类 - * 联网方式, 0: Wi-Fi, 1: Cellular, 2: Ethernet, 3: 其他 + * + * @author ahh */ @AllArgsConstructor @Getter @@ -19,19 +20,17 @@ public enum IotNetTypeEnum implements IntArrayValuable { ETHERNET(2, "Ethernet"), OTHER(3, "其他"); + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotNetTypeEnum::getType).toArray(); /** * 类型 */ private final Integer type; - /** * 描述 */ private final String description; - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotNetTypeEnum::getType).toArray(); - @Override public int[] array() { return ARRAYS; diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java index 37ce0b5ad..99b75f3fb 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java @@ -7,8 +7,9 @@ import lombok.Getter; import java.util.Arrays; /** - * IOT 产品设备类型 - * 设备类型, 0: 直连设备, 1: 网关子设备, 2: 网关设备 + * IOT 产品的设备类型 + * + * @author ahh */ @AllArgsConstructor @Getter diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java index b10cee46f..e64a3d678 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java @@ -4,9 +4,12 @@ import cn.iocoder.yudao.framework.common.core.IntArrayValuable; import lombok.AllArgsConstructor; import lombok.Getter; +import java.util.Arrays; + /** - * IOT 产品状态枚举类 - * 产品状态, 0: 开发中, 1: 已发布 + * IOT 产品的状态枚举类 + * + * @author ahh */ @AllArgsConstructor @Getter @@ -15,20 +18,20 @@ public enum IotProductStatusEnum implements IntArrayValuable { UNPUBLISHED(0, "开发中"), PUBLISHED(1, "已发布"); + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotProductStatusEnum::getType).toArray(); + /** * 类型 */ private final Integer type; - /** * 描述 */ private final String description; - public static final int[] ARRAYS = {1, 2}; - @Override public int[] array() { return ARRAYS; } + } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProtocolTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProtocolTypeEnum.java index 64644b213..c36a37723 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProtocolTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProtocolTypeEnum.java @@ -8,7 +8,8 @@ import java.util.Arrays; /** * IOT 接入网关协议枚举类 - * 接入网关协议, 0: 自定义, 1: Modbus, 2: OPC UA, 3: ZigBee, 4: BLE + * + * @author ahh */ @AllArgsConstructor @Getter @@ -20,19 +21,17 @@ public enum IotProtocolTypeEnum implements IntArrayValuable { ZIGBEE(3, "ZigBee"), BLE(4, "BLE"); + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotProtocolTypeEnum::getType).toArray(); /** * 类型 */ private final Integer type; - /** * 描述 */ private final String description; - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotProtocolTypeEnum::getType).toArray(); - @Override public int[] array() { return ARRAYS; diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotValidateTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotValidateTypeEnum.java index 3b27b0d36..9a8092b7b 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotValidateTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotValidateTypeEnum.java @@ -8,7 +8,8 @@ import java.util.Arrays; /** * IOT 数据校验级别枚举类 - * 数据校验级别, 0: 弱校验, 1: 免校验 + * + * @author ahh */ @AllArgsConstructor @Getter @@ -17,19 +18,17 @@ public enum IotValidateTypeEnum implements IntArrayValuable { WEAK(0, "弱校验"), NONE(1, "免校验"); + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotValidateTypeEnum::getType).toArray(); /** * 类型 */ private final Integer type; - /** * 描述 */ private final String description; - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotValidateTypeEnum::getType).toArray(); - @Override public int[] array() { return ARRAYS; diff --git a/yudao-module-iot/yudao-module-iot-biz/pom.xml b/yudao-module-iot/yudao-module-iot-biz/pom.xml index 25a97a1b1..e3f93086a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/pom.xml +++ b/yudao-module-iot/yudao-module-iot-biz/pom.xml @@ -15,9 +15,10 @@ ${project.artifactId} 物联网 模块,主要实现 产品管理、设备管理、协议管理等功能。 + - + cn.iocoder.boot yudao-module-iot-api @@ -53,7 +54,7 @@ yudao-spring-boot-starter-excel - + org.eclipse.paho org.eclipse.paho.client.mqttv3 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/ProductController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/ProductController.java index f6d7e494d..7e68d2c20 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/ProductController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/ProductController.java @@ -27,6 +27,7 @@ import java.util.List; import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +// TODO @haohao:Iot 前缀要加,不然很容易重复哈 @Tag(name = "管理后台 - IOT 产品") @RestController @RequestMapping("/iot/product") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductPageReqVO.java index 4479d5218..dc0ae9d65 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductPageReqVO.java @@ -1,14 +1,18 @@ package cn.iocoder.yudao.module.iot.controller.admin.product.vo; -import lombok.*; -import java.util.*; -import io.swagger.v3.oas.annotations.media.Schema; import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; import org.springframework.format.annotation.DateTimeFormat; + import java.time.LocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +// TODO @haohao:涉及到 iot 的拼写,要不都用 IoT,貌似更规范 +// TODO 芋艿:需要清理掉一些无用字段 @Schema(description = "管理后台 - iot 产品分页 Request VO") @Data @EqualsAndHashCode(callSuper = true) @@ -25,6 +29,9 @@ public class ProductPageReqVO extends PageParam { @Schema(description = "产品标识") private String productKey; + @Schema(description = "接入网关协议", example = "2") + private Integer protocolType; + @Schema(description = "协议编号(脚本解析 id)", example = "13177") private Long protocolId; @@ -34,22 +41,19 @@ public class ProductPageReqVO extends PageParam { @Schema(description = "产品描述", example = "你猜") private String description; - @Schema(description = "数据校验级别, 0: 强校验, 1: 弱校验, 2: 免校验", example = "1") + @Schema(description = "数据校验级别", example = "1") private Integer validateType; - @Schema(description = "产品状态, 0: DEVELOPMENT_STATUS, 1: RELEASE_STATUS", example = "1") + @Schema(description = "产品状态", example = "1") private Integer status; - @Schema(description = "设备类型, 0: 直连设备, 1: 网关子设备, 2: 网关设备", example = "2") + @Schema(description = "设备类型", example = "2") private Integer deviceType; - @Schema(description = "联网方式, 0: Wi-Fi, 1: Cellular, 2: Ethernet, 3: 其他", example = "2") + @Schema(description = "联网方式", example = "2") private Integer netType; - @Schema(description = "接入网关协议, 0: modbus, 1: opc-ua, 2: customize, 3: ble, 4: zigbee", example = "2") - private Integer protocolType; - - @Schema(description = "数据格式, 0: 透传模式, 1: Alink JSON") + @Schema(description = "数据格式", example = "0") private Integer dataFormat; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductRespVO.java index 64aeeac13..1a60f0290 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductRespVO.java @@ -1,17 +1,21 @@ package cn.iocoder.yudao.module.iot.controller.admin.product.vo; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; -import java.util.*; -import org.springframework.format.annotation.DateTimeFormat; +import lombok.Data; + import java.time.LocalDateTime; -import com.alibaba.excel.annotation.*; @Schema(description = "管理后台 - iot 产品 Response VO") @Data @ExcelIgnoreUnannotated public class ProductRespVO { + @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26087") + @ExcelProperty("产品ID") + private Long id; + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") @ExcelProperty("产品名称") private String name; @@ -20,14 +24,14 @@ public class ProductRespVO { @ExcelProperty("创建时间") private LocalDateTime createTime; - @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26087") - @ExcelProperty("产品ID") - private Long id; - @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("产品标识") private String productKey; + @Schema(description = "接入网关协议", example = "2") + @ExcelProperty("接入网关协议") + private Integer protocolType; + @Schema(description = "协议编号(脚本解析 id)", requiredMode = Schema.RequiredMode.REQUIRED, example = "13177") @ExcelProperty("协议编号(脚本解析 id)") private Long protocolId; @@ -40,28 +44,24 @@ public class ProductRespVO { @ExcelProperty("产品描述") private String description; - @Schema(description = "数据校验级别, 0: 强校验, 1: 弱校验, 2: 免校验", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @ExcelProperty("数据校验级别, 0: 强校验, 1: 弱校验, 2: 免校验") + @Schema(description = "数据校验级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("数据校验级别") private Integer validateType; - @Schema(description = "产品状态, 0: DEVELOPMENT_STATUS, 1: RELEASE_STATUS", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @ExcelProperty("产品状态, 0: DEVELOPMENT_STATUS, 1: RELEASE_STATUS") + @Schema(description = "产品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("产品状态") private Integer status; - @Schema(description = "设备类型, 0: 直连设备, 1: 网关子设备, 2: 网关设备", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @ExcelProperty("设备类型, 0: 直连设备, 1: 网关子设备, 2: 网关设备") + @Schema(description = "设备类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("设备类型") private Integer deviceType; - @Schema(description = "联网方式, 0: Wi-Fi, 1: Cellular, 2: Ethernet, 3: 其他", example = "2") - @ExcelProperty("联网方式, 0: Wi-Fi, 1: Cellular, 2: Ethernet, 3: 其他") + @Schema(description = "联网方式", example = "2") + @ExcelProperty("联网方式") private Integer netType; - @Schema(description = "接入网关协议, 0: modbus, 1: opc-ua, 2: customize, 3: ble, 4: zigbee", example = "2") - @ExcelProperty("接入网关协议, 0: modbus, 1: opc-ua, 2: customize, 3: ble, 4: zigbee") - private Integer protocolType; - - @Schema(description = "数据格式, 0: 透传模式, 1: Alink JSON") - @ExcelProperty("数据格式, 0: 透传模式, 1: Alink JSON") + @Schema(description = "数据格式") + @ExcelProperty("数据格式") private Integer dataFormat; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/ProductDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/ProductDO.java index d6a79d8c5..37c1eb513 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/ProductDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/ProductDO.java @@ -1,16 +1,15 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.product; -import lombok.*; -import java.util.*; -import java.time.LocalDateTime; -import java.time.LocalDateTime; -import com.baomidou.mybatisplus.annotation.*; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; /** * iot 产品 DO * - * @author 芋道源码 + * @author ahh */ @TableName("iot_product") @KeySequence("iot_product_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @@ -22,54 +21,73 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; @AllArgsConstructor public class ProductDO extends BaseDO { - /** - * 产品名称 - */ - private String name; /** * 产品ID */ @TableId private Long id; + /** + * 产品名称 + */ + private String name; + // TODO @haohao:这个字段,要不改成 identifier,和阿里云更统一些 /** * 产品标识 */ private String productKey; /** - * 协议编号(脚本解析 id) - */ - private Long protocolId; - /** - * 产品所属品类标识符 + * 产品所属品类编号 + * + * TODO 外键:后续加 */ private Long categoryId; /** * 产品描述 */ private String description; + /** - * 数据校验级别, 0: 强校验, 1: 弱校验, 2: 免校验 - */ - private Integer validateType; - /** - * 产品状态, 0: DEVELOPMENT_STATUS, 1: RELEASE_STATUS + * 产品状态 + * + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum} */ private Integer status; /** - * 设备类型, 0: 直连设备, 1: 网关子设备, 2: 网关设备 + * 设备类型 + * + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum} */ private Integer deviceType; /** - * 联网方式, 0: Wi-Fi, 1: Cellular, 2: Ethernet, 3: 其他 + * 联网方式 + * + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotNetTypeEnum} */ private Integer netType; + /** - * 接入网关协议, 0: modbus, 1: opc-ua, 2: customize, 3: ble, 4: zigbee + * 接入网关协议 + * + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotProtocolTypeEnum} */ private Integer protocolType; /** - * 数据格式, 0: 透传模式, 1: Alink JSON + * 协议编号 + * + * TODO 外键:后续加 + */ + private Long protocolId; + /** + * 数据格式 + * + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotDataFormatEnum} */ private Integer dataFormat; + /** + * 数据校验级别 + * + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotValidateTypeEnum} + */ + private Integer validateType; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java index b8e80b7a3..d9af9b4b9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java @@ -10,7 +10,7 @@ import org.apache.ibatis.annotations.Mapper; /** * iot 产品 Mapper * - * @author 芋道源码 + * @author ahh */ @Mapper public interface ProductMapper extends BaseMapperX { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/callback/EmqxCallback.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/callback/EmqxCallback.java index a34863a17..b466113f7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/callback/EmqxCallback.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/callback/EmqxCallback.java @@ -10,6 +10,7 @@ import org.eclipse.paho.client.mqttv3.MqttMessage; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; +// TODO @芋艿:详细再瞅瞅 /** * 用于处理MQTT连接的回调,如连接断开、消息到达、消息发布完成、连接完成等事件。 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/config/MqttConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/config/MqttConfig.java index ae1557c23..9d128903c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/config/MqttConfig.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/config/MqttConfig.java @@ -4,6 +4,8 @@ import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; +// TODO @芋艿:详细再瞅瞅 + /** * 配置类,用于读取MQTT连接的配置信息,如用户名、密码、连接地址等 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxService.java index 1658dc376..0d564c39f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxService.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.emq.service; import org.eclipse.paho.client.mqttv3.MqttClient; import org.eclipse.paho.client.mqttv3.MqttMessage; +// TODO @芋艿:在瞅瞅 /** * 用于处理MQTT消息的具体业务逻辑,如订阅回调 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java index a18bb73e1..0f1a53cd0 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java @@ -5,6 +5,8 @@ import org.eclipse.paho.client.mqttv3.MqttClient; import org.eclipse.paho.client.mqttv3.MqttMessage; import org.springframework.stereotype.Service; +// TODO @芋艿:在瞅瞅 + /** * 用于处理MQTT消息的具体业务逻辑,如订阅回调 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/start/EmqxStart.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/start/EmqxStart.java index f954cb588..0c316b66c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/start/EmqxStart.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/start/EmqxStart.java @@ -6,6 +6,8 @@ import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; +// TODO @芋艿:在瞅瞅 + /** * 用于在应用启动时自动连接MQTT服务器 * diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/package-info.java index 9d8ffe73d..234cad870 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/package-info.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/package-info.java @@ -1,6 +1,6 @@ /** * 属于 iot 模块的 framework 封装 * - * @author 芋道源码 + * @author ahh */ package cn.iocoder.yudao.module.iot.framework; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/web/config/IotWebConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/web/config/IotWebConfiguration.java index 890e60c7c..6b3cc6ae5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/web/config/IotWebConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/web/config/IotWebConfiguration.java @@ -8,7 +8,7 @@ import org.springframework.context.annotation.Configuration; /** * iot 模块的 web 组件的 Configuration * - * @author 芋道源码 + * @author ahh */ @Configuration(proxyBeanMethods = false) public class IotWebConfiguration { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java index cc1ffce81..8d4fdf801 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java @@ -9,7 +9,7 @@ import jakarta.validation.Valid; /** * IOT 产品 Service 接口 * - * @author 芋道源码 + * @author ahh */ public interface ProductService { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java index b692faa71..e5e3bc421 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java @@ -21,7 +21,7 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_STATU /** * IOT 产品 Service 实现类 * - * @author 芋道源码 + * @author ahh */ @Service @Validated @@ -37,7 +37,6 @@ public class ProductServiceImpl implements ProductService { // 插入 ProductDO product = BeanUtils.toBean(createReqVO, ProductDO.class); productMapper.insert(product); - // 返回 return product.getId(); } @@ -47,6 +46,7 @@ public class ProductServiceImpl implements ProductService { * @param createReqVO 创建信息 */ private void createProductKey(ProductSaveReqVO createReqVO) { + // TODO @haohao:应该前端没传递的时候,才生成哇?ps:需要校验下唯一性,万一有重复; // 生成随机的 11 位字符串 String productKey = UUID.randomUUID().toString().replace("-", "").substring(0, 11); createReqVO.setProductKey(productKey); @@ -54,8 +54,10 @@ public class ProductServiceImpl implements ProductService { @Override public void updateProduct(ProductSaveReqVO updateReqVO) { + updateReqVO.setProductKey(null); // 不更新产品标识 // 校验存在 validateProductExists(updateReqVO.getId()); + // TODO @haohao:如果已经发布,允许编辑么? // 更新 ProductDO updateObj = BeanUtils.toBean(updateReqVO, ProductDO.class); productMapper.updateById(updateObj); @@ -63,11 +65,12 @@ public class ProductServiceImpl implements ProductService { @Override public void deleteProduct(Long id) { - // 校验存在 + // TODO @haohao:这里最好只查询一次哈 + // 1.1 校验存在 validateProductExists(id); - // 发布状态不可删除 + // 1.2 发布状态不可删除 validateProductStatus(id); - // 删除 + // 2. 删除 productMapper.deleteById(id); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/product/ProductMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/product/ProductMapper.xml deleted file mode 100644 index 69352f8ea..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/product/ProductMapper.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImplTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImplTest.java deleted file mode 100644 index 244cda607..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImplTest.java +++ /dev/null @@ -1,174 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.product; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.mock.mockito.MockBean; - -import jakarta.annotation.Resource; - -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; - -import cn.iocoder.yudao.module.iot.controller.admin.product.vo.*; -import cn.iocoder.yudao.module.iot.dal.dataobject.product.ProductDO; -import cn.iocoder.yudao.module.iot.dal.mysql.product.ProductMapper; -import cn.iocoder.yudao.framework.common.pojo.PageResult; - -import jakarta.annotation.Resource; -import org.springframework.context.annotation.Import; -import java.util.*; -import java.time.LocalDateTime; - -import static cn.hutool.core.util.RandomUtil.*; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; -import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; - -/** - * {@link ProductServiceImpl} 的单元测试类 - * - * @author 芋道源码 - */ -@Import(ProductServiceImpl.class) -public class ProductServiceImplTest extends BaseDbUnitTest { - - @Resource - private ProductServiceImpl productService; - - @Resource - private ProductMapper productMapper; - - @Test - public void testCreateProduct_success() { - // 准备参数 - ProductSaveReqVO createReqVO = randomPojo(ProductSaveReqVO.class).setId(null); - - // 调用 - Long productId = productService.createProduct(createReqVO); - // 断言 - assertNotNull(productId); - // 校验记录的属性是否正确 - ProductDO product = productMapper.selectById(productId); - assertPojoEquals(createReqVO, product, "id"); - } - - @Test - public void testUpdateProduct_success() { - // mock 数据 - ProductDO dbProduct = randomPojo(ProductDO.class); - productMapper.insert(dbProduct);// @Sql: 先插入出一条存在的数据 - // 准备参数 - ProductSaveReqVO updateReqVO = randomPojo(ProductSaveReqVO.class, o -> { - o.setId(dbProduct.getId()); // 设置更新的 ID - }); - - // 调用 - productService.updateProduct(updateReqVO); - // 校验是否更新正确 - ProductDO product = productMapper.selectById(updateReqVO.getId()); // 获取最新的 - assertPojoEquals(updateReqVO, product); - } - - @Test - public void testUpdateProduct_notExists() { - // 准备参数 - ProductSaveReqVO updateReqVO = randomPojo(ProductSaveReqVO.class); - - // 调用, 并断言异常 - assertServiceException(() -> productService.updateProduct(updateReqVO), PRODUCT_NOT_EXISTS); - } - - @Test - public void testDeleteProduct_success() { - // mock 数据 - ProductDO dbProduct = randomPojo(ProductDO.class); - productMapper.insert(dbProduct);// @Sql: 先插入出一条存在的数据 - // 准备参数 - Long id = dbProduct.getId(); - - // 调用 - productService.deleteProduct(id); - // 校验数据不存在了 - assertNull(productMapper.selectById(id)); - } - - @Test - public void testDeleteProduct_notExists() { - // 准备参数 - Long id = randomLongId(); - - // 调用, 并断言异常 - assertServiceException(() -> productService.deleteProduct(id), PRODUCT_NOT_EXISTS); - } - - @Test - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 - public void testGetProductPage() { - // mock 数据 - ProductDO dbProduct = randomPojo(ProductDO.class, o -> { // 等会查询到 - o.setName(null); - o.setCreateTime(null); - o.setProductKey(null); - o.setProtocolId(null); - o.setCategoryId(null); - o.setDescription(null); - o.setValidateType(null); - o.setStatus(null); - o.setDeviceType(null); - o.setNetType(null); - o.setProtocolType(null); - o.setDataFormat(null); - }); - productMapper.insert(dbProduct); - // 测试 name 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setName(null))); - // 测试 createTime 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setCreateTime(null))); - // 测试 productKey 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setProductKey(null))); - // 测试 protocolId 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setProtocolId(null))); - // 测试 categoryId 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setCategoryId(null))); - // 测试 description 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setDescription(null))); - // 测试 validateType 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setValidateType(null))); - // 测试 status 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setStatus(null))); - // 测试 deviceType 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setDeviceType(null))); - // 测试 netType 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setNetType(null))); - // 测试 protocolType 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setProtocolType(null))); - // 测试 dataFormat 不匹配 - productMapper.insert(cloneIgnoreId(dbProduct, o -> o.setDataFormat(null))); - // 准备参数 - ProductPageReqVO reqVO = new ProductPageReqVO(); - reqVO.setName(null); - reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); - reqVO.setProductKey(null); - reqVO.setProtocolId(null); - reqVO.setCategoryId(null); - reqVO.setDescription(null); - reqVO.setValidateType(null); - reqVO.setStatus(null); - reqVO.setDeviceType(null); - reqVO.setNetType(null); - reqVO.setProtocolType(null); - reqVO.setDataFormat(null); - - // 调用 - PageResult pageResult = productService.getProductPage(reqVO); - // 断言 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - assertPojoEquals(dbProduct, pageResult.getList().get(0)); - } - -} \ No newline at end of file diff --git a/yudao-server/src/main/resources/application-dev.yaml b/yudao-server/src/main/resources/application-dev.yaml index 3e7f4e76a..27f12107d 100644 --- a/yudao-server/src/main/resources/application-dev.yaml +++ b/yudao-server/src/main/resources/application-dev.yaml @@ -196,7 +196,7 @@ justauth: timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟 ---- #################### iot相关配置 #################### +--- #################### iot相关配置 TODO 芋艿:再瞅瞅 #################### iot: emq: # 账号 diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index 27588d045..5cdc511a0 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -250,7 +250,7 @@ justauth: prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE:: timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟 ---- #################### iot相关配置 #################### +--- #################### iot相关配置 TODO 芋艿:再瞅瞅 #################### iot: emq: # 账号 From 1e69face929ced850c5aca1af0be5df01c3c36a5 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 7 Sep 2024 20:38:49 +0800 Subject: [PATCH 09/31] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IOT=EF=BC=9A=E4=BA=A7=E5=93=81=E7=9A=84?= =?UTF-8?q?=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 6 +++--- yudao-server/pom.xml | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index 4de660fed..c7217c41b 100644 --- a/pom.xml +++ b/pom.xml @@ -15,16 +15,16 @@ yudao-module-system yudao-module-infra - yudao-module-iot - yudao-module-bpm + - yudao-module-crm + + yudao-module-iot ${project.artifactId} diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml index 3fe8ef48d..3d4676d26 100644 --- a/yudao-server/pom.xml +++ b/yudao-server/pom.xml @@ -46,11 +46,11 @@ - - cn.iocoder.boot - yudao-module-bpm-biz - ${revision} - + + + + + @@ -88,11 +88,11 @@ - - cn.iocoder.boot - yudao-module-crm-biz - ${revision} - + + + + + From a83ce3b667be12ea9662f62bf0b8c2c455e01ece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sun, 8 Sep 2024 15:53:53 +0800 Subject: [PATCH 10/31] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9A=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20IOT=20=E5=89=8D=E7=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...troller.java => IotProductController.java} | 44 +++---- .../admin/product/vo/IotProductPageReqVO.java | 22 ++++ ...oductRespVO.java => IotProductRespVO.java} | 2 +- ...aveReqVO.java => IotProductSaveReqVO.java} | 14 +-- .../admin/product/vo/ProductPageReqVO.java | 59 --------- .../{ProductDO.java => IotProductDO.java} | 18 +-- .../dal/mysql/product/IotProductMapper.java | 28 +++++ .../iot/dal/mysql/product/ProductMapper.java | 35 ------ ...uctService.java => IotProductService.java} | 16 +-- .../product/IotProductServiceImpl.java | 117 ++++++++++++++++++ .../service/product/ProductServiceImpl.java | 109 ---------------- 11 files changed, 207 insertions(+), 257 deletions(-) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/{ProductController.java => IotProductController.java} (64%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductPageReqVO.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/{ProductRespVO.java => IotProductRespVO.java} (98%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/{ProductSaveReqVO.java => IotProductSaveReqVO.java} (85%) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductPageReqVO.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/{ProductDO.java => IotProductDO.java} (94%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/{ProductService.java => IotProductService.java} (62%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/ProductController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java similarity index 64% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/ProductController.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java index 7e68d2c20..fe2f1de17 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/ProductController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java @@ -6,11 +6,11 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; -import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.product.ProductDO; -import cn.iocoder.yudao.module.iot.service.product.ProductService; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import cn.iocoder.yudao.module.iot.service.product.IotProductService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -27,27 +27,26 @@ import java.util.List; import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -// TODO @haohao:Iot 前缀要加,不然很容易重复哈 @Tag(name = "管理后台 - IOT 产品") @RestController @RequestMapping("/iot/product") @Validated -public class ProductController { +public class IotProductController { @Resource - private ProductService productService; + private IotProductService productService; @PostMapping("/create") @Operation(summary = "创建产品") @PreAuthorize("@ss.hasPermission('iot:product:create')") - public CommonResult createProduct(@Valid @RequestBody ProductSaveReqVO createReqVO) { + public CommonResult createProduct(@Valid @RequestBody IotProductSaveReqVO createReqVO) { return success(productService.createProduct(createReqVO)); } @PutMapping("/update") @Operation(summary = "更新产品") @PreAuthorize("@ss.hasPermission('iot:product:update')") - public CommonResult updateProduct(@Valid @RequestBody ProductSaveReqVO updateReqVO) { + public CommonResult updateProduct(@Valid @RequestBody IotProductSaveReqVO updateReqVO) { productService.updateProduct(updateReqVO); return success(true); } @@ -76,30 +75,17 @@ public class ProductController { @Operation(summary = "获得产品") @Parameter(name = "id", description = "编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('iot:product:query')") - public CommonResult getProduct(@RequestParam("id") Long id) { - ProductDO product = productService.getProduct(id); - return success(BeanUtils.toBean(product, ProductRespVO.class)); + public CommonResult getProduct(@RequestParam("id") Long id) { + IotProductDO product = productService.getProduct(id); + return success(BeanUtils.toBean(product, IotProductRespVO.class)); } @GetMapping("/page") @Operation(summary = "获得产品分页") @PreAuthorize("@ss.hasPermission('iot:product:query')") - public CommonResult> getProductPage(@Valid ProductPageReqVO pageReqVO) { - PageResult pageResult = productService.getProductPage(pageReqVO); - return success(BeanUtils.toBean(pageResult, ProductRespVO.class)); - } - - @GetMapping("/export-excel") - @Operation(summary = "导出产品 Excel") - @PreAuthorize("@ss.hasPermission('iot:product:export')") - @ApiAccessLog(operateType = EXPORT) - public void exportProductExcel(@Valid ProductPageReqVO pageReqVO, - HttpServletResponse response) throws IOException { - pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); - List list = productService.getProductPage(pageReqVO).getList(); - // 导出 Excel - ExcelUtils.write(response, "产品.xls", "数据", ProductRespVO.class, - BeanUtils.toBean(list, ProductRespVO.class)); + public CommonResult> getProductPage(@Valid IotProductPageReqVO pageReqVO) { + PageResult pageResult = productService.getProductPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotProductRespVO.class)); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductPageReqVO.java new file mode 100644 index 000000000..afc3aafa0 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductPageReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.iot.controller.admin.product.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +// TODO @haohao:涉及到 iot 的拼写,要不都用 IoT,貌似更规范 +@Schema(description = "管理后台 - iot 产品分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class IotProductPageReqVO extends PageParam { + + @Schema(description = "产品名称", example = "李四") + private String name; + + @Schema(description = "产品标识") + private String productKey; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductRespVO.java similarity index 98% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductRespVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductRespVO.java index 1a60f0290..066efca93 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductRespVO.java @@ -10,7 +10,7 @@ import java.time.LocalDateTime; @Schema(description = "管理后台 - iot 产品 Response VO") @Data @ExcelIgnoreUnannotated -public class ProductRespVO { +public class IotProductRespVO { @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26087") @ExcelProperty("产品ID") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java similarity index 85% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java index ecbbb03c9..ad01bcd03 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java @@ -3,13 +3,13 @@ package cn.iocoder.yudao.module.iot.controller.admin.product.vo; import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.enums.product.*; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; -import java.util.*; -import jakarta.validation.constraints.*; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; @Schema(description = "管理后台 - iot 产品新增/修改 Request VO") @Data -public class ProductSaveReqVO { +public class IotProductSaveReqVO { @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.AUTO, example = "1") private Long id; @@ -26,15 +26,15 @@ public class ProductSaveReqVO { @NotNull(message = "设备类型不能为空") private Integer deviceType; - @Schema(description = "联网方式", requiredMode = Schema.RequiredMode.REQUIRED,example = "0") + @Schema(description = "联网方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") @InEnum(value = IotNetTypeEnum.class, message = "联网方式必须是 {value}") private Integer netType; - @Schema(description = "接入网关协议", requiredMode = Schema.RequiredMode.REQUIRED,example = "0") + @Schema(description = "接入网关协议", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") @InEnum(value = IotProtocolTypeEnum.class, message = "接入网关协议必须是 {value}") private Integer protocolType; - @Schema(description = "数据格式",requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @Schema(description = "数据格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") @InEnum(value = IotDataFormatEnum.class, message = "数据格式必须是 {value}") @NotNull(message = "数据格式不能为空") private Integer dataFormat; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductPageReqVO.java deleted file mode 100644 index dc0ae9d65..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/ProductPageReqVO.java +++ /dev/null @@ -1,59 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.product.vo; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; -import org.springframework.format.annotation.DateTimeFormat; - -import java.time.LocalDateTime; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; - -// TODO @haohao:涉及到 iot 的拼写,要不都用 IoT,貌似更规范 -// TODO 芋艿:需要清理掉一些无用字段 -@Schema(description = "管理后台 - iot 产品分页 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class ProductPageReqVO extends PageParam { - - @Schema(description = "产品名称", example = "李四") - private String name; - - @Schema(description = "创建时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] createTime; - - @Schema(description = "产品标识") - private String productKey; - - @Schema(description = "接入网关协议", example = "2") - private Integer protocolType; - - @Schema(description = "协议编号(脚本解析 id)", example = "13177") - private Long protocolId; - - @Schema(description = "产品所属品类标识符", example = "14237") - private Long categoryId; - - @Schema(description = "产品描述", example = "你猜") - private String description; - - @Schema(description = "数据校验级别", example = "1") - private Integer validateType; - - @Schema(description = "产品状态", example = "1") - private Integer status; - - @Schema(description = "设备类型", example = "2") - private Integer deviceType; - - @Schema(description = "联网方式", example = "2") - private Integer netType; - - @Schema(description = "数据格式", example = "0") - private Integer dataFormat; - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/ProductDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java similarity index 94% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/ProductDO.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java index 37c1eb513..1fa22c7d1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/ProductDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java @@ -19,7 +19,7 @@ import lombok.*; @Builder @NoArgsConstructor @AllArgsConstructor -public class ProductDO extends BaseDO { +public class IotProductDO extends BaseDO { /** * 产品ID @@ -37,7 +37,7 @@ public class ProductDO extends BaseDO { private String productKey; /** * 产品所属品类编号 - * + *

* TODO 外键:后续加 */ private Long categoryId; @@ -48,44 +48,44 @@ public class ProductDO extends BaseDO { /** * 产品状态 - * + *

* 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum} */ private Integer status; /** * 设备类型 - * + *

* 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum} */ private Integer deviceType; /** * 联网方式 - * + *

* 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotNetTypeEnum} */ private Integer netType; /** * 接入网关协议 - * + *

* 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotProtocolTypeEnum} */ private Integer protocolType; /** * 协议编号 - * + *

* TODO 外键:后续加 */ private Long protocolId; /** * 数据格式 - * + *

* 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotDataFormatEnum} */ private Integer dataFormat; /** * 数据校验级别 - * + *

* 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotValidateTypeEnum} */ private Integer validateType; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java new file mode 100644 index 000000000..111ed4969 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.product; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductPageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * iot 产品 Mapper + * + * @author ahh + */ +@Mapper +public interface IotProductMapper extends BaseMapperX { + + default PageResult selectPage(IotProductPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(IotProductDO::getName, reqVO.getName()) + .likeIfPresent(IotProductDO::getProductKey, reqVO.getProductKey()) + .orderByDesc(IotProductDO::getId)); + } + + default IotProductDO selectByProductKey(String productKey) { + return selectOne(new LambdaQueryWrapperX().eq(IotProductDO::getProductKey, productKey)); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java deleted file mode 100644 index d9af9b4b9..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/ProductMapper.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.mysql.product; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductPageReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.product.ProductDO; -import org.apache.ibatis.annotations.Mapper; - -/** - * iot 产品 Mapper - * - * @author ahh - */ -@Mapper -public interface ProductMapper extends BaseMapperX { - - default PageResult selectPage(ProductPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .likeIfPresent(ProductDO::getName, reqVO.getName()) - .betweenIfPresent(ProductDO::getCreateTime, reqVO.getCreateTime()) - .likeIfPresent(ProductDO::getProductKey, reqVO.getProductKey()) - .eqIfPresent(ProductDO::getProtocolId, reqVO.getProtocolId()) - .eqIfPresent(ProductDO::getCategoryId, reqVO.getCategoryId()) - .eqIfPresent(ProductDO::getDescription, reqVO.getDescription()) - .eqIfPresent(ProductDO::getValidateType, reqVO.getValidateType()) - .eqIfPresent(ProductDO::getStatus, reqVO.getStatus()) - .eqIfPresent(ProductDO::getDeviceType, reqVO.getDeviceType()) - .eqIfPresent(ProductDO::getNetType, reqVO.getNetType()) - .eqIfPresent(ProductDO::getProtocolType, reqVO.getProtocolType()) - .eqIfPresent(ProductDO::getDataFormat, reqVO.getDataFormat()) - .orderByDesc(ProductDO::getId)); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java similarity index 62% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java index 8d4fdf801..14f408030 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java @@ -1,9 +1,9 @@ package cn.iocoder.yudao.module.iot.service.product; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.product.ProductDO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import jakarta.validation.Valid; /** @@ -11,7 +11,7 @@ import jakarta.validation.Valid; * * @author ahh */ -public interface ProductService { +public interface IotProductService { /** * 创建产品 @@ -19,14 +19,14 @@ public interface ProductService { * @param createReqVO 创建信息 * @return 编号 */ - Long createProduct(@Valid ProductSaveReqVO createReqVO); + Long createProduct(@Valid IotProductSaveReqVO createReqVO); /** * 更新产品 * * @param updateReqVO 更新信息 */ - void updateProduct(@Valid ProductSaveReqVO updateReqVO); + void updateProduct(@Valid IotProductSaveReqVO updateReqVO); /** * 删除产品 @@ -41,7 +41,7 @@ public interface ProductService { * @param id 编号 * @return 产品 */ - ProductDO getProduct(Long id); + IotProductDO getProduct(Long id); /** * 获得产品分页 @@ -49,7 +49,7 @@ public interface ProductService { * @param pageReqVO 分页查询 * @return 产品分页 */ - PageResult getProductPage(ProductPageReqVO pageReqVO); + PageResult getProductPage(IotProductPageReqVO pageReqVO); /** * 更新产品状态 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java new file mode 100644 index 000000000..65686f533 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -0,0 +1,117 @@ +package cn.iocoder.yudao.module.iot.service.product; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductPageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; +import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.Objects; +import java.util.UUID; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_STATUS_NOT_DELETE; + +/** + * IOT 产品 Service 实现类 + * + * @author ahh + */ +@Service +@Validated +public class IotProductServiceImpl implements IotProductService { + + @Resource + private IotProductMapper productMapper; + + @Override + public Long createProduct(IotProductSaveReqVO createReqVO) { + // 1. 生成 ProductKey + createProductKey(createReqVO); + // 2. 插入 + IotProductDO product = BeanUtils.toBean(createReqVO, IotProductDO.class); + productMapper.insert(product); + return product.getId(); + } + + /** + * 创建 ProductKey + * + * @param createReqVO 创建信息 + */ + private void createProductKey(IotProductSaveReqVO createReqVO) { + String productKey = createReqVO.getProductKey(); + // 1. productKey为空,生成随机的 11 位字符串 + if (StrUtil.isEmpty(productKey)) { + productKey = UUID.randomUUID().toString().replace("-", "").substring(0, 11); + } + // 2. 校验唯一性 + if (productMapper.selectByProductKey(productKey) != null) { + throw exception(PRODUCT_NOT_EXISTS); + } + createReqVO.setProductKey(productKey); + } + + @Override + public void updateProduct(IotProductSaveReqVO updateReqVO) { + updateReqVO.setProductKey(null); // 不更新产品标识 + // 1.1 校验存在 + IotProductDO iotProductDO = validateProductExists(updateReqVO.getId()); + // 1.2 发布状态不可更新 + validateProductStatus(iotProductDO); + // 2. 更新 + IotProductDO updateObj = BeanUtils.toBean(updateReqVO, IotProductDO.class); + productMapper.updateById(updateObj); + } + + @Override + public void deleteProduct(Long id) { + // 1.1 校验存在 + IotProductDO iotProductDO = validateProductExists(id); + // 1.2 发布状态不可删除 + validateProductStatus(iotProductDO); + // 2. 删除 + productMapper.deleteById(id); + } + + private IotProductDO validateProductExists(Long id) { + IotProductDO iotProductDO = productMapper.selectById(id); + if (iotProductDO == null) { + throw exception(PRODUCT_NOT_EXISTS); + } + return iotProductDO; + } + + private void validateProductStatus(IotProductDO iotProductDO) { + if (Objects.equals(iotProductDO.getStatus(), IotProductStatusEnum.PUBLISHED.getType())) { + throw exception(PRODUCT_STATUS_NOT_DELETE); + } + } + + @Override + public IotProductDO getProduct(Long id) { + return productMapper.selectById(id); + } + + @Override + public PageResult getProductPage(IotProductPageReqVO pageReqVO) { + return productMapper.selectPage(pageReqVO); + } + + @Override + public void updateProductStatus(Long id, Integer status) { + // 1. 校验存在 + validateProductExists(id); + // 2. 更新 + IotProductDO updateObj = IotProductDO.builder().id(id).status(status).build(); + productMapper.updateById(updateObj); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java deleted file mode 100644 index e5e3bc421..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/ProductServiceImpl.java +++ /dev/null @@ -1,109 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.product; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductPageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.product.vo.ProductSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.product.ProductDO; -import cn.iocoder.yudao.module.iot.dal.mysql.product.ProductMapper; -import cn.iocoder.yudao.module.iot.enums.product.IotProductStatusEnum; -import jakarta.annotation.Resource; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import java.util.Objects; -import java.util.UUID; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_STATUS_NOT_DELETE; - -/** - * IOT 产品 Service 实现类 - * - * @author ahh - */ -@Service -@Validated -public class ProductServiceImpl implements ProductService { - - @Resource - private ProductMapper productMapper; - - @Override - public Long createProduct(ProductSaveReqVO createReqVO) { - // 生成 ProductKey - createProductKey(createReqVO); - // 插入 - ProductDO product = BeanUtils.toBean(createReqVO, ProductDO.class); - productMapper.insert(product); - return product.getId(); - } - - /** - * 创建 ProductKey - * - * @param createReqVO 创建信息 - */ - private void createProductKey(ProductSaveReqVO createReqVO) { - // TODO @haohao:应该前端没传递的时候,才生成哇?ps:需要校验下唯一性,万一有重复; - // 生成随机的 11 位字符串 - String productKey = UUID.randomUUID().toString().replace("-", "").substring(0, 11); - createReqVO.setProductKey(productKey); - } - - @Override - public void updateProduct(ProductSaveReqVO updateReqVO) { - updateReqVO.setProductKey(null); // 不更新产品标识 - // 校验存在 - validateProductExists(updateReqVO.getId()); - // TODO @haohao:如果已经发布,允许编辑么? - // 更新 - ProductDO updateObj = BeanUtils.toBean(updateReqVO, ProductDO.class); - productMapper.updateById(updateObj); - } - - @Override - public void deleteProduct(Long id) { - // TODO @haohao:这里最好只查询一次哈 - // 1.1 校验存在 - validateProductExists(id); - // 1.2 发布状态不可删除 - validateProductStatus(id); - // 2. 删除 - productMapper.deleteById(id); - } - - private void validateProductExists(Long id) { - if (productMapper.selectById(id) == null) { - throw exception(PRODUCT_NOT_EXISTS); - } - } - - private void validateProductStatus(Long id) { - ProductDO product = productMapper.selectById(id); - if (Objects.equals(product.getStatus(), IotProductStatusEnum.PUBLISHED.getType())) { - throw exception(PRODUCT_STATUS_NOT_DELETE); - } - } - - @Override - public ProductDO getProduct(Long id) { - return productMapper.selectById(id); - } - - @Override - public PageResult getProductPage(ProductPageReqVO pageReqVO) { - return productMapper.selectPage(pageReqVO); - } - - @Override - public void updateProductStatus(Long id, Integer status) { - // 校验存在 - validateProductExists(id); - // 更新 - ProductDO updateObj = ProductDO.builder().id(id).status(status).build(); - productMapper.updateById(updateObj); - } - -} \ No newline at end of file From 1aef8515e2ce87e539518752a11e8a13e98b09dc Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 10 Sep 2024 21:35:31 +0800 Subject: [PATCH 11/31] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IOT=EF=BC=9A=E4=BA=A7=E5=93=81=E7=9A=84?= =?UTF-8?q?=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/admin/product/IotProductController.java | 10 +--------- .../admin/product/vo/IotProductPageReqVO.java | 3 +-- .../controller/admin/product/vo/IotProductRespVO.java | 6 +++--- .../admin/product/vo/IotProductSaveReqVO.java | 2 +- .../iot/dal/dataobject/product/IotProductDO.java | 2 +- .../module/iot/dal/mysql/product/IotProductMapper.java | 2 +- .../module/iot/service/product/IotProductService.java | 2 +- .../iot/service/product/IotProductServiceImpl.java | 2 +- 8 files changed, 10 insertions(+), 19 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java index fe2f1de17..2a298e6a3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java @@ -1,11 +1,8 @@ package cn.iocoder.yudao.module.iot.controller.admin.product; -import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductRespVO; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSaveReqVO; @@ -15,19 +12,14 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import java.io.IOException; -import java.util.List; - -import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -@Tag(name = "管理后台 - IOT 产品") +@Tag(name = "管理后台 - IoT 产品") @RestController @RequestMapping("/iot/product") @Validated diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductPageReqVO.java index afc3aafa0..3437f563f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductPageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductPageReqVO.java @@ -6,8 +6,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; -// TODO @haohao:涉及到 iot 的拼写,要不都用 IoT,貌似更规范 -@Schema(description = "管理后台 - iot 产品分页 Request VO") +@Schema(description = "管理后台 - IoT 产品分页 Request VO") @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductRespVO.java index 066efca93..0958b3e84 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductRespVO.java @@ -7,13 +7,13 @@ import lombok.Data; import java.time.LocalDateTime; -@Schema(description = "管理后台 - iot 产品 Response VO") +@Schema(description = "管理后台 - IoT 产品 Response VO") @Data @ExcelIgnoreUnannotated public class IotProductRespVO { - @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26087") - @ExcelProperty("产品ID") + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26087") + @ExcelProperty("产品编号") private Long id; @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java index ad01bcd03..254b6b9da 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSaveReqVO.java @@ -7,7 +7,7 @@ import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; -@Schema(description = "管理后台 - iot 产品新增/修改 Request VO") +@Schema(description = "管理后台 - IoT 产品新增/修改 Request VO") @Data public class IotProductSaveReqVO { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java index 1fa22c7d1..eef466eda 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java @@ -7,7 +7,7 @@ import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; /** - * iot 产品 DO + * IoT 产品 DO * * @author ahh */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java index 111ed4969..694d7c007 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java @@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import org.apache.ibatis.annotations.Mapper; /** - * iot 产品 Mapper + * IoT 产品 Mapper * * @author ahh */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java index 14f408030..9677701f1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java @@ -7,7 +7,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import jakarta.validation.Valid; /** - * IOT 产品 Service 接口 + * IoT 产品 Service 接口 * * @author ahh */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index 65686f533..844e074d9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -20,7 +20,7 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_NOT_E import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_STATUS_NOT_DELETE; /** - * IOT 产品 Service 实现类 + * IoT 产品 Service 实现类 * * @author ahh */ From 18e789d4fb988dd4014a65fb4bda5ea90aa8307e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Wed, 11 Sep 2024 23:00:33 +0800 Subject: [PATCH 12/31] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20IOT=20=E7=89=A9=E6=A8=A1=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 5 +- .../IotThinkModelFunctionController.http | 96 +++++++++++++++++++ .../IotThinkModelFunctionController.java | 63 ++++++++++++ .../vo/IotThingModelProperty.java | 90 +++++++++++++++++ .../vo/IotThinkModelFunctionRespVO.java | 38 ++++++++ .../vo/IotThinkModelFunctionSaveReqVO.java | 26 +++++ .../IotThinkModelFunctionDO.java | 44 +++++++++ .../IotThinkModelFunctionMapper.java | 25 +++++ .../product/IotProductServiceImpl.java | 5 +- .../IotThinkModelFunctionService.java | 43 +++++++++ .../IotThinkModelFunctionServiceImpl.java | 74 ++++++++++++++ .../IotThinkModelFunctionMapper.xml | 12 +++ .../IotThinkModelFunctionServiceImplTest.java | 71 ++++++++++++++ 13 files changed, 588 insertions(+), 4 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/thinkmodelfunction/IotThinkModelFunctionMapper.xml create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImplTest.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 3fd09ce8e..19ee8972d 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -9,8 +9,11 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; */ public interface ErrorCodeConstants { - // ========== 产品相关 1-050-001-000 ============ + // ========== IoT 产品相关 1-050-001-000 ============ ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_050_001_000, "产品不存在"); ErrorCode PRODUCT_IDENTIFICATION_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在"); ErrorCode PRODUCT_STATUS_NOT_DELETE = new ErrorCode(1_050_001_002, "产品状是发布状态,不允许删除"); + + // ========== IoT 产品物模型 1-050-002-000 ============ + ErrorCode THINK_MODEL_FUNCTION_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在"); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http new file mode 100644 index 000000000..bc0229bfb --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http @@ -0,0 +1,96 @@ +### 请求 /iot/think-model-function/create 接口 => 成功 +POST {{baseUrl}}/iot/think-model-function/create +Content-Type: application/json +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} + +{ + "productKey": "123456", + "properties": [ + { + "identifier": "CurrentTemperature", + "name": "当前温度", + "accessMode": "r", + "required": true, + "dataType": { + "type": "float", + "specs": { + "min": "-40", + "max": "120", + "unit": "°C", + "unitName": "摄氏度", + "step": "0.1" + } + } + }, + { + "identifier": "CurrentHumidity", + "name": "当前湿度", + "accessMode": "r", + "required": true, + "dataType": { + "type": "float", + "specs": { + "min": "0", + "max": "100", + "unit": "%", + "unitName": "百分比", + "step": "0.1" + } + } + } + ], + "services": "{}", + "events": "{}" +} + +### 请求 /iot/think-model-function/update 接口 => 成功 +PUT {{baseUrl}}/iot/think-model-function/update +Content-Type: application/json +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} + +{ + "productKey": "123456", + "properties": [ + { + "identifier": "CurrentTemperature", + "name": "当前温度", + "accessMode": "r", + "required": true, + "dataType": { + "type": "float", + "specs": { + "min": "-40", + "max": "130", + "unit": "°C", + "unitName": "摄氏度", + "step": "0.1" + } + } + }, + { + "identifier": "CurrentHumidity", + "name": "当前湿度", + "accessMode": "r", + "required": true, + "dataType": { + "type": "float", + "specs": { + "min": "0", + "max": "100", + "unit": "%", + "unitName": "百分比", + "step": "0.1" + } + } + } + ], + "services": "{}", + "events": "{}" +} + +### 请求 /iot/think-model-function/get 接口 => 成功 +GET {{baseUrl}}/iot/think-model-function/get?productKey=123456 +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java new file mode 100644 index 000000000..cebaca4f5 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction; + +import org.springframework.web.bind.annotation.*; +import jakarta.annotation.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import jakarta.validation.*; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService; + +@Tag(name = "管理后台 - IoT 产品物模型") +@RestController +@RequestMapping("/iot/think-model-function") +@Validated +public class IotThinkModelFunctionController { + + @Resource + private IotThinkModelFunctionService thinkModelFunctionService; + + @PostMapping("/create") + @Operation(summary = "创建IoT 产品物模型") + @PreAuthorize("@ss.hasPermission('iot:think-model-function:create')") + public CommonResult createThinkModelFunction(@Valid @RequestBody IotThinkModelFunctionSaveReqVO createReqVO) { + return success(thinkModelFunctionService.createThinkModelFunction(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新IoT 产品物模型") + @PreAuthorize("@ss.hasPermission('iot:think-model-function:update')") + public CommonResult updateThinkModelFunction(@Valid @RequestBody IotThinkModelFunctionSaveReqVO updateReqVO) { + thinkModelFunctionService.updateThinkModelFunctionByProductKey(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除IoT 产品物模型") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:think-model-function:delete')") + public CommonResult deleteThinkModelFunction(@RequestParam("id") Long id) { + thinkModelFunctionService.deleteThinkModelFunction(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得IoT 产品物模型") + @Parameter(name = "productKey", description = "产品Key", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')") + public CommonResult getThinkModelFunctionByProductKey(@RequestParam("productKey") String productKey) { + IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionService.getThinkModelFunctionByProductKey(productKey); + return success(BeanUtils.toBean(thinkModelFunction, IotThinkModelFunctionRespVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java new file mode 100644 index 000000000..0187ae514 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java @@ -0,0 +1,90 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Schema(description = "管理后台 - IoT 产品物模型属性") +@Data +public class IotThingModelProperty { + + @Schema(description = "属性标识符") + private String identifier; + + @Schema(description = "属性名称") + private String name; + + @Schema(description = "访问模式 (r/rw)") + private String accessMode; + + @Schema(description = "是否必需") + private boolean required; + + @Schema(description = "数据类型") + private DataType dataType; + + @Schema(description = "数据类型") + @Data + public static class DataType { + + @Schema(description = "数据类型(float, double, struct, enum等)") + private String type; + + @Schema(description = "单一类型的规格(适用于float, double等)") + private Specs specs; + + @Schema(description = "结构体字段(适用于struct类型)") + private List structSpecs; + + @Schema(description = "规格") + @Data + public static class Specs { + + @Schema(description = "最小值") + private String min; + + @Schema(description = "最大值") + private String max; + + @Schema(description = "单位符号") + private String unit; + + @Schema(description = "单位名称") + private String unitName; + + @Schema(description = "步进值") + private String step; + } + + @Schema(description = "结构体字段") + @Data + public static class StructField { + + @Schema(description = "字段标识符") + private String identifier; + + @Schema(description = "字段名称") + private String name; + + @Schema(description = "字段的数据类型") + private DataType dataType; + } + } + + @Schema(description = "枚举规格") + @Data + public static class EnumSpecs { + + @Schema(description = "枚举值") + private int value; + + @Schema(description = "枚举名称") + private String name; + + public EnumSpecs(int value, String name) { + this.value = value; + this.name = name; + } + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java new file mode 100644 index 000000000..74f7bfb6f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; + +@Schema(description = "管理后台 - IoT 产品物模型 Response VO") +@Data +@ExcelIgnoreUnannotated +public class IotThinkModelFunctionRespVO { + + @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "21816") + @ExcelProperty("产品ID") + private Long id; + + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("产品标识") + private String productKey; + + @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("属性列表") + private String properties; + + @Schema(description = "服务列表") + @ExcelProperty("服务列表") + private String services; + + @Schema(description = "事件列表") + @ExcelProperty("事件列表") + private String events; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java new file mode 100644 index 000000000..200e7682c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import jakarta.validation.constraints.*; + +@Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO") +@Data +public class IotThinkModelFunctionSaveReqVO { + + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "产品标识不能为空") + private String productKey; + + @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "属性列表不能为空") + private List properties; + + @Schema(description = "服务列表") + private String services; + + @Schema(description = "事件列表") + private String events; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java new file mode 100644 index 000000000..7d9ea4589 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction; + +import lombok.*; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * IoT 产品物模型 DO + * + * @author 芋道源码 + */ +@TableName("iot_think_model_function") +@KeySequence("iot_think_model_function_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IotThinkModelFunctionDO extends BaseDO { + + /** + * 产品ID + */ + @TableId + private Long id; + /** + * 产品标识 + */ + private String productKey; + /** + * 属性列表 + */ + private String properties; + /** + * 服务列表 + */ + private String services; + /** + * 事件列表 + */ + private String events; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java new file mode 100644 index 000000000..5475a723b --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * IoT 产品物模型 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface IotThinkModelFunctionMapper extends BaseMapperX { + + default IotThinkModelFunctionDO selectByProductKey(String productKey) { + return selectOne(new LambdaQueryWrapperX().eq(IotThinkModelFunctionDO::getProductKey, productKey)); + } + + default int updateByProductKey(IotThinkModelFunctionDO thinkModelFunction) { + return update(thinkModelFunction, new LambdaQueryWrapperX() + .eq(IotThinkModelFunctionDO::getProductKey, thinkModelFunction.getProductKey()) + ); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index 844e074d9..96975c27f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -16,8 +16,7 @@ import java.util.Objects; import java.util.UUID; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.PRODUCT_STATUS_NOT_DELETE; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; /** * IoT 产品 Service 实现类 @@ -54,7 +53,7 @@ public class IotProductServiceImpl implements IotProductService { } // 2. 校验唯一性 if (productMapper.selectByProductKey(productKey) != null) { - throw exception(PRODUCT_NOT_EXISTS); + throw exception(PRODUCT_IDENTIFICATION_EXISTS); } createReqVO.setProductKey(productKey); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java new file mode 100644 index 000000000..a52142810 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.iot.service.thinkmodelfunction; + +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import jakarta.validation.Valid; + +/** + * IoT 产品物模型 Service 接口 + * + * @author 芋道源码 + */ +public interface IotThinkModelFunctionService { + + /** + * 创建IoT 产品物模型 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createThinkModelFunction(@Valid IotThinkModelFunctionSaveReqVO createReqVO); + + /** + * 删除IoT 产品物模型 + * + * @param id 编号 + */ + void deleteThinkModelFunction(Long id); + + /** + * 获得IoT 产品物模型 + * + * @param productKey 产品Key + * @return IoT 产品物模型 + */ + IotThinkModelFunctionDO getThinkModelFunctionByProductKey(String productKey); + + /** + * 更新IoT 产品物模型 + * + * @param updateReqVO 更新信息 + */ + void updateThinkModelFunctionByProductKey(@Valid IotThinkModelFunctionSaveReqVO updateReqVO); +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java new file mode 100644 index 000000000..1f1355dd3 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.iot.service.thinkmodelfunction; + +import cn.hutool.json.JSONUtil; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS; + +/** + * IoT 产品物模型 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionService { + + @Resource + private IotThinkModelFunctionMapper thinkModelFunctionMapper; + + @Override + public Long createThinkModelFunction(IotThinkModelFunctionSaveReqVO createReqVO) { + // 插入 + IotThinkModelFunctionDO thinkModelFunction = BeanUtils.toBean(createReqVO, IotThinkModelFunctionDO.class); + // properties 字段,需要转换成 JSON + thinkModelFunction.setProperties(JSONUtil.toJsonStr(createReqVO.getProperties())); + thinkModelFunctionMapper.insert(thinkModelFunction); + // 返回 + return thinkModelFunction.getId(); + } + + @Override + public void deleteThinkModelFunction(Long id) { + // 校验存在 + validateThinkModelFunctionExists(id); + // 删除 + thinkModelFunctionMapper.deleteById(id); + } + + private void validateThinkModelFunctionExists(Long id) { + if (thinkModelFunctionMapper.selectById(id) == null) { + throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS); + } + } + + private void validateThinkModelFunctionExistsByProductKey(String productKey) { + if (thinkModelFunctionMapper.selectByProductKey(productKey) == null) { + throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS); + } + } + + @Override + public IotThinkModelFunctionDO getThinkModelFunctionByProductKey(String productKey) { + return thinkModelFunctionMapper.selectByProductKey(productKey); + } + + @Override + public void updateThinkModelFunctionByProductKey(IotThinkModelFunctionSaveReqVO updateReqVO) { + // 校验存在 + validateThinkModelFunctionExistsByProductKey(updateReqVO.getProductKey()); + // 更新 + IotThinkModelFunctionDO thinkModelFunction = BeanUtils.toBean(updateReqVO, IotThinkModelFunctionDO.class); + // properties 字段,需要转换成 JSON + thinkModelFunction.setProperties(JSONUtil.toJsonStr(updateReqVO.getProperties())); + thinkModelFunctionMapper.updateByProductKey(thinkModelFunction); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/thinkmodelfunction/IotThinkModelFunctionMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/thinkmodelfunction/IotThinkModelFunctionMapper.xml new file mode 100644 index 000000000..525a32bd6 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/thinkmodelfunction/IotThinkModelFunctionMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImplTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImplTest.java new file mode 100644 index 000000000..762f6021b --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImplTest.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.iot.service.thinkmodelfunction; + +import org.junit.jupiter.api.Test; + +import jakarta.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper; + +import org.springframework.context.annotation.Import; + +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link IotThinkModelFunctionServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(IotThinkModelFunctionServiceImpl.class) +public class IotThinkModelFunctionServiceImplTest extends BaseDbUnitTest { + + @Resource + private IotThinkModelFunctionServiceImpl thinkModelFunctionService; + + @Resource + private IotThinkModelFunctionMapper thinkModelFunctionMapper; + + @Test + public void testCreateThinkModelFunction_success() { + // 准备参数 + IotThinkModelFunctionSaveReqVO createReqVO = randomPojo(IotThinkModelFunctionSaveReqVO.class); + + // 调用 + Long thinkModelFunctionId = thinkModelFunctionService.createThinkModelFunction(createReqVO); + // 断言 + assertNotNull(thinkModelFunctionId); + // 校验记录的属性是否正确 + IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionMapper.selectById(thinkModelFunctionId); + assertPojoEquals(createReqVO, thinkModelFunction, "id"); + } + + @Test + public void testDeleteThinkModelFunction_success() { + // mock 数据 + IotThinkModelFunctionDO dbThinkModelFunction = randomPojo(IotThinkModelFunctionDO.class); + thinkModelFunctionMapper.insert(dbThinkModelFunction);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbThinkModelFunction.getId(); + + // 调用 + thinkModelFunctionService.deleteThinkModelFunction(id); + // 校验数据不存在了 + assertNull(thinkModelFunctionMapper.selectById(id)); + } + + @Test + public void testDeleteThinkModelFunction_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> thinkModelFunctionService.deleteThinkModelFunction(id), THINK_MODEL_FUNCTION_NOT_EXISTS); + } + +} \ No newline at end of file From 9e77692414dc805be24c8ee12d5ccc3c05d1bb23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Fri, 13 Sep 2024 22:30:19 +0800 Subject: [PATCH 13/31] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9A=E4=BC=98?= =?UTF-8?q?=E5=8C=96=20IOT=20=E7=89=A9=E6=A8=A1=E5=9E=8B=20=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E5=92=8C=E6=9F=A5=E8=AF=A2=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 1 + .../IotThinkModelFunctionController.http | 7 ++- .../IotThinkModelFunctionController.java | 47 +++++++++------ .../vo/IotThinkModelFunctionRespVO.java | 8 ++- .../vo/IotThinkModelFunctionSaveReqVO.java | 7 +++ .../IotThinkModelFunctionConvert.java | 51 ++++++++++++++++ .../IotThinkModelFunctionDO.java | 15 ++++- .../IotThinkModelFunctionMapper.java | 7 +-- .../IotThinkModelFunctionService.java | 12 +++- .../IotThinkModelFunctionServiceImpl.java | 60 +++++++++++-------- 10 files changed, 159 insertions(+), 56 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 19ee8972d..d26e5f2ec 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -16,4 +16,5 @@ public interface ErrorCodeConstants { // ========== IoT 产品物模型 1-050-002-000 ============ ErrorCode THINK_MODEL_FUNCTION_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在"); + ErrorCode THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY = new ErrorCode(1_050_002_001, "ProductKey 对应的产品物模型已存在"); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http index bc0229bfb..b29ae8ddf 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http @@ -5,6 +5,7 @@ tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} { + "productId": 1, "productKey": "123456", "properties": [ { @@ -51,6 +52,8 @@ tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} { + "id": 1, + "productId": 1, "productKey": "123456", "properties": [ { @@ -90,7 +93,7 @@ Authorization: Bearer {{token}} "events": "{}" } -### 请求 /iot/think-model-function/get 接口 => 成功 -GET {{baseUrl}}/iot/think-model-function/get?productKey=123456 +### 请求 /iot/think-model-function/get-by-product-key 接口 => 成功 +GET {{baseUrl}}/iot/think-model-function/get-by-product-key?productKey=123456 tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java index cebaca4f5..a0051d9eb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java @@ -1,22 +1,21 @@ package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction; -import org.springframework.web.bind.annotation.*; -import jakarta.annotation.Resource; -import org.springframework.validation.annotation.Validated; -import org.springframework.security.access.prepost.PreAuthorize; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.Operation; - -import jakarta.validation.*; - import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.*; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; +import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import cn.iocoder.yudao.module.iot.service.thinkmodelfunction.IotThinkModelFunctionService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @Tag(name = "管理后台 - IoT 产品物模型") @RestController @@ -38,7 +37,7 @@ public class IotThinkModelFunctionController { @Operation(summary = "更新IoT 产品物模型") @PreAuthorize("@ss.hasPermission('iot:think-model-function:update')") public CommonResult updateThinkModelFunction(@Valid @RequestBody IotThinkModelFunctionSaveReqVO updateReqVO) { - thinkModelFunctionService.updateThinkModelFunctionByProductKey(updateReqVO); + thinkModelFunctionService.updateThinkModelFunction(updateReqVO); return success(true); } @@ -51,13 +50,23 @@ public class IotThinkModelFunctionController { return success(true); } - @GetMapping("/get") + @GetMapping("/get-by-product-key") @Operation(summary = "获得IoT 产品物模型") @Parameter(name = "productKey", description = "产品Key", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')") - public CommonResult getThinkModelFunctionByProductKey(@RequestParam("productKey") String productKey) { + public CommonResult getThinkModelFunctionByProductKey(@RequestParam("productKey") String productKey) { IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionService.getThinkModelFunctionByProductKey(productKey); - return success(BeanUtils.toBean(thinkModelFunction, IotThinkModelFunctionRespVO.class)); + IotThinkModelFunctionRespVO respVO = IotThinkModelFunctionConvert.INSTANCE.convert(thinkModelFunction); + return success(respVO); } -} \ No newline at end of file + @GetMapping("/get-by-product-id") + @Operation(summary = "获得IoT 产品物模型") + @Parameter(name = "productId", description = "产品ID", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')") + public CommonResult getThinkModelFunctionByProductId(@RequestParam("productId") Long productId) { + IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionService.getThinkModelFunctionByProductId(productId); + IotThinkModelFunctionRespVO respVO = IotThinkModelFunctionConvert.INSTANCE.convert(thinkModelFunction); + return success(respVO); + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java index 74f7bfb6f..5d525e5b5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java @@ -1,10 +1,12 @@ package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; +import lombok.Data; import java.time.LocalDateTime; -import com.alibaba.excel.annotation.*; +import java.util.List; @Schema(description = "管理后台 - IoT 产品物模型 Response VO") @Data @@ -21,7 +23,7 @@ public class IotThinkModelFunctionRespVO { @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("属性列表") - private String properties; + private List properties; @Schema(description = "服务列表") @ExcelProperty("服务列表") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java index 200e7682c..705846210 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java @@ -9,6 +9,13 @@ import jakarta.validation.constraints.*; @Data public class IotThinkModelFunctionSaveReqVO { + @Schema(description = "编号", example = "1") + private Long id; + + @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "产品ID不能为空") + private Long productId; + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED) @NotEmpty(message = "产品标识不能为空") private String productKey; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java new file mode 100644 index 000000000..783ef658a --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.iot.convert.thinkmodelfunction; + +import cn.hutool.json.JSONUtil; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import org.mapstruct.AfterMapping; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface IotThinkModelFunctionConvert { + + IotThinkModelFunctionConvert INSTANCE = Mappers.getMapper(IotThinkModelFunctionConvert.class); + + // 将 SaveReqVO 转换为 DO + @Mapping(target = "properties", ignore = true) + IotThinkModelFunctionDO convert(IotThinkModelFunctionSaveReqVO bean); + + // 将 DO 转换为 RespVO + @Mapping(target = "properties", ignore = true) + IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean); + + // 处理 properties 字段的转换,从 VO 到 DO + @AfterMapping + default void convertPropertiesToDO(IotThinkModelFunctionSaveReqVO source, @MappingTarget IotThinkModelFunctionDO target) { + target.setProperties(JSONUtil.toJsonStr(source.getProperties())); + } + + // 处理 properties 字段的转换,从 DO 到 VO + @AfterMapping + default void convertPropertiesToVO(IotThinkModelFunctionDO source, @MappingTarget IotThinkModelFunctionRespVO target) { + target.setProperties(JSONUtil.toList(source.getProperties(), IotThingModelProperty.class)); + } + + // 批量转换 DO 列表到 RespVO 列表 + List convertList(List list); + + // 批量转换处理 properties 字段 + @AfterMapping + default void convertPropertiesListToVO(List sourceList, @MappingTarget List targetList) { + for (int i = 0; i < sourceList.size(); i++) { + convertPropertiesToVO(sourceList.get(i), targetList.get(i)); + } + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java index 7d9ea4589..564eefb2b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java @@ -1,8 +1,10 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction; -import lombok.*; -import com.baomidou.mybatisplus.annotation.*; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; /** * IoT 产品物模型 DO @@ -24,18 +26,27 @@ public class IotThinkModelFunctionDO extends BaseDO { */ @TableId private Long id; + + /** + * 产品标识 + */ + private Long productId; + /** * 产品标识 */ private String productKey; + /** * 属性列表 */ private String properties; + /** * 服务列表 */ private String services; + /** * 事件列表 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java index 5475a723b..21ae1967a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java @@ -17,9 +17,8 @@ public interface IotThinkModelFunctionMapper extends BaseMapperX().eq(IotThinkModelFunctionDO::getProductKey, productKey)); } - default int updateByProductKey(IotThinkModelFunctionDO thinkModelFunction) { - return update(thinkModelFunction, new LambdaQueryWrapperX() - .eq(IotThinkModelFunctionDO::getProductKey, thinkModelFunction.getProductKey()) - ); + default IotThinkModelFunctionDO selectByProductId(Long productId){ + return selectOne(new LambdaQueryWrapperX().eq(IotThinkModelFunctionDO::getProductId, productId)); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java index a52142810..d24ce0031 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java @@ -27,17 +27,25 @@ public interface IotThinkModelFunctionService { void deleteThinkModelFunction(Long id); /** - * 获得IoT 产品物模型 + * 获得IoT 产品物模型,通过产品Key * * @param productKey 产品Key * @return IoT 产品物模型 */ IotThinkModelFunctionDO getThinkModelFunctionByProductKey(String productKey); + /** + * 获得IoT 产品物模型,通过产品ID + * + * @param productId 产品ID + * @return IoT 产品物模型 + */ + IotThinkModelFunctionDO getThinkModelFunctionByProductId(Long productId); + /** * 更新IoT 产品物模型 * * @param updateReqVO 更新信息 */ - void updateThinkModelFunctionByProductKey(@Valid IotThinkModelFunctionSaveReqVO updateReqVO); + void updateThinkModelFunction(@Valid IotThinkModelFunctionSaveReqVO updateReqVO); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index 1f1355dd3..89c5f6b98 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -1,22 +1,20 @@ package cn.iocoder.yudao.module.iot.service.thinkmodelfunction; -import cn.hutool.json.JSONUtil; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; +import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper; import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS; -/** - * IoT 产品物模型 Service 实现类 - * - * @author 芋道源码 - */ +@Slf4j @Service @Validated public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionService { @@ -26,17 +24,25 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe @Override public Long createThinkModelFunction(IotThinkModelFunctionSaveReqVO createReqVO) { + log.info("创建物模型,参数:{}", createReqVO); + // 验证 ProductKey 对应的产品物模型是否已存在 + validateThinkModelFunctionNotExistsByProductKey(createReqVO.getProductKey()); // 插入 - IotThinkModelFunctionDO thinkModelFunction = BeanUtils.toBean(createReqVO, IotThinkModelFunctionDO.class); - // properties 字段,需要转换成 JSON - thinkModelFunction.setProperties(JSONUtil.toJsonStr(createReqVO.getProperties())); + IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO); thinkModelFunctionMapper.insert(thinkModelFunction); // 返回 return thinkModelFunction.getId(); } + private void validateThinkModelFunctionNotExistsByProductKey(String productKey) { + if (thinkModelFunctionMapper.selectByProductKey(productKey) != null) { + throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY); + } + } + @Override public void deleteThinkModelFunction(Long id) { + log.info("删除物模型,id:{}", id); // 校验存在 validateThinkModelFunctionExists(id); // 删除 @@ -49,26 +55,32 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe } } - private void validateThinkModelFunctionExistsByProductKey(String productKey) { - if (thinkModelFunctionMapper.selectByProductKey(productKey) == null) { - throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS); - } - } - @Override public IotThinkModelFunctionDO getThinkModelFunctionByProductKey(String productKey) { return thinkModelFunctionMapper.selectByProductKey(productKey); } @Override - public void updateThinkModelFunctionByProductKey(IotThinkModelFunctionSaveReqVO updateReqVO) { - // 校验存在 - validateThinkModelFunctionExistsByProductKey(updateReqVO.getProductKey()); - // 更新 - IotThinkModelFunctionDO thinkModelFunction = BeanUtils.toBean(updateReqVO, IotThinkModelFunctionDO.class); - // properties 字段,需要转换成 JSON - thinkModelFunction.setProperties(JSONUtil.toJsonStr(updateReqVO.getProperties())); - thinkModelFunctionMapper.updateByProductKey(thinkModelFunction); + public IotThinkModelFunctionDO getThinkModelFunctionByProductId(Long productId) { + return thinkModelFunctionMapper.selectByProductId(productId); } + @Override + public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) { + log.info("更新物模型,参数:{}", updateReqVO); + // 校验存在 + validateThinkModelFunctionExists(updateReqVO.getId()); + // 校验 productKey 是否重复 + validateProductKeyUnique(updateReqVO.getId(), updateReqVO.getProductKey()); + // 更新 + IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO); + thinkModelFunctionMapper.updateById(thinkModelFunction); + } + + private void validateProductKeyUnique(Long id, String productKey) { + IotThinkModelFunctionDO existingFunction = thinkModelFunctionMapper.selectByProductKey(productKey); + if (existingFunction != null && !existingFunction.getId().equals(id)) { + throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY); + } + } } \ No newline at end of file From 1f8576f6432fe5201497d2c3704de809d7185307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sat, 14 Sep 2024 00:35:43 +0800 Subject: [PATCH 14/31] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9AIOT=20?= =?UTF-8?q?=E6=A0=B9=E6=8D=AE=E5=B1=9E=E6=80=A7=E5=88=97=E8=A1=A8=EF=BC=8C?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90=E5=B1=9E=E6=80=A7=E4=B8=8A?= =?UTF-8?q?=E6=8A=A5=E4=BA=8B=E4=BB=B6=E5=92=8C=E5=B1=9E=E6=80=A7=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E3=80=81=E8=8E=B7=E5=8F=96=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IotThinkModelFunctionController.http | 265 +++++++++++++++--- .../thingModel/ThingModelArgument.java | 12 + .../thingModel/ThingModelArraySpecs.java | 9 + .../thingModel/ThingModelArrayType.java | 11 + .../thingModel/ThingModelBoolType.java | 10 + .../thingModel/ThingModelDataType.java | 22 ++ .../thingModel/ThingModelDateType.java | 10 + .../thingModel/ThingModelDoubleType.java | 18 ++ .../thingModel/ThingModelEnumType.java | 11 + .../thingModel/ThingModelEvent.java | 14 + .../thingModel/ThingModelFloatType.java | 18 ++ .../thingModel/ThingModelIntType.java | 18 ++ .../thingModel/ThingModelProperty.java | 13 + .../thingModel/ThingModelService.java | 15 + .../thingModel/ThingModelStructField.java | 11 + .../thingModel/ThingModelStructType.java | 13 + .../thingModel/ThingModelTextType.java | 15 + .../vo/IotThingModelProperty.java | 90 ------ .../vo/IotThinkModelFunctionRespVO.java | 9 +- .../vo/IotThinkModelFunctionSaveReqVO.java | 17 +- .../IotThinkModelFunctionConvert.java | 60 ++-- .../IotThinkModelFunctionServiceImpl.java | 176 +++++++++++- 22 files changed, 664 insertions(+), 173 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArgument.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArrayType.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelBoolType.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDataType.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDateType.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDoubleType.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEnumType.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelFloatType.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelIntType.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructField.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructType.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelTextType.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http index b29ae8ddf..e31540710 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http @@ -5,46 +5,140 @@ tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} { - "productId": 1, - "productKey": "123456", + "productId": 1002, + "productKey": "smart-sensor-002", "properties": [ { - "identifier": "CurrentTemperature", - "name": "当前温度", + "identifier": "Temperature", + "name": "温度", "accessMode": "r", "required": true, "dataType": { "type": "float", "specs": { - "min": "-40", - "max": "120", - "unit": "°C", - "unitName": "摄氏度", - "step": "0.1" + "min": -40.0, + "max": 125.0, + "step": 0.1, + "unit": "℃" } - } + }, + "description": "当前温度值" }, { - "identifier": "CurrentHumidity", - "name": "当前湿度", + "identifier": "Humidity", + "name": "湿度", "accessMode": "r", "required": true, "dataType": { "type": "float", "specs": { - "min": "0", - "max": "100", - "unit": "%", - "unitName": "百分比", - "step": "0.1" + "min": 0.0, + "max": 100.0, + "step": 0.1, + "unit": "%" } - } + }, + "description": "当前湿度值" + }, + { + "identifier": "GeoLocation", + "name": "地理位置", + "accessMode": "r", + "required": false, + "dataType": { + "type": "struct", + "specs": [ + { + "identifier": "Longitude", + "name": "经度", + "dataType": { + "type": "double", + "specs": { + "min": -180.0, + "max": 180.0, + "step": 0.000001, + "unit": "°" + } + }, + "description": "设备所在位置的经度" + }, + { + "identifier": "Latitude", + "name": "纬度", + "dataType": { + "type": "double", + "specs": { + "min": -90.0, + "max": 90.0, + "step": 0.000001, + "unit": "°" + } + }, + "description": "设备所在位置的纬度" + } + ] + }, + "description": "设备的地理位置信息" } ], - "services": "{}", - "events": "{}" + "services": [ + { + "identifier": "Reboot", + "name": "重启设备", + "callType": "async", + "inputData": [], + "description": "远程重启设备", + "method": "thing.service.reboot" + }, + { + "identifier": "SetThreshold", + "name": "设置温度阈值", + "callType": "sync", + "inputData": [ + { + "identifier": "Threshold", + "name": "阈值", + "dataType": { + "type": "float", + "specs": { + "min": -40.0, + "max": 125.0, + "step": 0.1, + "unit": "℃" + } + }, + "description": "报警温度阈值" + } + ], + "description": "设置设备的温度报警阈值", + "method": "thing.service.setThreshold" + } + ], + "events": [ + { + "identifier": "HighTemperatureAlert", + "name": "高温报警", + "type": "alert", + "outputData": [ + { + "identifier": "CurrentTemperature", + "name": "当前温度", + "dataType": { + "type": "float", + "specs": { + "unit": "℃" + } + }, + "description": "触发报警时的温度值" + } + ], + "description": "当温度超过阈值时触发高温报警事件", + "method": "thing.event.highTemperatureAlert" + } + ] } + ### 请求 /iot/think-model-function/update 接口 => 成功 PUT {{baseUrl}}/iot/think-model-function/update Content-Type: application/json @@ -53,46 +147,137 @@ Authorization: Bearer {{token}} { "id": 1, - "productId": 1, - "productKey": "123456", + "productId": 1001, + "productKey": "smart-sensor-001", "properties": [ { - "identifier": "CurrentTemperature", - "name": "当前温度", + "identifier": "Temperature", + "name": "温度", "accessMode": "r", "required": true, "dataType": { "type": "float", "specs": { - "min": "-40", - "max": "130", - "unit": "°C", - "unitName": "摄氏度", - "step": "0.1" + "min": -40.0, + "max": 125.0, + "step": 0.1, + "unit": "℃" } - } + }, + "description": "当前温度值" }, { - "identifier": "CurrentHumidity", - "name": "当前湿度", + "identifier": "Humidity", + "name": "湿度", "accessMode": "r", "required": true, "dataType": { "type": "float", "specs": { - "min": "0", - "max": "100", - "unit": "%", - "unitName": "百分比", - "step": "0.1" + "min": 0.0, + "max": 100.0, + "step": 0.1, + "unit": "%" } - } + }, + "description": "当前湿度值" + }, + { + "identifier": "GeoLocation", + "name": "地理位置", + "accessMode": "r", + "required": false, + "dataType": { + "type": "struct", + "specs": [ + { + "identifier": "Longitude", + "name": "经度", + "dataType": { + "type": "double", + "specs": { + "min": -180.0, + "max": 180.0, + "step": 0.000001, + "unit": "°" + } + }, + "description": "设备所在位置的经度" + }, + { + "identifier": "Latitude", + "name": "纬度", + "dataType": { + "type": "double", + "specs": { + "min": -90.0, + "max": 90.0, + "step": 0.000001, + "unit": "°" + } + }, + "description": "设备所在位置的纬度" + } + ] + }, + "description": "设备的地理位置信息" } ], - "services": "{}", - "events": "{}" + "services": [ + { + "identifier": "Reboot", + "name": "重启设备", + "callType": "async", + "inputData": [], + "description": "远程重启设备" + }, + { + "identifier": "SetThreshold", + "name": "设置温度阈值", + "callType": "sync", + "inputData": [ + { + "identifier": "Threshold", + "name": "阈值", + "dataType": { + "type": "float", + "specs": { + "min": -40.0, + "max": 125.0, + "step": 0.1, + "unit": "℃" + } + }, + "description": "报警温度阈值" + } + ], + "description": "设置设备的温度报警阈值" + } + ], + "events": [ + { + "identifier": "HighTemperatureAlert", + "name": "高温报警", + "type": "alert", + "outputData": [ + { + "identifier": "CurrentTemperature", + "name": "当前温度", + "dataType": { + "type": "float", + "specs": { + "unit": "℃" + } + }, + "description": "触发报警时的温度值" + } + ], + "description": "当温度超过阈值时触发高温报警事件" + } + ] } + ### 请求 /iot/think-model-function/get-by-product-key 接口 => 成功 GET {{baseUrl}}/iot/think-model-function/get-by-product-key?productKey=123456 tenant-id: {{adminTenentId}} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArgument.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArgument.java new file mode 100644 index 000000000..909d63459 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArgument.java @@ -0,0 +1,12 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; + +@Data +public class ThingModelArgument { + private String identifier; + private String name; + private ThingModelDataType dataType; + private String direction; // 用于区分输入或输出参数,"input" 或 "output" + private String description; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java new file mode 100644 index 000000000..3ea23e8db --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java @@ -0,0 +1,9 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; + +@Data +public class ThingModelArraySpecs { + private int size; // 数组长度 + private ThingModelDataType item; // 数组元素的类型 +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArrayType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArrayType.java new file mode 100644 index 000000000..114add210 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArrayType.java @@ -0,0 +1,11 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ThingModelArrayType extends ThingModelDataType { + private ThingModelArraySpecs specs; +} + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelBoolType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelBoolType.java new file mode 100644 index 000000000..f7e7e456b --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelBoolType.java @@ -0,0 +1,10 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ThingModelBoolType extends ThingModelDataType { + // Bool 类型一般不需要额外的 specs +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDataType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDataType.java new file mode 100644 index 000000000..613cbd766 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDataType.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import lombok.Data; + +@Data +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true) +@JsonSubTypes({ + @JsonSubTypes.Type(value = ThingModelIntType.class, name = "int"), + @JsonSubTypes.Type(value = ThingModelFloatType.class, name = "float"), + @JsonSubTypes.Type(value = ThingModelDoubleType.class, name = "double"), + @JsonSubTypes.Type(value = ThingModelTextType.class, name = "text"), + @JsonSubTypes.Type(value = ThingModelDateType.class, name = "date"), + @JsonSubTypes.Type(value = ThingModelBoolType.class, name = "bool"), + @JsonSubTypes.Type(value = ThingModelEnumType.class, name = "enum"), + @JsonSubTypes.Type(value = ThingModelStructType.class, name = "struct"), + @JsonSubTypes.Type(value = ThingModelArrayType.class, name = "array") +}) +public abstract class ThingModelDataType { + private String type; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDateType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDateType.java new file mode 100644 index 000000000..11cb3a729 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDateType.java @@ -0,0 +1,10 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ThingModelDateType extends ThingModelDataType { + // Date 类型一般不需要额外的 specs +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDoubleType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDoubleType.java new file mode 100644 index 000000000..d60302179 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDoubleType.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ThingModelDoubleType extends ThingModelDataType { + private ThingModelDoubleSpecs specs; +} + +@Data +class ThingModelDoubleSpecs { + private Double min; + private Double max; + private Double step; + private String unit; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEnumType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEnumType.java new file mode 100644 index 000000000..f76962661 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEnumType.java @@ -0,0 +1,11 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.util.Map; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ThingModelEnumType extends ThingModelDataType { + private Map specs; // 枚举值和描述的键值对 +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java new file mode 100644 index 000000000..857f688e9 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import java.util.List; + +@Data +public class ThingModelEvent { + private String identifier; + private String name; + private String type; // "info"、"alert"、"error" + private List outputData; + private String description; + private String method; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelFloatType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelFloatType.java new file mode 100644 index 000000000..c9d5516ad --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelFloatType.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ThingModelFloatType extends ThingModelDataType { + private ThingModelFloatSpecs specs; +} + +@Data +class ThingModelFloatSpecs { + private Float min; + private Float max; + private Float step; + private String unit; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelIntType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelIntType.java new file mode 100644 index 000000000..d48f50e47 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelIntType.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ThingModelIntType extends ThingModelDataType { + private ThingModelIntSpecs specs; +} + +@Data +class ThingModelIntSpecs { + private Integer min; + private Integer max; + private Integer step; + private String unit; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java new file mode 100644 index 000000000..f82198152 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; + +@Data +public class ThingModelProperty { + private String identifier; + private String name; + private String accessMode; // "rw"、"r"、"w" + private boolean required; + private ThingModelDataType dataType; + private String description; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java new file mode 100644 index 000000000..521e9ab08 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import java.util.List; + +@Data +public class ThingModelService { + private String identifier; + private String name; + private String callType; // "sync"、"async" + private List inputData; + private List outputData; + private String description; + private String method; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructField.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructField.java new file mode 100644 index 000000000..449db55c2 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructField.java @@ -0,0 +1,11 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; + +@Data +public class ThingModelStructField { + private String identifier; + private String name; + private ThingModelDataType dataType; + private String description; +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructType.java new file mode 100644 index 000000000..d3d35f16c --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructType.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.util.List; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ThingModelStructType extends ThingModelDataType { + private List specs; +} + + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelTextType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelTextType.java new file mode 100644 index 000000000..0f6ea2bcb --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelTextType.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ThingModelTextType extends ThingModelDataType { + private ThingModelTextSpecs specs; +} + +@Data +class ThingModelTextSpecs { + private Integer length; // 最大长度 +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java deleted file mode 100644 index 0187ae514..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java +++ /dev/null @@ -1,90 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.util.List; - -@Schema(description = "管理后台 - IoT 产品物模型属性") -@Data -public class IotThingModelProperty { - - @Schema(description = "属性标识符") - private String identifier; - - @Schema(description = "属性名称") - private String name; - - @Schema(description = "访问模式 (r/rw)") - private String accessMode; - - @Schema(description = "是否必需") - private boolean required; - - @Schema(description = "数据类型") - private DataType dataType; - - @Schema(description = "数据类型") - @Data - public static class DataType { - - @Schema(description = "数据类型(float, double, struct, enum等)") - private String type; - - @Schema(description = "单一类型的规格(适用于float, double等)") - private Specs specs; - - @Schema(description = "结构体字段(适用于struct类型)") - private List structSpecs; - - @Schema(description = "规格") - @Data - public static class Specs { - - @Schema(description = "最小值") - private String min; - - @Schema(description = "最大值") - private String max; - - @Schema(description = "单位符号") - private String unit; - - @Schema(description = "单位名称") - private String unitName; - - @Schema(description = "步进值") - private String step; - } - - @Schema(description = "结构体字段") - @Data - public static class StructField { - - @Schema(description = "字段标识符") - private String identifier; - - @Schema(description = "字段名称") - private String name; - - @Schema(description = "字段的数据类型") - private DataType dataType; - } - } - - @Schema(description = "枚举规格") - @Data - public static class EnumSpecs { - - @Schema(description = "枚举值") - private int value; - - @Schema(description = "枚举名称") - private String name; - - public EnumSpecs(int value, String name) { - this.value = value; - this.name = name; - } - } -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java index 5d525e5b5..42ac727a4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java @@ -1,5 +1,8 @@ package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -23,15 +26,15 @@ public class IotThinkModelFunctionRespVO { @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("属性列表") - private List properties; + private List properties; @Schema(description = "服务列表") @ExcelProperty("服务列表") - private String services; + private List services; @Schema(description = "事件列表") @ExcelProperty("事件列表") - private String events; + private List events; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("创建时间") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java index 705846210..00132fa8b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java @@ -1,9 +1,14 @@ package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; -import java.util.*; -import jakarta.validation.constraints.*; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.List; @Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO") @Data @@ -22,12 +27,12 @@ public class IotThinkModelFunctionSaveReqVO { @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED) @NotEmpty(message = "属性列表不能为空") - private List properties; + private List properties; @Schema(description = "服务列表") - private String services; + private List services; @Schema(description = "事件列表") - private String events; + private List events; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java index 783ef658a..41e0c583b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java @@ -1,16 +1,17 @@ package cn.iocoder.yudao.module.iot.convert.thinkmodelfunction; import cn.hutool.json.JSONUtil; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; -import org.mapstruct.AfterMapping; import org.mapstruct.Mapper; import org.mapstruct.Mapping; -import org.mapstruct.MappingTarget; import org.mapstruct.factory.Mappers; +import java.util.ArrayList; import java.util.List; @Mapper @@ -18,34 +19,43 @@ public interface IotThinkModelFunctionConvert { IotThinkModelFunctionConvert INSTANCE = Mappers.getMapper(IotThinkModelFunctionConvert.class); - // 将 SaveReqVO 转换为 DO - @Mapping(target = "properties", ignore = true) + // 将 SaveReqVO 转换为 DO 对象,处理 properties, services, events 字段 + @Mapping(target = "properties", expression = "java(convertPropertiesToJson(bean.getProperties()))") + @Mapping(target = "services", expression = "java(convertServicesToJson(bean.getServices()))") + @Mapping(target = "events", expression = "java(convertEventsToJson(bean.getEvents()))") IotThinkModelFunctionDO convert(IotThinkModelFunctionSaveReqVO bean); - // 将 DO 转换为 RespVO - @Mapping(target = "properties", ignore = true) - IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean); - - // 处理 properties 字段的转换,从 VO 到 DO - @AfterMapping - default void convertPropertiesToDO(IotThinkModelFunctionSaveReqVO source, @MappingTarget IotThinkModelFunctionDO target) { - target.setProperties(JSONUtil.toJsonStr(source.getProperties())); + default String convertPropertiesToJson(List properties) { + return properties != null ? JSONUtil.toJsonStr(properties) : "[]"; } - // 处理 properties 字段的转换,从 DO 到 VO - @AfterMapping - default void convertPropertiesToVO(IotThinkModelFunctionDO source, @MappingTarget IotThinkModelFunctionRespVO target) { - target.setProperties(JSONUtil.toList(source.getProperties(), IotThingModelProperty.class)); + default String convertServicesToJson(List services) { + return services != null ? JSONUtil.toJsonStr(services) : "[]"; + } + + default String convertEventsToJson(List events) { + return events != null ? JSONUtil.toJsonStr(events) : "[]"; + } + + // 将 DO 转换为 RespVO 对象,处理 properties, services, events 字段 + @Mapping(target = "properties", expression = "java(convertJsonToProperties(bean.getProperties()))") + @Mapping(target = "services", expression = "java(convertJsonToServices(bean.getServices()))") + @Mapping(target = "events", expression = "java(convertJsonToEvents(bean.getEvents()))") + IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean); + + default List convertJsonToProperties(String propertiesJson) { + return propertiesJson != null ? JSONUtil.toList(propertiesJson, ThingModelProperty.class) : new ArrayList<>(); + } + + default List convertJsonToServices(String servicesJson) { + return servicesJson != null ? JSONUtil.toList(servicesJson, ThingModelService.class) : new ArrayList<>(); + } + + default List convertJsonToEvents(String eventsJson) { + return eventsJson != null ? JSONUtil.toList(eventsJson, ThingModelEvent.class) : new ArrayList<>(); } // 批量转换 DO 列表到 RespVO 列表 List convertList(List list); - - // 批量转换处理 properties 字段 - @AfterMapping - default void convertPropertiesListToVO(List sourceList, @MappingTarget List targetList) { - for (int i = 0; i < sourceList.size(); i++) { - convertPropertiesToVO(sourceList.get(i), targetList.get(i)); - } - } } + diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index 89c5f6b98..66fc01779 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.service.thinkmodelfunction; -import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.hutool.json.JSONUtil; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.*; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; @@ -10,6 +11,10 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS; @@ -27,10 +32,13 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe log.info("创建物模型,参数:{}", createReqVO); // 验证 ProductKey 对应的产品物模型是否已存在 validateThinkModelFunctionNotExistsByProductKey(createReqVO.getProductKey()); - // 插入 + // 转换请求对象为数据对象 IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO); + // 自动生成属性上报事件和属性设置、获取服务 + generateDefaultEventsAndServices(createReqVO, thinkModelFunction); + // 插入数据库 thinkModelFunctionMapper.insert(thinkModelFunction); - // 返回 + // 返回生成的 ID return thinkModelFunction.getId(); } @@ -43,9 +51,9 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe @Override public void deleteThinkModelFunction(Long id) { log.info("删除物模型,id:{}", id); - // 校验存在 + // 校验物模型是否存在 validateThinkModelFunctionExists(id); - // 删除 + // 删除物模型 thinkModelFunctionMapper.deleteById(id); } @@ -68,12 +76,15 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe @Override public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) { log.info("更新物模型,参数:{}", updateReqVO); - // 校验存在 + // 校验物模型是否存在 validateThinkModelFunctionExists(updateReqVO.getId()); - // 校验 productKey 是否重复 + // 校验 ProductKey 是否唯一 validateProductKeyUnique(updateReqVO.getId(), updateReqVO.getProductKey()); - // 更新 + // 转换请求对象为数据对象 IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO); + // 自动生成或更新属性上报事件和属性设置、获取服务 + generateDefaultEventsAndServices(updateReqVO, thinkModelFunction); + // 更新数据库 thinkModelFunctionMapper.updateById(thinkModelFunction); } @@ -83,4 +94,151 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY); } } -} \ No newline at end of file + + /** + * @ TODO 还要再优化 + * 根据属性列表,自动生成属性上报事件和属性设置、获取服务 + */ + private void generateDefaultEventsAndServices(IotThinkModelFunctionSaveReqVO reqVO, IotThinkModelFunctionDO thinkModelFunction) { + // 获取属性列表 + List properties = reqVO.getProperties(); + if (properties == null) { + properties = new ArrayList<>(); + } + + // 生成属性上报事件 + List events = reqVO.getEvents() != null ? new ArrayList<>(reqVO.getEvents()) : new ArrayList<>(); + ThingModelEvent propertyPostEvent = generatePropertyPostEvent(properties); + events.add(propertyPostEvent); + + // 生成属性设置和获取服务 + List services = reqVO.getServices() != null ? new ArrayList<>(reqVO.getServices()) : new ArrayList<>(); + ThingModelService propertySetService = generatePropertySetService(properties); + if (propertySetService != null) { + services.add(propertySetService); + } + ThingModelService propertyGetService = generatePropertyGetService(properties); + if (propertyGetService != null) { + services.add(propertyGetService); + } + + // 更新 thinkModelFunction 对象的 events 和 services 字段 + thinkModelFunction.setEvents(JSONUtil.toJsonStr(events)); + thinkModelFunction.setServices(JSONUtil.toJsonStr(services)); + } + + /** + * 生成属性上报事件 + */ + private ThingModelEvent generatePropertyPostEvent(List properties) { + ThingModelEvent event = new ThingModelEvent(); + event.setIdentifier("post"); + event.setName("属性上报"); + event.setType("info"); + event.setDescription("属性上报事件"); + event.setMethod("thing.event.property.post"); + + // 将属性列表转换为事件的输出参数 + List outputData = new ArrayList<>(); + for (ThingModelProperty property : properties) { + ThingModelArgument arg = new ThingModelArgument(); + arg.setIdentifier(property.getIdentifier()); + arg.setName(property.getName()); + arg.setDataType(property.getDataType()); + arg.setDescription(property.getDescription()); + arg.setDirection("output"); // 设置为输出参数 + outputData.add(arg); + } + event.setOutputData(outputData); + + return event; + } + + /** + * 生成属性设置服务 + */ + private ThingModelService generatePropertySetService(List properties) { + List inputData = new ArrayList<>(); + for (ThingModelProperty property : properties) { + if ("w".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) { + ThingModelArgument arg = new ThingModelArgument(); + arg.setIdentifier(property.getIdentifier()); + arg.setName(property.getName()); + arg.setDataType(property.getDataType()); + arg.setDescription(property.getDescription()); + arg.setDirection("input"); // 设置为输入参数 + inputData.add(arg); + } + } + if (inputData.isEmpty()) { + // 如果没有可写属性,不生成属性设置服务 + return null; + } + + ThingModelService service = new ThingModelService(); + service.setIdentifier("set"); + service.setName("属性设置"); + service.setCallType("async"); + service.setDescription("属性设置服务"); + service.setMethod("thing.service.property.set"); + service.setInputData(inputData); + // 属性设置服务一般不需要输出参数 + service.setOutputData(new ArrayList<>()); + + return service; + } + + /** + * 生成属性获取服务 + */ + private ThingModelService generatePropertyGetService(List properties) { + List outputData = new ArrayList<>(); + for (ThingModelProperty property : properties) { + if ("r".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) { + ThingModelArgument arg = new ThingModelArgument(); + arg.setIdentifier(property.getIdentifier()); + arg.setName(property.getName()); + arg.setDataType(property.getDataType()); + arg.setDescription(property.getDescription()); + arg.setDirection("output"); // 设置为输出参数 + outputData.add(arg); + } + } + if (outputData.isEmpty()) { + // 如果没有可读属性,不生成属性获取服务 + return null; + } + + ThingModelService service = new ThingModelService(); + service.setIdentifier("get"); + service.setName("属性获取"); + service.setCallType("async"); + service.setDescription("属性获取服务"); + service.setMethod("thing.service.property.get"); + + // 定义输入参数:属性标识符列表 + ThingModelArgument inputArg = new ThingModelArgument(); + inputArg.setIdentifier("properties"); + inputArg.setName("属性标识符列表"); + inputArg.setDescription("需要获取的属性标识符列表"); + inputArg.setDirection("input"); // 设置为输入参数 + + // 创建数组类型,元素类型为文本类型(字符串) + ThingModelArrayType arrayType = new ThingModelArrayType(); + arrayType.setType("array"); + ThingModelArraySpecs arraySpecs = new ThingModelArraySpecs(); + // 不指定数组长度,size 可以为 0 或者省略 + ThingModelTextType textType = new ThingModelTextType(); + textType.setType("text"); + // 如果有需要,可以设置 TextType 的 specs,如长度限制 + arraySpecs.setItem(textType); + arrayType.setSpecs(arraySpecs); + + inputArg.setDataType(arrayType); + + service.setInputData(Collections.singletonList(inputArg)); + service.setOutputData(outputData); + + return service; + } +} From 061819f25b16275b2ef97915f821dbf66cd673dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sat, 14 Sep 2024 08:32:04 +0800 Subject: [PATCH 15/31] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9AIOT=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=A0=B9=E6=8D=AE=E5=B1=9E=E6=80=A7=E5=88=97?= =?UTF-8?q?=E8=A1=A8=EF=BC=8C=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E4=B8=8A=E6=8A=A5=E4=BA=8B=E4=BB=B6=E5=92=8C=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E8=AE=BE=E7=BD=AE=E3=80=81=E8=8E=B7=E5=8F=96=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IotThinkModelFunctionServiceImpl.java | 67 ++++++++++++++----- 1 file changed, 52 insertions(+), 15 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index 66fc01779..a2943a77b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -96,7 +96,6 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe } /** - * @ TODO 还要再优化 * 根据属性列表,自动生成属性上报事件和属性设置、获取服务 */ private void generateDefaultEventsAndServices(IotThinkModelFunctionSaveReqVO reqVO, IotThinkModelFunctionDO thinkModelFunction) { @@ -106,27 +105,65 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe properties = new ArrayList<>(); } - // 生成属性上报事件 - List events = reqVO.getEvents() != null ? new ArrayList<>(reqVO.getEvents()) : new ArrayList<>(); - ThingModelEvent propertyPostEvent = generatePropertyPostEvent(properties); - events.add(propertyPostEvent); + // 获取现有的事件和服务 + List existingEvents = reqVO.getEvents() != null ? new ArrayList<>(reqVO.getEvents()) : new ArrayList<>(); + List existingServices = reqVO.getServices() != null ? new ArrayList<>(reqVO.getServices()) : new ArrayList<>(); - // 生成属性设置和获取服务 - List services = reqVO.getServices() != null ? new ArrayList<>(reqVO.getServices()) : new ArrayList<>(); + // 生成或更新属性上报事件 + ThingModelEvent propertyPostEvent = generatePropertyPostEvent(properties); + updateEventInList(existingEvents, propertyPostEvent); + + // 生成或更新属性设置和获取服务 ThingModelService propertySetService = generatePropertySetService(properties); - if (propertySetService != null) { - services.add(propertySetService); - } + updateServiceInList(existingServices, propertySetService); + ThingModelService propertyGetService = generatePropertyGetService(properties); - if (propertyGetService != null) { - services.add(propertyGetService); - } + updateServiceInList(existingServices, propertyGetService); // 更新 thinkModelFunction 对象的 events 和 services 字段 - thinkModelFunction.setEvents(JSONUtil.toJsonStr(events)); - thinkModelFunction.setServices(JSONUtil.toJsonStr(services)); + thinkModelFunction.setEvents(JSONUtil.toJsonStr(existingEvents)); + thinkModelFunction.setServices(JSONUtil.toJsonStr(existingServices)); } + /** + * 在事件列表中更新或添加事件 + */ + private void updateEventInList(List events, ThingModelEvent newEvent) { + if (newEvent == null) { + return; + } + for (int i = 0; i < events.size(); i++) { + ThingModelEvent event = events.get(i); + if (event.getIdentifier().equals(newEvent.getIdentifier())) { + // 更新已有的事件 + events.set(i, newEvent); + return; + } + } + // 如果不存在,则添加新的事件 + events.add(newEvent); + } + + /** + * 在服务列表中更新或添加服务 + */ + private void updateServiceInList(List services, ThingModelService newService) { + if (newService == null) { + return; + } + for (int i = 0; i < services.size(); i++) { + ThingModelService service = services.get(i); + if (service.getIdentifier().equals(newService.getIdentifier())) { + // 更新已有的服务 + services.set(i, newService); + return; + } + } + // 如果不存在,则添加新的服务 + services.add(newService); + } + + /** * 生成属性上报事件 */ From 64fefaa6305027762e4836ae06dae3ebac961429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sat, 14 Sep 2024 08:59:55 +0800 Subject: [PATCH 16/31] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9AIOT=20?= =?UTF-8?q?=E5=BA=8F=E5=88=97=E5=8C=96=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E5=A4=84=E7=90=86=E3=80=81=E8=AF=B7=E6=B1=82=E7=A4=BA=E4=BE=8B?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IotThinkModelFunctionController.http | 21 +++++---- .../IotThinkModelFunctionConvert.java | 44 +++++++++++++++---- .../IotThinkModelFunctionServiceImpl.java | 12 ++++- 3 files changed, 57 insertions(+), 20 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http index e31540710..34a4054f6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http @@ -146,9 +146,9 @@ tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} { - "id": 1, - "productId": 1001, - "productKey": "smart-sensor-001", + "id": 3, + "productId": 1002, + "productKey": "smart-sensor-002", "properties": [ { "identifier": "Temperature", @@ -158,8 +158,8 @@ Authorization: Bearer {{token}} "dataType": { "type": "float", "specs": { - "min": -40.0, - "max": 125.0, + "min": -100.0, + "max": 200.0, "step": 0.1, "unit": "℃" } @@ -229,7 +229,8 @@ Authorization: Bearer {{token}} "name": "重启设备", "callType": "async", "inputData": [], - "description": "远程重启设备" + "description": "远程重启设备", + "method": "thing.service.reboot" }, { "identifier": "SetThreshold", @@ -251,7 +252,8 @@ Authorization: Bearer {{token}} "description": "报警温度阈值" } ], - "description": "设置设备的温度报警阈值" + "description": "设置设备的温度报警阈值", + "method": "thing.service.setThreshold" } ], "events": [ @@ -272,13 +274,14 @@ Authorization: Bearer {{token}} "description": "触发报警时的温度值" } ], - "description": "当温度超过阈值时触发高温报警事件" + "description": "当温度超过阈值时触发高温报警事件", + "method": "thing.event.highTemperatureAlert" } ] } ### 请求 /iot/think-model-function/get-by-product-key 接口 => 成功 -GET {{baseUrl}}/iot/think-model-function/get-by-product-key?productKey=123456 +GET {{baseUrl}}/iot/think-model-function/get-by-product-key?productKey=smart-sensor-002 tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java index 41e0c583b..aa7322eb3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java @@ -1,12 +1,13 @@ package cn.iocoder.yudao.module.iot.convert.thinkmodelfunction; -import cn.hutool.json.JSONUtil; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; @@ -19,6 +20,8 @@ public interface IotThinkModelFunctionConvert { IotThinkModelFunctionConvert INSTANCE = Mappers.getMapper(IotThinkModelFunctionConvert.class); + ObjectMapper objectMapper = new ObjectMapper(); + // 将 SaveReqVO 转换为 DO 对象,处理 properties, services, events 字段 @Mapping(target = "properties", expression = "java(convertPropertiesToJson(bean.getProperties()))") @Mapping(target = "services", expression = "java(convertServicesToJson(bean.getServices()))") @@ -26,15 +29,27 @@ public interface IotThinkModelFunctionConvert { IotThinkModelFunctionDO convert(IotThinkModelFunctionSaveReqVO bean); default String convertPropertiesToJson(List properties) { - return properties != null ? JSONUtil.toJsonStr(properties) : "[]"; + try { + return properties != null ? objectMapper.writeValueAsString(properties) : "[]"; + } catch (JsonProcessingException e) { + throw new RuntimeException("序列化 properties 时发生错误", e); + } } default String convertServicesToJson(List services) { - return services != null ? JSONUtil.toJsonStr(services) : "[]"; + try { + return services != null ? objectMapper.writeValueAsString(services) : "[]"; + } catch (JsonProcessingException e) { + throw new RuntimeException("序列化 services 时发生错误", e); + } } default String convertEventsToJson(List events) { - return events != null ? JSONUtil.toJsonStr(events) : "[]"; + try { + return events != null ? objectMapper.writeValueAsString(events) : "[]"; + } catch (JsonProcessingException e) { + throw new RuntimeException("序列化 events 时发生错误", e); + } } // 将 DO 转换为 RespVO 对象,处理 properties, services, events 字段 @@ -44,18 +59,29 @@ public interface IotThinkModelFunctionConvert { IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean); default List convertJsonToProperties(String propertiesJson) { - return propertiesJson != null ? JSONUtil.toList(propertiesJson, ThingModelProperty.class) : new ArrayList<>(); + try { + return propertiesJson != null ? objectMapper.readValue(propertiesJson, objectMapper.getTypeFactory().constructCollectionType(List.class, ThingModelProperty.class)) : new ArrayList<>(); + } catch (JsonProcessingException e) { + throw new RuntimeException("反序列化 properties 时发生错误", e); + } } default List convertJsonToServices(String servicesJson) { - return servicesJson != null ? JSONUtil.toList(servicesJson, ThingModelService.class) : new ArrayList<>(); + try { + return servicesJson != null ? objectMapper.readValue(servicesJson, objectMapper.getTypeFactory().constructCollectionType(List.class, ThingModelService.class)) : new ArrayList<>(); + } catch (JsonProcessingException e) { + throw new RuntimeException("反序列化 services 时发生错误", e); + } } default List convertJsonToEvents(String eventsJson) { - return eventsJson != null ? JSONUtil.toList(eventsJson, ThingModelEvent.class) : new ArrayList<>(); + try { + return eventsJson != null ? objectMapper.readValue(eventsJson, objectMapper.getTypeFactory().constructCollectionType(List.class, ThingModelEvent.class)) : new ArrayList<>(); + } catch (JsonProcessingException e) { + throw new RuntimeException("反序列化 events 时发生错误", e); + } } // 批量转换 DO 列表到 RespVO 列表 List convertList(List list); -} - +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index a2943a77b..559e0bed7 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -6,6 +6,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThi import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -27,6 +29,8 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe @Resource private IotThinkModelFunctionMapper thinkModelFunctionMapper; + private ObjectMapper objectMapper = new ObjectMapper(); + @Override public Long createThinkModelFunction(IotThinkModelFunctionSaveReqVO createReqVO) { log.info("创建物模型,参数:{}", createReqVO); @@ -121,8 +125,12 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe updateServiceInList(existingServices, propertyGetService); // 更新 thinkModelFunction 对象的 events 和 services 字段 - thinkModelFunction.setEvents(JSONUtil.toJsonStr(existingEvents)); - thinkModelFunction.setServices(JSONUtil.toJsonStr(existingServices)); + try { + thinkModelFunction.setEvents(objectMapper.writeValueAsString(existingEvents)); + thinkModelFunction.setServices(objectMapper.writeValueAsString(existingServices)); + } catch (JsonProcessingException e) { + throw new RuntimeException("序列化事件和服务时发生错误", e); + } } /** From 07b3ac20f613e4b1e7fd7442f802fbba72bf3d30 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 14 Sep 2024 09:44:09 +0800 Subject: [PATCH 17/31] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IOT=EF=BC=9A=E7=89=A9=E6=A8=A1=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thingModel/ThingModelArraySpecs.java | 9 --------- .../thingModel/ThingModelEvent.java | 10 +++++++++- .../thingModel/ThingModelProperty.java | 5 ++++- .../thingModel/ThingModelService.java | 10 +++++++++- .../{ => dataType}/ThingModelArgument.java | 9 +++++++-- .../dataType/ThingModelArraySpecs.java | 17 +++++++++++++++++ .../{ => dataType}/ThingModelArrayType.java | 7 ++++--- .../{ => dataType}/ThingModelBoolType.java | 4 +++- .../{ => dataType}/ThingModelDataType.java | 4 +++- .../{ => dataType}/ThingModelDateType.java | 6 +++--- .../{ => dataType}/ThingModelDoubleType.java | 6 +++--- .../{ => dataType}/ThingModelEnumType.java | 12 ++++++++---- .../{ => dataType}/ThingModelFloatType.java | 4 +++- .../{ => dataType}/ThingModelIntType.java | 6 +++--- .../{ => dataType}/ThingModelStructField.java | 4 +++- .../{ => dataType}/ThingModelStructType.java | 7 ++++--- .../{ => dataType}/ThingModelTextType.java | 13 +++++++++---- .../IotThinkModelFunctionDO.java | 18 ++++++++++++------ .../IotThinkModelFunctionServiceImpl.java | 5 ++++- 19 files changed, 108 insertions(+), 48 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelArgument.java (64%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArraySpecs.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelArrayType.java (67%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelBoolType.java (89%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelDataType.java (97%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelDateType.java (69%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelDoubleType.java (78%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelEnumType.java (52%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelFloatType.java (92%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelIntType.java (78%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelStructField.java (89%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelStructType.java (71%) rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/{ => dataType}/ThingModelTextType.java (63%) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java deleted file mode 100644 index 3ea23e8db..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java +++ /dev/null @@ -1,9 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; - -import lombok.Data; - -@Data -public class ThingModelArraySpecs { - private int size; // 数组长度 - private ThingModelDataType item; // 数组元素的类型 -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java index 857f688e9..96dff1adf 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java @@ -1,14 +1,22 @@ package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArgument; import lombok.Data; import java.util.List; @Data public class ThingModelEvent { + private String identifier; private String name; - private String type; // "info"、"alert"、"error" + /** + * 事件类型 + * + * "info"、"alert"、"error" + */ + private String type; private List outputData; private String description; private String method; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java index f82198152..4f9e32c59 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java @@ -1,13 +1,16 @@ package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelDataType; import lombok.Data; @Data public class ThingModelProperty { + private String identifier; private String name; private String accessMode; // "rw"、"r"、"w" - private boolean required; + private Boolean required; private ThingModelDataType dataType; private String description; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java index 521e9ab08..839ceff47 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java @@ -1,15 +1,23 @@ package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArgument; import lombok.Data; import java.util.List; @Data public class ThingModelService { + private String identifier; private String name; - private String callType; // "sync"、"async" + /** + * 调用类型 + * + * "sync"、"async" + */ + private String callType; private List inputData; private List outputData; private String description; private String method; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArgument.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArgument.java similarity index 64% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArgument.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArgument.java index 909d63459..2be24004e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArgument.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArgument.java @@ -1,12 +1,17 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; import lombok.Data; @Data public class ThingModelArgument { + private String identifier; private String name; private ThingModelDataType dataType; - private String direction; // 用于区分输入或输出参数,"input" 或 "output" + /** + * 用于区分输入或输出参数,"input" 或 "output" + */ + private String direction; private String description; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArraySpecs.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArraySpecs.java new file mode 100644 index 000000000..c3faf6161 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArraySpecs.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; + +import lombok.Data; + +@Data +public class ThingModelArraySpecs { + + /** + * 数组长度 + */ + private int size; + /** + * 数组元素的类型 + */ + private ThingModelDataType item; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArrayType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArrayType.java similarity index 67% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArrayType.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArrayType.java index 114add210..bab87be0a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArrayType.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelArrayType.java @@ -1,11 +1,12 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; import lombok.Data; -import lombok.EqualsAndHashCode; +// TODO @haohao:这个是不是和别的类,不太统一哈 @Data -@EqualsAndHashCode(callSuper = true) public class ThingModelArrayType extends ThingModelDataType { + private ThingModelArraySpecs specs; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelBoolType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelBoolType.java similarity index 89% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelBoolType.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelBoolType.java index f7e7e456b..b8ca64195 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelBoolType.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelBoolType.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; import lombok.Data; import lombok.EqualsAndHashCode; @@ -6,5 +6,7 @@ import lombok.EqualsAndHashCode; @Data @EqualsAndHashCode(callSuper = true) public class ThingModelBoolType extends ThingModelDataType { + // Bool 类型一般不需要额外的 specs + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDataType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDataType.java similarity index 97% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDataType.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDataType.java index 613cbd766..ec5f04bbb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDataType.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDataType.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; @@ -18,5 +18,7 @@ import lombok.Data; @JsonSubTypes.Type(value = ThingModelArrayType.class, name = "array") }) public abstract class ThingModelDataType { + private String type; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDateType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDateType.java similarity index 69% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDateType.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDateType.java index 11cb3a729..854229339 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDateType.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDateType.java @@ -1,10 +1,10 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; import lombok.Data; -import lombok.EqualsAndHashCode; @Data -@EqualsAndHashCode(callSuper = true) public class ThingModelDateType extends ThingModelDataType { + // Date 类型一般不需要额外的 specs + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDoubleType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDoubleType.java similarity index 78% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDoubleType.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDoubleType.java index d60302179..e5f3ad268 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDoubleType.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelDoubleType.java @@ -1,18 +1,18 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; import lombok.Data; -import lombok.EqualsAndHashCode; @Data -@EqualsAndHashCode(callSuper = true) public class ThingModelDoubleType extends ThingModelDataType { private ThingModelDoubleSpecs specs; } @Data class ThingModelDoubleSpecs { + private Double min; private Double max; private Double step; private String unit; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEnumType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelEnumType.java similarity index 52% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEnumType.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelEnumType.java index f76962661..3dcb068e9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEnumType.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelEnumType.java @@ -1,11 +1,15 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; import lombok.Data; -import lombok.EqualsAndHashCode; + import java.util.Map; @Data -@EqualsAndHashCode(callSuper = true) public class ThingModelEnumType extends ThingModelDataType { - private Map specs; // 枚举值和描述的键值对 + + /** + * 枚举值和描述的键值对 + */ + private Map specs; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelFloatType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelFloatType.java similarity index 92% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelFloatType.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelFloatType.java index c9d5516ad..27926fa49 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelFloatType.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelFloatType.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; import lombok.Data; import lombok.EqualsAndHashCode; @@ -11,8 +11,10 @@ public class ThingModelFloatType extends ThingModelDataType { @Data class ThingModelFloatSpecs { + private Float min; private Float max; private Float step; private String unit; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelIntType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelIntType.java similarity index 78% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelIntType.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelIntType.java index d48f50e47..a126eb749 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelIntType.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelIntType.java @@ -1,18 +1,18 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; import lombok.Data; -import lombok.EqualsAndHashCode; @Data -@EqualsAndHashCode(callSuper = true) public class ThingModelIntType extends ThingModelDataType { private ThingModelIntSpecs specs; } @Data class ThingModelIntSpecs { + private Integer min; private Integer max; private Integer step; private String unit; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructField.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructField.java similarity index 89% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructField.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructField.java index 449db55c2..5e079f22b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructField.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructField.java @@ -1,11 +1,13 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; import lombok.Data; @Data public class ThingModelStructField { + private String identifier; private String name; private ThingModelDataType dataType; private String description; + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructType.java similarity index 71% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructType.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructType.java index d3d35f16c..f0996513c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructType.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelStructType.java @@ -1,13 +1,14 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; import lombok.Data; -import lombok.EqualsAndHashCode; + import java.util.List; @Data -@EqualsAndHashCode(callSuper = true) public class ThingModelStructType extends ThingModelDataType { + private List specs; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelTextType.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelTextType.java similarity index 63% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelTextType.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelTextType.java index 0f6ea2bcb..16d1e402e 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelTextType.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/dataType/ThingModelTextType.java @@ -1,15 +1,20 @@ -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType; import lombok.Data; -import lombok.EqualsAndHashCode; @Data -@EqualsAndHashCode(callSuper = true) public class ThingModelTextType extends ThingModelDataType { + private ThingModelTextSpecs specs; + } @Data class ThingModelTextSpecs { - private Integer length; // 最大长度 + + /** + * 最大长度 + */ + private Integer length; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java index 564eefb2b..80fe0a65b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java @@ -1,42 +1,48 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; /** - * IoT 产品物模型 DO + * IoT 产品物模型功能 DO + * + * 每个 {@link IotProductDO} 和 {@link IotThinkModelFunctionDO} 是“一对多”的关系,它的每个属性、事件、服务都对应一条记录 * * @author 芋道源码 */ @TableName("iot_think_model_function") @KeySequence("iot_think_model_function_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor public class IotThinkModelFunctionDO extends BaseDO { /** - * 产品ID + * 物模型功能编号 */ @TableId private Long id; - + // TODO @haohao:是不是有一个 identifier,需要要有哈 + // TODO @haohao:name、description 属性,还有个类型 /** * 产品标识 + * + * 关联 {@link IotProductDO#getId()} */ private Long productId; - /** * 产品标识 + * + * 关联 {@link IotProductDO#getProductKey()} */ private String productKey; + // TODO @haohao:是不是可以搞成 ThingModelProperty、ThingModelEvent、ThingModelService 进行存储 /** * 属性列表 */ diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index 559e0bed7..6c8afe15f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -1,7 +1,10 @@ package cn.iocoder.yudao.module.iot.service.thinkmodelfunction; -import cn.hutool.json.JSONUtil; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.*; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArgument; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArraySpecs; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArrayType; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelTextType; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; From 84bc5aec1ec67a18654ba5ecb8cfea6bc41b1c94 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 14 Sep 2024 22:39:14 +0800 Subject: [PATCH 18/31] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IOT=EF=BC=9A=E7=89=A9=E6=A8=A1=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thingModel/ThingModelEvent.java | 12 ++- .../thingModel/ThingModelProperty.java | 17 +++- .../thingModel/ThingModelService.java | 12 ++- .../IotThinkModelFunctionDO2.java | 85 +++++++++++++++++++ 4 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO2.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java index 96dff1adf..d7fa68758 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java @@ -7,8 +7,19 @@ import java.util.List; @Data public class ThingModelEvent { + /** + * 事件标识符 + */ private String identifier; + /** + * 事件名称 + */ private String name; + /** + * 事件描述 + */ + private String description; + /** * 事件类型 * @@ -16,7 +27,6 @@ public class ThingModelEvent { */ private String type; private List outputData; - private String description; private String method; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java index 4f9e32c59..025d37e76 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java @@ -6,11 +6,22 @@ import lombok.Data; @Data public class ThingModelProperty { + /** + * 属性标识符 + */ private String identifier; + /** + * 属性名称 + */ private String name; - private String accessMode; // "rw"、"r"、"w" - private Boolean required; - private ThingModelDataType dataType; + /** + * 属性描述 + */ private String description; + private String accessMode; // "rw"、"r"、"w" + private Boolean required; + // TODO @haohao:这个是不是 dataSpecs 和 dataSpecsList?https://help.aliyun.com/zh/iot/developer-reference/api-a99t11 + private ThingModelDataType dataType; + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java index 839ceff47..d97e05e9c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java @@ -7,8 +7,19 @@ import java.util.List; @Data public class ThingModelService { + /** + * 服务标识符 + */ private String identifier; + /** + * 服务名称 + */ private String name; + /** + * 服务描述 + */ + private String description; + /** * 调用类型 * @@ -17,7 +28,6 @@ public class ThingModelService { private String callType; private List inputData; private List outputData; - private String description; private String method; } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO2.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO2.java new file mode 100644 index 000000000..ece631c77 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO2.java @@ -0,0 +1,85 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * IoT 产品物模型功能 DO + * + * 每个 {@link IotProductDO} 和 {@link IotThinkModelFunctionDO2} 是“一对多”的关系,它的每个属性、事件、服务都对应一条记录 + * + * @author 芋道源码 + */ +@TableName("iot_think_model_function") +@KeySequence("iot_think_model_function_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IotThinkModelFunctionDO2 extends BaseDO { + + /** + * 物模型功能编号 + */ + @TableId + private Long id; + + /** + * 功能标识 + */ + private String identifier; + /** + * 功能名称 + */ + private String name; + /** + * 功能描述 + */ + private String description; + + /** + * 产品标识 + * + * 关联 {@link IotProductDO#getId()} + */ + private Long productId; + /** + * 产品标识 + * + * 关联 {@link IotProductDO#getProductKey()} + */ + private String productKey; + + /** + * 功能类型 + * + * 1 - 属性 + * 2 - 服务 + * 3 - 事件 + */ + // TODO @haohao:枚举 + private Integer type; + + /** + * 属性 + */ + private ThingModelProperty property; + /** + * 事件 + */ + private ThingModelEvent event; + /** + * 服务 + */ + private String service; + +} \ No newline at end of file From 2932314ee0b838a822e63e3c225efc0fa41ca6a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sun, 15 Sep 2024 20:09:18 +0800 Subject: [PATCH 19/31] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9AIOT=20?= =?UTF-8?q?=E7=89=A9=E6=A8=A1=E5=9E=8B=E6=8E=A5=E5=8F=A3=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 1 + .../enums/product/IotThingModelTypeEnum.java | 47 +++ .../IotThinkModelFunctionController.http | 311 +++--------------- .../IotThinkModelFunctionController.java | 18 +- .../vo/IotThinkModelFunctionRespVO.java | 30 +- .../vo/IotThinkModelFunctionSaveReqVO.java | 33 +- .../IotThinkModelFunctionConvert.java | 78 ++--- .../IotThinkModelFunctionDO.java | 57 +++- .../IotThinkModelFunctionDO2.java | 85 ----- .../IotThinkModelFunctionMapper.java | 15 +- .../IotThinkModelFunctionService.java | 31 +- .../IotThinkModelFunctionServiceImpl.java | 281 +++++++++------- 12 files changed, 409 insertions(+), 578 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotThingModelTypeEnum.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO2.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index d26e5f2ec..e586d4535 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -17,4 +17,5 @@ public interface ErrorCodeConstants { // ========== IoT 产品物模型 1-050-002-000 ============ ErrorCode THINK_MODEL_FUNCTION_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在"); ErrorCode THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY = new ErrorCode(1_050_002_001, "ProductKey 对应的产品物模型已存在"); + ErrorCode THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER = new ErrorCode(1_050_002_002, "产品物模型标识已存在"); } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotThingModelTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotThingModelTypeEnum.java new file mode 100644 index 000000000..872dda6a3 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotThingModelTypeEnum.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.iot.enums.product; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * IOT 物模型功能类型枚举类 + * + * @author ahh + */ +@AllArgsConstructor +@Getter +public enum IotThingModelTypeEnum implements IntArrayValuable { + + /** + * 属性 + */ + PROPERTY(1, "属性"), + /** + * 服务 + */ + SERVICE(2, "服务"), + /** + * 事件 + */ + EVENT(3, "事件"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotThingModelTypeEnum::getType).toArray(); + + /** + * 类型 + */ + private final Integer type; + /** + * 描述 + */ + private final String description; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http index 34a4054f6..febf01014 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http @@ -5,137 +5,28 @@ tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} { - "productId": 1002, - "productKey": "smart-sensor-002", - "properties": [ - { - "identifier": "Temperature", - "name": "温度", - "accessMode": "r", - "required": true, - "dataType": { - "type": "float", - "specs": { - "min": -40.0, - "max": 125.0, - "step": 0.1, - "unit": "℃" - } - }, - "description": "当前温度值" + "productId": 1001, + "productKey": "smart-sensor-001", + "identifier": "Temperature", + "name": "温度", + "description": "当前温度值", + "type": 1, + "property": { + "identifier": "Temperature", + "name": "温度", + "accessMode": "r", + "required": true, + "dataType": { + "type": "float", + "specs": { + "min": -40.0, + "max": 125.0, + "step": 0.1, + "unit": "℃" + } }, - { - "identifier": "Humidity", - "name": "湿度", - "accessMode": "r", - "required": true, - "dataType": { - "type": "float", - "specs": { - "min": 0.0, - "max": 100.0, - "step": 0.1, - "unit": "%" - } - }, - "description": "当前湿度值" - }, - { - "identifier": "GeoLocation", - "name": "地理位置", - "accessMode": "r", - "required": false, - "dataType": { - "type": "struct", - "specs": [ - { - "identifier": "Longitude", - "name": "经度", - "dataType": { - "type": "double", - "specs": { - "min": -180.0, - "max": 180.0, - "step": 0.000001, - "unit": "°" - } - }, - "description": "设备所在位置的经度" - }, - { - "identifier": "Latitude", - "name": "纬度", - "dataType": { - "type": "double", - "specs": { - "min": -90.0, - "max": 90.0, - "step": 0.000001, - "unit": "°" - } - }, - "description": "设备所在位置的纬度" - } - ] - }, - "description": "设备的地理位置信息" - } - ], - "services": [ - { - "identifier": "Reboot", - "name": "重启设备", - "callType": "async", - "inputData": [], - "description": "远程重启设备", - "method": "thing.service.reboot" - }, - { - "identifier": "SetThreshold", - "name": "设置温度阈值", - "callType": "sync", - "inputData": [ - { - "identifier": "Threshold", - "name": "阈值", - "dataType": { - "type": "float", - "specs": { - "min": -40.0, - "max": 125.0, - "step": 0.1, - "unit": "℃" - } - }, - "description": "报警温度阈值" - } - ], - "description": "设置设备的温度报警阈值", - "method": "thing.service.setThreshold" - } - ], - "events": [ - { - "identifier": "HighTemperatureAlert", - "name": "高温报警", - "type": "alert", - "outputData": [ - { - "identifier": "CurrentTemperature", - "name": "当前温度", - "dataType": { - "type": "float", - "specs": { - "unit": "℃" - } - }, - "description": "触发报警时的温度值" - } - ], - "description": "当温度超过阈值时触发高温报警事件", - "method": "thing.event.highTemperatureAlert" - } - ] + "description": "当前温度值" + } } @@ -147,141 +38,37 @@ Authorization: Bearer {{token}} { "id": 3, - "productId": 1002, - "productKey": "smart-sensor-002", - "properties": [ - { - "identifier": "Temperature", - "name": "温度", - "accessMode": "r", - "required": true, - "dataType": { - "type": "float", - "specs": { - "min": -100.0, - "max": 200.0, - "step": 0.1, - "unit": "℃" - } - }, - "description": "当前温度值" + "productId": 1001, + "productKey": "smart-sensor-001", + "identifier": "Temperature", + "name": "温度", + "description": "当前温度值", + "type": 1, + "property": { + "identifier": "Temperature", + "name": "温度", + "accessMode": "r", + "required": true, + "dataType": { + "type": "float", + "specs": { + "min": -10.0, + "max": 100.0, + "step": 0.1, + "unit": "℃" + } }, - { - "identifier": "Humidity", - "name": "湿度", - "accessMode": "r", - "required": true, - "dataType": { - "type": "float", - "specs": { - "min": 0.0, - "max": 100.0, - "step": 0.1, - "unit": "%" - } - }, - "description": "当前湿度值" - }, - { - "identifier": "GeoLocation", - "name": "地理位置", - "accessMode": "r", - "required": false, - "dataType": { - "type": "struct", - "specs": [ - { - "identifier": "Longitude", - "name": "经度", - "dataType": { - "type": "double", - "specs": { - "min": -180.0, - "max": 180.0, - "step": 0.000001, - "unit": "°" - } - }, - "description": "设备所在位置的经度" - }, - { - "identifier": "Latitude", - "name": "纬度", - "dataType": { - "type": "double", - "specs": { - "min": -90.0, - "max": 90.0, - "step": 0.000001, - "unit": "°" - } - }, - "description": "设备所在位置的纬度" - } - ] - }, - "description": "设备的地理位置信息" - } - ], - "services": [ - { - "identifier": "Reboot", - "name": "重启设备", - "callType": "async", - "inputData": [], - "description": "远程重启设备", - "method": "thing.service.reboot" - }, - { - "identifier": "SetThreshold", - "name": "设置温度阈值", - "callType": "sync", - "inputData": [ - { - "identifier": "Threshold", - "name": "阈值", - "dataType": { - "type": "float", - "specs": { - "min": -40.0, - "max": 125.0, - "step": 0.1, - "unit": "℃" - } - }, - "description": "报警温度阈值" - } - ], - "description": "设置设备的温度报警阈值", - "method": "thing.service.setThreshold" - } - ], - "events": [ - { - "identifier": "HighTemperatureAlert", - "name": "高温报警", - "type": "alert", - "outputData": [ - { - "identifier": "CurrentTemperature", - "name": "当前温度", - "dataType": { - "type": "float", - "specs": { - "unit": "℃" - } - }, - "description": "触发报警时的温度值" - } - ], - "description": "当温度超过阈值时触发高温报警事件", - "method": "thing.event.highTemperatureAlert" - } - ] + "description": "当前温度值" + } } +### 请求 /iot/think-model-function/get 接口 => 成功 +GET {{baseUrl}}/iot/think-model-function/get?id=3 +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} -### 请求 /iot/think-model-function/get-by-product-key 接口 => 成功 -GET {{baseUrl}}/iot/think-model-function/get-by-product-key?productKey=smart-sensor-002 + +### 请求 /iot/think-model-function/list-by-product-id 接口 => 成功 +GET {{baseUrl}}/iot/think-model-function/list-by-product-id?productId=1001 tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java index a0051d9eb..36b91e85b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java @@ -15,6 +15,8 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import java.util.List; + import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @Tag(name = "管理后台 - IoT 产品物模型") @@ -50,23 +52,23 @@ public class IotThinkModelFunctionController { return success(true); } - @GetMapping("/get-by-product-key") + @GetMapping("/get") @Operation(summary = "获得IoT 产品物模型") - @Parameter(name = "productKey", description = "产品Key", required = true, example = "1024") + @Parameter(name = "id", description = "编号", required = true) @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')") - public CommonResult getThinkModelFunctionByProductKey(@RequestParam("productKey") String productKey) { - IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionService.getThinkModelFunctionByProductKey(productKey); + public CommonResult getThinkModelFunction(@RequestParam("id") Long id) { + IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionService.getThinkModelFunction(id); IotThinkModelFunctionRespVO respVO = IotThinkModelFunctionConvert.INSTANCE.convert(thinkModelFunction); return success(respVO); } - @GetMapping("/get-by-product-id") + @GetMapping("/list-by-product-id") @Operation(summary = "获得IoT 产品物模型") @Parameter(name = "productId", description = "产品ID", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')") - public CommonResult getThinkModelFunctionByProductId(@RequestParam("productId") Long productId) { - IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionService.getThinkModelFunctionByProductId(productId); - IotThinkModelFunctionRespVO respVO = IotThinkModelFunctionConvert.INSTANCE.convert(thinkModelFunction); + public CommonResult> getThinkModelFunctionListByProductId(@RequestParam("productId") Long productId) { + List thinkModelFunctionListByProductId = thinkModelFunctionService.getThinkModelFunctionListByProductId(productId); + List respVO = IotThinkModelFunctionConvert.INSTANCE.convertList(thinkModelFunctionListByProductId); return success(respVO); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java index 42ac727a4..9ef3f58d8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java @@ -20,21 +20,33 @@ public class IotThinkModelFunctionRespVO { @ExcelProperty("产品ID") private Long id; + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED) + private Long productId; + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("产品标识") private String productKey; - @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("属性列表") - private List properties; + @Schema(description = "功能标识", requiredMode = Schema.RequiredMode.REQUIRED) + private String identifier; - @Schema(description = "服务列表") - @ExcelProperty("服务列表") - private List services; + @Schema(description = "功能名称", requiredMode = Schema.RequiredMode.REQUIRED) + private String name; - @Schema(description = "事件列表") - @ExcelProperty("事件列表") - private List events; + @Schema(description = "功能描述", requiredMode = Schema.RequiredMode.REQUIRED) + private String description; + + @Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED) + private Integer type; + + @Schema(description = "属性", requiredMode = Schema.RequiredMode.REQUIRED) + private ThingModelProperty property; + + @Schema(description = "服务", requiredMode = Schema.RequiredMode.REQUIRED) + private ThingModelEvent event; + + @Schema(description = "事件", requiredMode = Schema.RequiredMode.REQUIRED) + private ThingModelService service; @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("创建时间") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java index 00132fa8b..106972fe3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java @@ -1,15 +1,15 @@ package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; +import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; +import cn.iocoder.yudao.module.iot.enums.product.IotThingModelTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; -import java.util.List; - @Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO") @Data public class IotThinkModelFunctionSaveReqVO { @@ -25,14 +25,29 @@ public class IotThinkModelFunctionSaveReqVO { @NotEmpty(message = "产品标识不能为空") private String productKey; - @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED) - @NotEmpty(message = "属性列表不能为空") - private List properties; + @Schema(description = "功能标识", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "功能标识不能为空") + private String identifier; - @Schema(description = "服务列表") - private List services; + @Schema(description = "功能名称", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "功能名称不能为空") + private String name; - @Schema(description = "事件列表") - private List events; + @Schema(description = "功能描述", requiredMode = Schema.RequiredMode.REQUIRED) + private String description; + + @Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "功能类型不能为空") + @InEnum(IotThingModelTypeEnum.class) + private Integer type; + + @Schema(description = "属性", requiredMode = Schema.RequiredMode.REQUIRED) + private ThingModelProperty property; + + @Schema(description = "服务", requiredMode = Schema.RequiredMode.REQUIRED) + private ThingModelService service; + + @Schema(description = "事件", requiredMode = Schema.RequiredMode.REQUIRED) + private ThingModelEvent event; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java index aa7322eb3..08dabd5d6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java @@ -6,82 +6,52 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingMode import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; +import cn.iocoder.yudao.module.iot.enums.product.IotThingModelTypeEnum; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; -import java.util.ArrayList; import java.util.List; +import java.util.Objects; @Mapper public interface IotThinkModelFunctionConvert { IotThinkModelFunctionConvert INSTANCE = Mappers.getMapper(IotThinkModelFunctionConvert.class); - ObjectMapper objectMapper = new ObjectMapper(); - - // 将 SaveReqVO 转换为 DO 对象,处理 properties, services, events 字段 - @Mapping(target = "properties", expression = "java(convertPropertiesToJson(bean.getProperties()))") - @Mapping(target = "services", expression = "java(convertServicesToJson(bean.getServices()))") - @Mapping(target = "events", expression = "java(convertEventsToJson(bean.getEvents()))") + // 将 SaveReqVO 转换为 DO + @Mapping(target = "property", expression = "java(convertToProperty(bean))") + @Mapping(target = "event", expression = "java(convertToEvent(bean))") + @Mapping(target = "service", expression = "java(convertToService(bean))") IotThinkModelFunctionDO convert(IotThinkModelFunctionSaveReqVO bean); - default String convertPropertiesToJson(List properties) { - try { - return properties != null ? objectMapper.writeValueAsString(properties) : "[]"; - } catch (JsonProcessingException e) { - throw new RuntimeException("序列化 properties 时发生错误", e); + default ThingModelProperty convertToProperty(IotThinkModelFunctionSaveReqVO bean) { + if (Objects.equals(bean.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { + return bean.getProperty(); } + return null; } - default String convertServicesToJson(List services) { - try { - return services != null ? objectMapper.writeValueAsString(services) : "[]"; - } catch (JsonProcessingException e) { - throw new RuntimeException("序列化 services 时发生错误", e); + default ThingModelEvent convertToEvent(IotThinkModelFunctionSaveReqVO bean) { + if (Objects.equals(bean.getType(), IotThingModelTypeEnum.EVENT.getType())) { + return bean.getEvent(); } + return null; } - default String convertEventsToJson(List events) { - try { - return events != null ? objectMapper.writeValueAsString(events) : "[]"; - } catch (JsonProcessingException e) { - throw new RuntimeException("序列化 events 时发生错误", e); + default ThingModelService convertToService(IotThinkModelFunctionSaveReqVO bean) { + if (Objects.equals(bean.getType(), IotThingModelTypeEnum.SERVICE.getType())) { + return bean.getService(); } + return null; } - // 将 DO 转换为 RespVO 对象,处理 properties, services, events 字段 - @Mapping(target = "properties", expression = "java(convertJsonToProperties(bean.getProperties()))") - @Mapping(target = "services", expression = "java(convertJsonToServices(bean.getServices()))") - @Mapping(target = "events", expression = "java(convertJsonToEvents(bean.getEvents()))") + // 将 DO 转换为 RespVO + @Mapping(target = "property", source = "property") + @Mapping(target = "event", source = "event") + @Mapping(target = "service", source = "service") IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean); - default List convertJsonToProperties(String propertiesJson) { - try { - return propertiesJson != null ? objectMapper.readValue(propertiesJson, objectMapper.getTypeFactory().constructCollectionType(List.class, ThingModelProperty.class)) : new ArrayList<>(); - } catch (JsonProcessingException e) { - throw new RuntimeException("反序列化 properties 时发生错误", e); - } - } - - default List convertJsonToServices(String servicesJson) { - try { - return servicesJson != null ? objectMapper.readValue(servicesJson, objectMapper.getTypeFactory().constructCollectionType(List.class, ThingModelService.class)) : new ArrayList<>(); - } catch (JsonProcessingException e) { - throw new RuntimeException("反序列化 services 时发生错误", e); - } - } - - default List convertJsonToEvents(String eventsJson) { - try { - return eventsJson != null ? objectMapper.readValue(eventsJson, objectMapper.getTypeFactory().constructCollectionType(List.class, ThingModelEvent.class)) : new ArrayList<>(); - } catch (JsonProcessingException e) { - throw new RuntimeException("反序列化 events 时发生错误", e); - } - } - - // 批量转换 DO 列表到 RespVO 列表 + // 批量转换 List convertList(List list); -} \ No newline at end of file +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java index 80fe0a65b..f05562452 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java @@ -1,20 +1,28 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import lombok.*; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; /** * IoT 产品物模型功能 DO - * + *

* 每个 {@link IotProductDO} 和 {@link IotThinkModelFunctionDO} 是“一对多”的关系,它的每个属性、事件、服务都对应一条记录 * * @author 芋道源码 */ -@TableName("iot_think_model_function") +@TableName(value = "iot_think_model_function", autoResultMap = true) @KeySequence("iot_think_model_function_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @Builder @@ -27,35 +35,56 @@ public class IotThinkModelFunctionDO extends BaseDO { */ @TableId private Long id; - // TODO @haohao:是不是有一个 identifier,需要要有哈 - // TODO @haohao:name、description 属性,还有个类型 + + /** + * 功能标识 + */ + private String identifier; + /** + * 功能名称 + */ + private String name; + /** + * 功能描述 + */ + private String description; + /** * 产品标识 - * + *

* 关联 {@link IotProductDO#getId()} */ private Long productId; /** * 产品标识 - * + *

* 关联 {@link IotProductDO#getProductKey()} */ private String productKey; - // TODO @haohao:是不是可以搞成 ThingModelProperty、ThingModelEvent、ThingModelService 进行存储 /** - * 属性列表 + * 功能类型 + *

+ * 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotThingModelTypeEnum} */ - private String properties; + private Integer type; /** - * 服务列表 + * 属性 */ - private String services; + @TableField(typeHandler = JacksonTypeHandler.class) + private ThingModelProperty property; /** - * 事件列表 + * 事件 */ - private String events; + @TableField(typeHandler = JacksonTypeHandler.class) + private ThingModelEvent event; + + /** + * 服务 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private ThingModelService service; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO2.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO2.java deleted file mode 100644 index ece631c77..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO2.java +++ /dev/null @@ -1,85 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction; - -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; -import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; -import com.baomidou.mybatisplus.annotation.KeySequence; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -/** - * IoT 产品物模型功能 DO - * - * 每个 {@link IotProductDO} 和 {@link IotThinkModelFunctionDO2} 是“一对多”的关系,它的每个属性、事件、服务都对应一条记录 - * - * @author 芋道源码 - */ -@TableName("iot_think_model_function") -@KeySequence("iot_think_model_function_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class IotThinkModelFunctionDO2 extends BaseDO { - - /** - * 物模型功能编号 - */ - @TableId - private Long id; - - /** - * 功能标识 - */ - private String identifier; - /** - * 功能名称 - */ - private String name; - /** - * 功能描述 - */ - private String description; - - /** - * 产品标识 - * - * 关联 {@link IotProductDO#getId()} - */ - private Long productId; - /** - * 产品标识 - * - * 关联 {@link IotProductDO#getProductKey()} - */ - private String productKey; - - /** - * 功能类型 - * - * 1 - 属性 - * 2 - 服务 - * 3 - 事件 - */ - // TODO @haohao:枚举 - private Integer type; - - /** - * 属性 - */ - private ThingModelProperty property; - /** - * 事件 - */ - private ThingModelEvent event; - /** - * 服务 - */ - private String service; - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java index 21ae1967a..dbd4cb359 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java @@ -5,6 +5,8 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + /** * IoT 产品物模型 Mapper * @@ -13,12 +15,17 @@ import org.apache.ibatis.annotations.Mapper; @Mapper public interface IotThinkModelFunctionMapper extends BaseMapperX { - default IotThinkModelFunctionDO selectByProductKey(String productKey) { - return selectOne(new LambdaQueryWrapperX().eq(IotThinkModelFunctionDO::getProductKey, productKey)); + default IotThinkModelFunctionDO selectByProductIdAndIdentifier(Long productId, String identifier) { + return selectOne(new LambdaQueryWrapperX().eq(IotThinkModelFunctionDO::getProductId, productId) + .eq(IotThinkModelFunctionDO::getIdentifier, identifier)); } - default IotThinkModelFunctionDO selectByProductId(Long productId){ - return selectOne(new LambdaQueryWrapperX().eq(IotThinkModelFunctionDO::getProductId, productId)); + default List selectListByProductId(Long productId) { + return selectList(new LambdaQueryWrapperX().eq(IotThinkModelFunctionDO::getProductId, productId)); } + default List selectListByProductIdAndType(Long productId, Integer type) { + return selectList(new LambdaQueryWrapperX().eq(IotThinkModelFunctionDO::getProductId, productId) + .eq(IotThinkModelFunctionDO::getType, type)); + } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java index d24ce0031..664df4fb9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java @@ -4,6 +4,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThi import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import jakarta.validation.Valid; +import java.util.List; + /** * IoT 产品物模型 Service 接口 * @@ -19,6 +21,14 @@ public interface IotThinkModelFunctionService { */ Long createThinkModelFunction(@Valid IotThinkModelFunctionSaveReqVO createReqVO); + + /** + * 更新IoT 产品物模型 + * + * @param updateReqVO 更新信息 + */ + void updateThinkModelFunction(@Valid IotThinkModelFunctionSaveReqVO updateReqVO); + /** * 删除IoT 产品物模型 * @@ -27,25 +37,18 @@ public interface IotThinkModelFunctionService { void deleteThinkModelFunction(Long id); /** - * 获得IoT 产品物模型,通过产品Key + * 获得IoT 产品物模型 * - * @param productKey 产品Key + * @param id 编号 * @return IoT 产品物模型 */ - IotThinkModelFunctionDO getThinkModelFunctionByProductKey(String productKey); + IotThinkModelFunctionDO getThinkModelFunction(Long id); /** - * 获得IoT 产品物模型,通过产品ID + * 获得IoT 产品物模型列表 * - * @param productId 产品ID - * @return IoT 产品物模型 + * @param productId 产品编号 + * @return IoT 产品物模型列表 */ - IotThinkModelFunctionDO getThinkModelFunctionByProductId(Long productId); - - /** - * 更新IoT 产品物模型 - * - * @param updateReqVO 更新信息 - */ - void updateThinkModelFunction(@Valid IotThinkModelFunctionSaveReqVO updateReqVO); + List getThinkModelFunctionListByProductId(Long productId); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index 6c8afe15f..92ed900cc 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -1,6 +1,9 @@ package cn.iocoder.yudao.module.iot.service.thinkmodelfunction; -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.*; +import cn.iocoder.yudao.framework.common.validation.Telephone; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArgument; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArraySpecs; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArrayType; @@ -9,19 +12,20 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThi import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; +import cn.iocoder.yudao.module.iot.enums.product.IotThingModelTypeEnum; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS; @Slf4j @@ -32,38 +36,83 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe @Resource private IotThinkModelFunctionMapper thinkModelFunctionMapper; - private ObjectMapper objectMapper = new ObjectMapper(); - @Override public Long createThinkModelFunction(IotThinkModelFunctionSaveReqVO createReqVO) { - log.info("创建物模型,参数:{}", createReqVO); - // 验证 ProductKey 对应的产品物模型是否已存在 - validateThinkModelFunctionNotExistsByProductKey(createReqVO.getProductKey()); + // 校验功能标识符在同一产品下是否唯一 + validateIdentifierUnique(createReqVO.getProductId(), createReqVO.getIdentifier()); + // 转换请求对象为数据对象 IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO); - // 自动生成属性上报事件和属性设置、获取服务 - generateDefaultEventsAndServices(createReqVO, thinkModelFunction); + // 插入数据库 thinkModelFunctionMapper.insert(thinkModelFunction); + + // 如果创建的是属性,需要更新默认的事件和服务 + if (Objects.equals(createReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { + generateDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); + } + // 返回生成的 ID return thinkModelFunction.getId(); } - private void validateThinkModelFunctionNotExistsByProductKey(String productKey) { - if (thinkModelFunctionMapper.selectByProductKey(productKey) != null) { - throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY); + private void validateIdentifierUnique(Long productId, String identifier) { + IotThinkModelFunctionDO existingFunction = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier); + if (existingFunction != null) { + throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER); } } @Override - public void deleteThinkModelFunction(Long id) { - log.info("删除物模型,id:{}", id); - // 校验物模型是否存在 - validateThinkModelFunctionExists(id); - // 删除物模型 - thinkModelFunctionMapper.deleteById(id); + public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) { + // 校验功能是否存在 + validateThinkModelFunctionExists(updateReqVO.getId()); + + // 校验功能标识符是否唯一 + validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier()); + + // 转换请求对象为数据对象 + IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO); + + // 更新数据库 + thinkModelFunctionMapper.updateById(thinkModelFunction); + + // 如果更新的是属性,需要更新默认的事件和服务 + if (Objects.equals(updateReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { + generateDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey()); + } } + private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) { + IotThinkModelFunctionDO existingFunction = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier); + if (existingFunction != null && !existingFunction.getId().equals(id)) { + throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER); + } + } + + + @Override + public void deleteThinkModelFunction(Long id) { + // 校验功能是否存在 + IotThinkModelFunctionDO functionDO = thinkModelFunctionMapper.selectById(id); + if (functionDO == null) { + throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS); + } + + // 删除功能 + thinkModelFunctionMapper.deleteById(id); + + // 如果删除的是属性,需要更新默认的事件和服务 + if (Objects.equals(functionDO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { + generateDefaultEventsAndServices(functionDO.getProductId(), functionDO.getProductKey()); + } + } + + /** + * 校验功能是否存在 + * + * @param id 功能编号 + */ private void validateThinkModelFunctionExists(Long id) { if (thinkModelFunctionMapper.selectById(id) == null) { throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS); @@ -71,114 +120,49 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe } @Override - public IotThinkModelFunctionDO getThinkModelFunctionByProductKey(String productKey) { - return thinkModelFunctionMapper.selectByProductKey(productKey); + public IotThinkModelFunctionDO getThinkModelFunction(Long id) { + return thinkModelFunctionMapper.selectById(id); } @Override - public IotThinkModelFunctionDO getThinkModelFunctionByProductId(Long productId) { - return thinkModelFunctionMapper.selectByProductId(productId); - } - - @Override - public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) { - log.info("更新物模型,参数:{}", updateReqVO); - // 校验物模型是否存在 - validateThinkModelFunctionExists(updateReqVO.getId()); - // 校验 ProductKey 是否唯一 - validateProductKeyUnique(updateReqVO.getId(), updateReqVO.getProductKey()); - // 转换请求对象为数据对象 - IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO); - // 自动生成或更新属性上报事件和属性设置、获取服务 - generateDefaultEventsAndServices(updateReqVO, thinkModelFunction); - // 更新数据库 - thinkModelFunctionMapper.updateById(thinkModelFunction); - } - - private void validateProductKeyUnique(Long id, String productKey) { - IotThinkModelFunctionDO existingFunction = thinkModelFunctionMapper.selectByProductKey(productKey); - if (existingFunction != null && !existingFunction.getId().equals(id)) { - throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY); - } + public List getThinkModelFunctionListByProductId(Long productId) { + return thinkModelFunctionMapper.selectListByProductId(productId); } /** - * 根据属性列表,自动生成属性上报事件和属性设置、获取服务 + * 生成默认的事件和服务 */ - private void generateDefaultEventsAndServices(IotThinkModelFunctionSaveReqVO reqVO, IotThinkModelFunctionDO thinkModelFunction) { - // 获取属性列表 - List properties = reqVO.getProperties(); - if (properties == null) { - properties = new ArrayList<>(); + public void generateDefaultEventsAndServices(Long productId, String productKey) { + // 获取当前产品的所有属性列表 + List propertyList = thinkModelFunctionMapper.selectListByProductIdAndType(productId, IotThingModelTypeEnum.PROPERTY.getType()); + + // 生成属性上报事件 + ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList); + if (propertyPostEvent != null) { + saveOrUpdateEvent(productId, productKey, propertyPostEvent); } - // 获取现有的事件和服务 - List existingEvents = reqVO.getEvents() != null ? new ArrayList<>(reqVO.getEvents()) : new ArrayList<>(); - List existingServices = reqVO.getServices() != null ? new ArrayList<>(reqVO.getServices()) : new ArrayList<>(); + // 生成属性设置服务 + ThingModelService propertySetService = generatePropertySetService(propertyList); + if (propertySetService != null) { + saveOrUpdateService(productId, productKey, propertySetService); + } - // 生成或更新属性上报事件 - ThingModelEvent propertyPostEvent = generatePropertyPostEvent(properties); - updateEventInList(existingEvents, propertyPostEvent); - - // 生成或更新属性设置和获取服务 - ThingModelService propertySetService = generatePropertySetService(properties); - updateServiceInList(existingServices, propertySetService); - - ThingModelService propertyGetService = generatePropertyGetService(properties); - updateServiceInList(existingServices, propertyGetService); - - // 更新 thinkModelFunction 对象的 events 和 services 字段 - try { - thinkModelFunction.setEvents(objectMapper.writeValueAsString(existingEvents)); - thinkModelFunction.setServices(objectMapper.writeValueAsString(existingServices)); - } catch (JsonProcessingException e) { - throw new RuntimeException("序列化事件和服务时发生错误", e); + // 生成属性获取服务 + ThingModelService propertyGetService = generatePropertyGetService(propertyList); + if (propertyGetService != null) { + saveOrUpdateService(productId, productKey, propertyGetService); } } - /** - * 在事件列表中更新或添加事件 - */ - private void updateEventInList(List events, ThingModelEvent newEvent) { - if (newEvent == null) { - return; - } - for (int i = 0; i < events.size(); i++) { - ThingModelEvent event = events.get(i); - if (event.getIdentifier().equals(newEvent.getIdentifier())) { - // 更新已有的事件 - events.set(i, newEvent); - return; - } - } - // 如果不存在,则添加新的事件 - events.add(newEvent); - } - - /** - * 在服务列表中更新或添加服务 - */ - private void updateServiceInList(List services, ThingModelService newService) { - if (newService == null) { - return; - } - for (int i = 0; i < services.size(); i++) { - ThingModelService service = services.get(i); - if (service.getIdentifier().equals(newService.getIdentifier())) { - // 更新已有的服务 - services.set(i, newService); - return; - } - } - // 如果不存在,则添加新的服务 - services.add(newService); - } - - /** * 生成属性上报事件 */ - private ThingModelEvent generatePropertyPostEvent(List properties) { + private ThingModelEvent generatePropertyPostEvent(List propertyList) { + if (propertyList == null || propertyList.isEmpty()) { + return null; + } + ThingModelEvent event = new ThingModelEvent(); event.setIdentifier("post"); event.setName("属性上报"); @@ -188,7 +172,8 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe // 将属性列表转换为事件的输出参数 List outputData = new ArrayList<>(); - for (ThingModelProperty property : properties) { + for (IotThinkModelFunctionDO functionDO : propertyList) { + ThingModelProperty property = functionDO.getProperty(); ThingModelArgument arg = new ThingModelArgument(); arg.setIdentifier(property.getIdentifier()); arg.setName(property.getName()); @@ -205,9 +190,14 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe /** * 生成属性设置服务 */ - private ThingModelService generatePropertySetService(List properties) { + private ThingModelService generatePropertySetService(List propertyList) { + if (propertyList == null || propertyList.isEmpty()) { + return null; + } + List inputData = new ArrayList<>(); - for (ThingModelProperty property : properties) { + for (IotThinkModelFunctionDO functionDO : propertyList) { + ThingModelProperty property = functionDO.getProperty(); if ("w".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) { ThingModelArgument arg = new ThingModelArgument(); arg.setIdentifier(property.getIdentifier()); @@ -239,9 +229,14 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe /** * 生成属性获取服务 */ - private ThingModelService generatePropertyGetService(List properties) { + private ThingModelService generatePropertyGetService(List propertyList) { + if (propertyList == null || propertyList.isEmpty()) { + return null; + } + List outputData = new ArrayList<>(); - for (ThingModelProperty property : properties) { + for (IotThinkModelFunctionDO functionDO : propertyList) { + ThingModelProperty property = functionDO.getProperty(); if ("r".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) { ThingModelArgument arg = new ThingModelArgument(); arg.setIdentifier(property.getIdentifier()); @@ -275,10 +270,8 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe ThingModelArrayType arrayType = new ThingModelArrayType(); arrayType.setType("array"); ThingModelArraySpecs arraySpecs = new ThingModelArraySpecs(); - // 不指定数组长度,size 可以为 0 或者省略 ThingModelTextType textType = new ThingModelTextType(); textType.setType("text"); - // 如果有需要,可以设置 TextType 的 specs,如长度限制 arraySpecs.setItem(textType); arrayType.setSpecs(arraySpecs); @@ -289,4 +282,54 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe return service; } + + /** + * 保存或更新事件 + */ + private void saveOrUpdateEvent(Long productId, String productKey, ThingModelEvent event) { + // 检查是否已存在相同的事件 + IotThinkModelFunctionDO existingEvent = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, event.getIdentifier()); + IotThinkModelFunctionDO functionDO = new IotThinkModelFunctionDO(); + functionDO.setProductId(productId); + functionDO.setProductKey(productKey); + functionDO.setIdentifier(event.getIdentifier()); + functionDO.setName(event.getName()); + functionDO.setDescription(event.getDescription()); + functionDO.setType(IotThingModelTypeEnum.EVENT.getType()); + functionDO.setEvent(event); + + if (existingEvent != null) { + // 更新事件 + functionDO.setId(existingEvent.getId()); + thinkModelFunctionMapper.updateById(functionDO); + } else { + // 创建新的事件 + thinkModelFunctionMapper.insert(functionDO); + } + } + + /** + * 保存或更新事服务 + */ + private void saveOrUpdateService(Long productId, String productKey, ThingModelService service) { + // 检查是否已存在相同的服务 + IotThinkModelFunctionDO existingService = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, service.getIdentifier()); + IotThinkModelFunctionDO functionDO = new IotThinkModelFunctionDO(); + functionDO.setProductId(productId); + functionDO.setProductKey(productKey); + functionDO.setIdentifier(service.getIdentifier()); + functionDO.setName(service.getName()); + functionDO.setDescription(service.getDescription()); + functionDO.setType(IotThingModelTypeEnum.SERVICE.getType()); + functionDO.setService(service); + + if (existingService != null) { + // 更新服务 + functionDO.setId(existingService.getId()); + thinkModelFunctionMapper.updateById(functionDO); + } else { + // 创建新的服务 + thinkModelFunctionMapper.insert(functionDO); + } + } } From c0e2bdbdd48c4f8554724776dcb9149294c433a7 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 16 Sep 2024 20:00:47 +0800 Subject: [PATCH 20/31] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IOT=EF=BC=9A=E7=89=A9=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E7=9A=84=20review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/db/TenantDatabaseInterceptor.java | 2 +- .../IotThinkModelFunctionMapper.java | 12 ++-- .../IotThinkModelFunctionService.java | 14 ++--- .../IotThinkModelFunctionServiceImpl.java | 63 ++++++++++--------- 4 files changed, 46 insertions(+), 45 deletions(-) diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java index 8ea1a96b8..e220f8bcf 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java +++ b/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; /** * 基于 MyBatis Plus 多租户的功能,实现 DB 层面的多租户的功能 * - * @author 芋道源码 + * @author */ public class TenantDatabaseInterceptor implements TenantLineHandler { diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java index dbd4cb359..214d5c167 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import org.apache.ibatis.annotations.Mapper; @@ -16,16 +15,17 @@ import java.util.List; public interface IotThinkModelFunctionMapper extends BaseMapperX { default IotThinkModelFunctionDO selectByProductIdAndIdentifier(Long productId, String identifier) { - return selectOne(new LambdaQueryWrapperX().eq(IotThinkModelFunctionDO::getProductId, productId) - .eq(IotThinkModelFunctionDO::getIdentifier, identifier)); + return selectOne(IotThinkModelFunctionDO::getProductId, productId, + IotThinkModelFunctionDO::getIdentifier, identifier); } default List selectListByProductId(Long productId) { - return selectList(new LambdaQueryWrapperX().eq(IotThinkModelFunctionDO::getProductId, productId)); + return selectList(IotThinkModelFunctionDO::getProductId, productId); } default List selectListByProductIdAndType(Long productId, Integer type) { - return selectList(new LambdaQueryWrapperX().eq(IotThinkModelFunctionDO::getProductId, productId) - .eq(IotThinkModelFunctionDO::getType, type)); + return selectList(IotThinkModelFunctionDO::getProductId, productId, + IotThinkModelFunctionDO::getType, type); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java index 664df4fb9..e2a5ad38d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java @@ -14,7 +14,7 @@ import java.util.List; public interface IotThinkModelFunctionService { /** - * 创建IoT 产品物模型 + * 创建产品物模型 * * @param createReqVO 创建信息 * @return 编号 @@ -23,32 +23,32 @@ public interface IotThinkModelFunctionService { /** - * 更新IoT 产品物模型 + * 更新产品物模型 * * @param updateReqVO 更新信息 */ void updateThinkModelFunction(@Valid IotThinkModelFunctionSaveReqVO updateReqVO); /** - * 删除IoT 产品物模型 + * 删除产品物模型 * * @param id 编号 */ void deleteThinkModelFunction(Long id); /** - * 获得IoT 产品物模型 + * 获得产品物模型 * * @param id 编号 - * @return IoT 产品物模型 + * @return 产品物模型 */ IotThinkModelFunctionDO getThinkModelFunction(Long id); /** - * 获得IoT 产品物模型列表 + * 获得产品物模型列表 * * @param productId 产品编号 - * @return IoT 产品物模型列表 + * @return 产品物模型列表 */ List getThinkModelFunctionListByProductId(Long productId); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index 92ed900cc..bc90cff24 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.iot.service.thinkmodelfunction; -import cn.iocoder.yudao.framework.common.validation.Telephone; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; @@ -16,7 +15,6 @@ import cn.iocoder.yudao.module.iot.enums.product.IotThingModelTypeEnum; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.ArrayList; @@ -28,81 +26,83 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS; -@Slf4j +/** + * IoT 产品物模型 Service 实现类 + * + * @author 芋道源码 + */ @Service @Validated +@Slf4j public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionService { @Resource private IotThinkModelFunctionMapper thinkModelFunctionMapper; @Override + // TODO @haohao:事务 public Long createThinkModelFunction(IotThinkModelFunctionSaveReqVO createReqVO) { - // 校验功能标识符在同一产品下是否唯一 + // 1. 校验功能标识符在同一产品下是否唯一 validateIdentifierUnique(createReqVO.getProductId(), createReqVO.getIdentifier()); - // 转换请求对象为数据对象 - IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO); + // 2. 插入数据库 + IotThinkModelFunctionDO function = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO); + thinkModelFunctionMapper.insert(function); - // 插入数据库 - thinkModelFunctionMapper.insert(thinkModelFunction); - - // 如果创建的是属性,需要更新默认的事件和服务 + // 3. 如果创建的是属性,需要更新默认的事件和服务 if (Objects.equals(createReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { + // TODO @haohao:最好使用 createDefaultEventsAndServices。原因是:generate 更多在目前项目里,是创建对象,不涉及到 insert db。 generateDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); } - - // 返回生成的 ID - return thinkModelFunction.getId(); + return function.getId(); } private void validateIdentifierUnique(Long productId, String identifier) { - IotThinkModelFunctionDO existingFunction = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier); - if (existingFunction != null) { + IotThinkModelFunctionDO function = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier); + if (function != null) { throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER); } } @Override + // TODO @haohao:事务 public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) { - // 校验功能是否存在 + // 1.1 校验功能是否存在 validateThinkModelFunctionExists(updateReqVO.getId()); - - // 校验功能标识符是否唯一 + // 1.2 校验功能标识符是否唯一 validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier()); - // 转换请求对象为数据对象 + // 2. 更新数据库 IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO); - - // 更新数据库 thinkModelFunctionMapper.updateById(thinkModelFunction); - // 如果更新的是属性,需要更新默认的事件和服务 + // 3. 如果更新的是属性,需要更新默认的事件和服务 if (Objects.equals(updateReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { generateDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey()); } } private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) { - IotThinkModelFunctionDO existingFunction = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier); - if (existingFunction != null && !existingFunction.getId().equals(id)) { + IotThinkModelFunctionDO function = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier); + // TODO !function.getId().equals(id) 使用 ObjectUtil.notEquals 。逻辑里,尽量避免 ! 取反。用不等于会比 ! 更容易理解 + if (function != null && !function.getId().equals(id)) { throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER); } } - @Override + // TODO @haohao:事务 public void deleteThinkModelFunction(Long id) { - // 校验功能是否存在 + // 1. 校验功能是否存在 IotThinkModelFunctionDO functionDO = thinkModelFunctionMapper.selectById(id); if (functionDO == null) { throw exception(THINK_MODEL_FUNCTION_NOT_EXISTS); } - // 删除功能 + // 2. 删除功能 thinkModelFunctionMapper.deleteById(id); - // 如果删除的是属性,需要更新默认的事件和服务 + // 3. 如果删除的是属性,需要更新默认的事件和服务 if (Objects.equals(functionDO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { generateDefaultEventsAndServices(functionDO.getProductId(), functionDO.getProductKey()); } @@ -159,10 +159,12 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe * 生成属性上报事件 */ private ThingModelEvent generatePropertyPostEvent(List propertyList) { + // TODO @haohao:用 CollUtil.isNotEmpty 会更容易哈 if (propertyList == null || propertyList.isEmpty()) { return null; } + // TODO @haohao:可以考虑链式调用,简化整个方法的长度;然后,把相同类型的户型,尽量再放同一行,看起来轻松点;其它类似的,也可以试试看哈 ThingModelEvent event = new ThingModelEvent(); event.setIdentifier("post"); event.setName("属性上报"); @@ -183,7 +185,6 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe outputData.add(arg); } event.setOutputData(outputData); - return event; } @@ -222,7 +223,6 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe service.setInputData(inputData); // 属性设置服务一般不需要输出参数 service.setOutputData(new ArrayList<>()); - return service; } @@ -237,6 +237,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe List outputData = new ArrayList<>(); for (IotThinkModelFunctionDO functionDO : propertyList) { ThingModelProperty property = functionDO.getProperty(); + // TODO @haohao:r、rw 是不是枚举起来 if ("r".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) { ThingModelArgument arg = new ThingModelArgument(); arg.setIdentifier(property.getIdentifier()); @@ -279,7 +280,6 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe service.setInputData(Collections.singletonList(inputArg)); service.setOutputData(outputData); - return service; } @@ -298,6 +298,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe functionDO.setType(IotThingModelTypeEnum.EVENT.getType()); functionDO.setEvent(event); + // TODO @haohao:会不会存在删除的情况哈?另外,项目里有 diffList 方法,看看是不是可以方便的,适合这个场景。具体怎么用,可以全局搜 if (existingEvent != null) { // 更新事件 functionDO.setId(existingEvent.getId()); From edc6a8ad4a77b122b88da4db31525aea4ae3d369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Mon, 16 Sep 2024 21:42:10 +0800 Subject: [PATCH 21/31] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9AIOT=20?= =?UTF-8?q?=E7=89=A9=E6=A8=A1=E5=9E=8B=E6=8E=A5=E5=8F=A3=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E4=BA=8B=E7=89=A9=EF=BC=8C=E4=BC=98=E5=8C=96=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E7=9A=84=E4=BA=8B=E4=BB=B6=E5=92=8C=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 3 + .../iot/enums/product/IotAccessModeEnum.java | 25 ++ .../IotThinkModelFunctionController.http | 9 +- .../IotThinkModelFunctionMapper.java | 6 + .../iot/emq/service/EmqxServiceImpl.java | 2 +- .../IotThinkModelFunctionServiceImpl.java | 294 ++++++++++-------- 6 files changed, 212 insertions(+), 127 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index e586d4535..7677ef89d 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -18,4 +18,7 @@ public interface ErrorCodeConstants { ErrorCode THINK_MODEL_FUNCTION_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在"); ErrorCode THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY = new ErrorCode(1_050_002_001, "ProductKey 对应的产品物模型已存在"); ErrorCode THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER = new ErrorCode(1_050_002_002, "产品物模型标识已存在"); + + // ========== IoT 设备 1-050-003-000 ============ + ErrorCode DEVICE_NOT_EXISTS = new ErrorCode(1_050_003_000, "设备不存在"); } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java new file mode 100644 index 000000000..630240b86 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.iot.enums.product; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * IOT 访问方式枚举类 + * + * @author ahh + */ +@AllArgsConstructor +@Getter +public enum IotAccessModeEnum { + + READ("r"), + WRITE("w"), + READ_WRITE("rw"); + + private final String mode; + + public String getMode() { + return mode; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http index febf01014..6b9032fc6 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http @@ -37,7 +37,7 @@ tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} { - "id": 3, + "id": 1, "productId": 1001, "productKey": "smart-sensor-001", "identifier": "Temperature", @@ -62,8 +62,13 @@ Authorization: Bearer {{token}} } } +### 请求 /iot/think-model-function/delete 接口 => 成功 +DELETE {{baseUrl}}/iot/think-model-function/delete?id=1 +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} + ### 请求 /iot/think-model-function/get 接口 => 成功 -GET {{baseUrl}}/iot/think-model-function/get?id=3 +GET {{baseUrl}}/iot/think-model-function/get?id=4 tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java index 214d5c167..8c29c7eab 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import org.apache.ibatis.annotations.Mapper; @@ -28,4 +29,9 @@ public interface IotThinkModelFunctionMapper extends BaseMapperX selectListByProductIdAndTypes(Long productId, List list) { + return selectList(new LambdaQueryWrapperX() + .eq(IotThinkModelFunctionDO::getProductId, productId) + .in(IotThinkModelFunctionDO::getType, list)); + } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java index 0f1a53cd0..0c1a87f7f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/emq/service/EmqxServiceImpl.java @@ -30,7 +30,7 @@ public class EmqxServiceImpl implements EmqxService { public void subscribe(MqttClient client) { try { // 订阅默认主题,可以根据需要修改 - client.subscribe("$share/yudao/+/+/#", 1); +// client.subscribe("$share/yudao/+/+/#", 1); log.info("订阅默认主题成功"); } catch (Exception e) { log.error("订阅默认主题失败", e); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index bc90cff24..9d5d1e650 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.iot.service.thinkmodelfunction; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; @@ -11,18 +13,19 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThi import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper; +import cn.iocoder.yudao.module.iot.enums.product.IotAccessModeEnum; import cn.iocoder.yudao.module.iot.enums.product.IotThingModelTypeEnum; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; +import java.util.*; +import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS; @@ -40,7 +43,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe private IotThinkModelFunctionMapper thinkModelFunctionMapper; @Override - // TODO @haohao:事务 + @Transactional(rollbackFor = Exception.class) public Long createThinkModelFunction(IotThinkModelFunctionSaveReqVO createReqVO) { // 1. 校验功能标识符在同一产品下是否唯一 validateIdentifierUnique(createReqVO.getProductId(), createReqVO.getIdentifier()); @@ -51,8 +54,11 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe // 3. 如果创建的是属性,需要更新默认的事件和服务 if (Objects.equals(createReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { - // TODO @haohao:最好使用 createDefaultEventsAndServices。原因是:generate 更多在目前项目里,是创建对象,不涉及到 insert db。 - generateDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); + // 获取当前属性列表,并添加新插入的属性 + List propertyList = thinkModelFunctionMapper + .selectListByProductIdAndType(createReqVO.getProductId(), IotThingModelTypeEnum.PROPERTY.getType()); + propertyList.add(function); + createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey(), propertyList); } return function.getId(); } @@ -65,33 +71,41 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe } @Override - // TODO @haohao:事务 + @Transactional(rollbackFor = Exception.class) public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) { - // 1.1 校验功能是否存在 + // 1. 校验功能是否存在 validateThinkModelFunctionExists(updateReqVO.getId()); - // 1.2 校验功能标识符是否唯一 + // 2. 校验功能标识符是否唯一 validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier()); - // 2. 更新数据库 + // 3. 更新数据库 IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO); thinkModelFunctionMapper.updateById(thinkModelFunction); - // 3. 如果更新的是属性,需要更新默认的事件和服务 + // 4. 如果更新的是属性,需要更新默认的事件和服务 if (Objects.equals(updateReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { - generateDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey()); + // 获取当前属性列表,更新其中的属性 + List propertyList = thinkModelFunctionMapper + .selectListByProductIdAndType(updateReqVO.getProductId(), IotThingModelTypeEnum.PROPERTY.getType()); + for (int i = 0; i < propertyList.size(); i++) { + if (propertyList.get(i).getId().equals(thinkModelFunction.getId())) { + propertyList.set(i, thinkModelFunction); + break; + } + } + createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey(), propertyList); } } private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) { IotThinkModelFunctionDO function = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, identifier); - // TODO !function.getId().equals(id) 使用 ObjectUtil.notEquals 。逻辑里,尽量避免 ! 取反。用不等于会比 ! 更容易理解 - if (function != null && !function.getId().equals(id)) { + if (function != null && ObjectUtil.notEqual(function.getId(), id)) { throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER); } } @Override - // TODO @haohao:事务 + @Transactional(rollbackFor = Exception.class) public void deleteThinkModelFunction(Long id) { // 1. 校验功能是否存在 IotThinkModelFunctionDO functionDO = thinkModelFunctionMapper.selectById(id); @@ -104,7 +118,11 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe // 3. 如果删除的是属性,需要更新默认的事件和服务 if (Objects.equals(functionDO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { - generateDefaultEventsAndServices(functionDO.getProductId(), functionDO.getProductKey()); + // 获取当前属性列表,移除已删除的属性 + List propertyList = thinkModelFunctionMapper + .selectListByProductIdAndType(functionDO.getProductId(), IotThingModelTypeEnum.PROPERTY.getType()); + propertyList.removeIf(property -> property.getId().equals(id)); + createDefaultEventsAndServices(functionDO.getProductId(), functionDO.getProductKey(), propertyList); } } @@ -130,58 +148,137 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe } /** - * 生成默认的事件和服务 + * 创建默认的事件和服务 */ - public void generateDefaultEventsAndServices(Long productId, String productKey) { - // 获取当前产品的所有属性列表 - List propertyList = thinkModelFunctionMapper.selectListByProductIdAndType(productId, IotThingModelTypeEnum.PROPERTY.getType()); + public void createDefaultEventsAndServices(Long productId, String productKey, List propertyList) { + // 1. 生成新的事件和服务列表 + List newFunctionList = new ArrayList<>(); // 生成属性上报事件 ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList); if (propertyPostEvent != null) { - saveOrUpdateEvent(productId, productKey, propertyPostEvent); + IotThinkModelFunctionDO eventFunction = buildEventFunctionDO(productId, productKey, propertyPostEvent); + newFunctionList.add(eventFunction); } // 生成属性设置服务 ThingModelService propertySetService = generatePropertySetService(propertyList); if (propertySetService != null) { - saveOrUpdateService(productId, productKey, propertySetService); + IotThinkModelFunctionDO setServiceFunction = buildServiceFunctionDO(productId, productKey, propertySetService); + newFunctionList.add(setServiceFunction); } // 生成属性获取服务 ThingModelService propertyGetService = generatePropertyGetService(propertyList); if (propertyGetService != null) { - saveOrUpdateService(productId, productKey, propertyGetService); + IotThinkModelFunctionDO getServiceFunction = buildServiceFunctionDO(productId, productKey, propertyGetService); + newFunctionList.add(getServiceFunction); } + + // 2. 获取数据库中的旧事件和服务列表 + List oldFunctionList = thinkModelFunctionMapper.selectListByProductIdAndTypes( + productId, + Arrays.asList(IotThingModelTypeEnum.EVENT.getType(), IotThingModelTypeEnum.SERVICE.getType()) + ); + + // 3. 使用 diffList 方法比较新旧列表 + List> diffResult = diffList( + oldFunctionList, + newFunctionList, + (oldFunc, newFunc) -> Objects.equals(oldFunc.getIdentifier(), newFunc.getIdentifier()) + && Objects.equals(oldFunc.getType(), newFunc.getType()) + ); + + List createList = diffResult.get(0); // 需要新增的 + List updateList = diffResult.get(1); // 需要更新的 + List deleteList = diffResult.get(2); // 需要删除的 + + // 4. 批量执行数据库操作 + if (CollUtil.isNotEmpty(createList)) { + thinkModelFunctionMapper.insertBatch(createList); + } + if (CollUtil.isNotEmpty(updateList)) { + for (IotThinkModelFunctionDO updateFunc : updateList) { + // 设置 ID,以便更新 + IotThinkModelFunctionDO oldFunc = findFunctionByIdentifierAndType( + oldFunctionList, updateFunc.getIdentifier(), updateFunc.getType() + ); + if (oldFunc != null) { + updateFunc.setId(oldFunc.getId()); + thinkModelFunctionMapper.updateById(updateFunc); + } + } + } + if (CollUtil.isNotEmpty(deleteList)) { + List idsToDelete = deleteList.stream().map(IotThinkModelFunctionDO::getId).collect(Collectors.toList()); + thinkModelFunctionMapper.deleteByIds(idsToDelete); + } + } + + /** + * 根据标识符和类型查找功能对象 + */ + private IotThinkModelFunctionDO findFunctionByIdentifierAndType(List functionList, + String identifier, Integer type) { + return functionList.stream() + .filter(func -> Objects.equals(func.getIdentifier(), identifier) && Objects.equals(func.getType(), type)) + .findFirst() + .orElse(null); + } + + /** + * 构建事件功能对象 + */ + private IotThinkModelFunctionDO buildEventFunctionDO(Long productId, String productKey, ThingModelEvent event) { + return new IotThinkModelFunctionDO() + .setProductId(productId) + .setProductKey(productKey) + .setIdentifier(event.getIdentifier()) + .setName(event.getName()) + .setDescription(event.getDescription()) + .setType(IotThingModelTypeEnum.EVENT.getType()) + .setEvent(event); + } + + /** + * 构建服务功能对象 + */ + private IotThinkModelFunctionDO buildServiceFunctionDO(Long productId, String productKey, ThingModelService service) { + return new IotThinkModelFunctionDO() + .setProductId(productId) + .setProductKey(productKey) + .setIdentifier(service.getIdentifier()) + .setName(service.getName()) + .setDescription(service.getDescription()) + .setType(IotThingModelTypeEnum.SERVICE.getType()) + .setService(service); } /** * 生成属性上报事件 */ private ThingModelEvent generatePropertyPostEvent(List propertyList) { - // TODO @haohao:用 CollUtil.isNotEmpty 会更容易哈 - if (propertyList == null || propertyList.isEmpty()) { + if (CollUtil.isEmpty(propertyList)) { return null; } - // TODO @haohao:可以考虑链式调用,简化整个方法的长度;然后,把相同类型的户型,尽量再放同一行,看起来轻松点;其它类似的,也可以试试看哈 - ThingModelEvent event = new ThingModelEvent(); - event.setIdentifier("post"); - event.setName("属性上报"); - event.setType("info"); - event.setDescription("属性上报事件"); - event.setMethod("thing.event.property.post"); + ThingModelEvent event = new ThingModelEvent() + .setIdentifier("post") + .setName("属性上报") + .setType("info") + .setDescription("属性上报事件") + .setMethod("thing.event.property.post"); // 将属性列表转换为事件的输出参数 List outputData = new ArrayList<>(); for (IotThinkModelFunctionDO functionDO : propertyList) { ThingModelProperty property = functionDO.getProperty(); - ThingModelArgument arg = new ThingModelArgument(); - arg.setIdentifier(property.getIdentifier()); - arg.setName(property.getName()); - arg.setDataType(property.getDataType()); - arg.setDescription(property.getDescription()); - arg.setDirection("output"); // 设置为输出参数 + ThingModelArgument arg = new ThingModelArgument() + .setIdentifier(property.getIdentifier()) + .setName(property.getName()) + .setDataType(property.getDataType()) + .setDescription(property.getDescription()) + .setDirection("output"); // 设置为输出参数 outputData.add(arg); } event.setOutputData(outputData); @@ -199,13 +296,13 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe List inputData = new ArrayList<>(); for (IotThinkModelFunctionDO functionDO : propertyList) { ThingModelProperty property = functionDO.getProperty(); - if ("w".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) { - ThingModelArgument arg = new ThingModelArgument(); - arg.setIdentifier(property.getIdentifier()); - arg.setName(property.getName()); - arg.setDataType(property.getDataType()); - arg.setDescription(property.getDescription()); - arg.setDirection("input"); // 设置为输入参数 + if (IotAccessModeEnum.WRITE.getMode().equals(property.getAccessMode()) || IotAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) { + ThingModelArgument arg = new ThingModelArgument() + .setIdentifier(property.getIdentifier()) + .setName(property.getName()) + .setDataType(property.getDataType()) + .setDescription(property.getDescription()) + .setDirection("input"); // 设置为输入参数 inputData.add(arg); } } @@ -214,16 +311,16 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe return null; } - ThingModelService service = new ThingModelService(); - service.setIdentifier("set"); - service.setName("属性设置"); - service.setCallType("async"); - service.setDescription("属性设置服务"); - service.setMethod("thing.service.property.set"); - service.setInputData(inputData); // 属性设置服务一般不需要输出参数 - service.setOutputData(new ArrayList<>()); - return service; + return new ThingModelService() + .setIdentifier("set") + .setName("属性设置") + .setCallType("async") + .setDescription("属性设置服务") + .setMethod("thing.service.property.set") + .setInputData(inputData) + // 属性设置服务一般不需要输出参数 + .setOutputData(new ArrayList<>()); } /** @@ -237,14 +334,13 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe List outputData = new ArrayList<>(); for (IotThinkModelFunctionDO functionDO : propertyList) { ThingModelProperty property = functionDO.getProperty(); - // TODO @haohao:r、rw 是不是枚举起来 - if ("r".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) { - ThingModelArgument arg = new ThingModelArgument(); - arg.setIdentifier(property.getIdentifier()); - arg.setName(property.getName()); - arg.setDataType(property.getDataType()); - arg.setDescription(property.getDescription()); - arg.setDirection("output"); // 设置为输出参数 + if (IotAccessModeEnum.READ.getMode().equals(property.getAccessMode()) || IotAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) { + ThingModelArgument arg = new ThingModelArgument() + .setIdentifier(property.getIdentifier()) + .setName(property.getName()) + .setDataType(property.getDataType()) + .setDescription(property.getDescription()) + .setDirection("output"); // 设置为输出参数 outputData.add(arg); } } @@ -253,19 +349,19 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe return null; } - ThingModelService service = new ThingModelService(); - service.setIdentifier("get"); - service.setName("属性获取"); - service.setCallType("async"); - service.setDescription("属性获取服务"); - service.setMethod("thing.service.property.get"); + ThingModelService service = new ThingModelService() + .setIdentifier("get") + .setName("属性获取") + .setCallType("async") + .setDescription("属性获取服务") + .setMethod("thing.service.property.get"); // 定义输入参数:属性标识符列表 - ThingModelArgument inputArg = new ThingModelArgument(); - inputArg.setIdentifier("properties"); - inputArg.setName("属性标识符列表"); - inputArg.setDescription("需要获取的属性标识符列表"); - inputArg.setDirection("input"); // 设置为输入参数 + ThingModelArgument inputArg = new ThingModelArgument() + .setIdentifier("properties") + .setName("属性标识符列表") + .setDescription("需要获取的属性标识符列表") + .setDirection("input"); // 设置为输入参数 // 创建数组类型,元素类型为文本类型(字符串) ThingModelArrayType arrayType = new ThingModelArrayType(); @@ -283,54 +379,4 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe return service; } - /** - * 保存或更新事件 - */ - private void saveOrUpdateEvent(Long productId, String productKey, ThingModelEvent event) { - // 检查是否已存在相同的事件 - IotThinkModelFunctionDO existingEvent = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, event.getIdentifier()); - IotThinkModelFunctionDO functionDO = new IotThinkModelFunctionDO(); - functionDO.setProductId(productId); - functionDO.setProductKey(productKey); - functionDO.setIdentifier(event.getIdentifier()); - functionDO.setName(event.getName()); - functionDO.setDescription(event.getDescription()); - functionDO.setType(IotThingModelTypeEnum.EVENT.getType()); - functionDO.setEvent(event); - - // TODO @haohao:会不会存在删除的情况哈?另外,项目里有 diffList 方法,看看是不是可以方便的,适合这个场景。具体怎么用,可以全局搜 - if (existingEvent != null) { - // 更新事件 - functionDO.setId(existingEvent.getId()); - thinkModelFunctionMapper.updateById(functionDO); - } else { - // 创建新的事件 - thinkModelFunctionMapper.insert(functionDO); - } - } - - /** - * 保存或更新事服务 - */ - private void saveOrUpdateService(Long productId, String productKey, ThingModelService service) { - // 检查是否已存在相同的服务 - IotThinkModelFunctionDO existingService = thinkModelFunctionMapper.selectByProductIdAndIdentifier(productId, service.getIdentifier()); - IotThinkModelFunctionDO functionDO = new IotThinkModelFunctionDO(); - functionDO.setProductId(productId); - functionDO.setProductKey(productKey); - functionDO.setIdentifier(service.getIdentifier()); - functionDO.setName(service.getName()); - functionDO.setDescription(service.getDescription()); - functionDO.setType(IotThingModelTypeEnum.SERVICE.getType()); - functionDO.setService(service); - - if (existingService != null) { - // 更新服务 - functionDO.setId(existingService.getId()); - thinkModelFunctionMapper.updateById(functionDO); - } else { - // 创建新的服务 - thinkModelFunctionMapper.insert(functionDO); - } - } } From e4ef1c81902b3bfae136ef70120be092005bc538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Mon, 16 Sep 2024 21:54:12 +0800 Subject: [PATCH 22/31] =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=9AIOT=20?= =?UTF-8?q?=E7=89=A9=E6=A8=A1=E5=9E=8B=E6=8E=A5=E5=8F=A3=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thinkmodelfunction/IotThinkModelFunctionMapper.java | 5 +++-- .../thinkmodelfunction/IotThinkModelFunctionServiceImpl.java | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java index 8c29c7eab..cd1327461 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java @@ -29,9 +29,10 @@ public interface IotThinkModelFunctionMapper extends BaseMapperX selectListByProductIdAndTypes(Long productId, List list) { + default List selectListByProductIdAndIdentifiersAndTypes(Long productId, List list, List list1){ return selectList(new LambdaQueryWrapperX() .eq(IotThinkModelFunctionDO::getProductId, productId) - .in(IotThinkModelFunctionDO::getType, list)); + .in(IotThinkModelFunctionDO::getIdentifier, list) + .in(IotThinkModelFunctionDO::getType, list1)); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index 9d5d1e650..7d4c9ef04 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -175,9 +175,10 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe newFunctionList.add(getServiceFunction); } - // 2. 获取数据库中的旧事件和服务列表 - List oldFunctionList = thinkModelFunctionMapper.selectListByProductIdAndTypes( + // 2. 获取数据库中的默认的旧事件和服务列表 + List oldFunctionList = thinkModelFunctionMapper.selectListByProductIdAndIdentifiersAndTypes( productId, + Arrays.asList("post", "set", "get"), Arrays.asList(IotThingModelTypeEnum.EVENT.getType(), IotThingModelTypeEnum.SERVICE.getType()) ); From 9658ed1a0d93dd492e3551038c105f540ccda2aa Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 17 Sep 2024 10:27:33 +0800 Subject: [PATCH 23/31] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IOT=EF=BC=9A=E7=89=A9=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E7=9A=84=20review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 1 + .../iot/enums/product/IotAccessModeEnum.java | 6 +--- .../IotThinkModelFunctionMapper.java | 9 ++++-- .../IotThinkModelFunctionServiceImpl.java | 30 +++++++++---------- 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 7677ef89d..790bbb40c 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -21,4 +21,5 @@ public interface ErrorCodeConstants { // ========== IoT 设备 1-050-003-000 ============ ErrorCode DEVICE_NOT_EXISTS = new ErrorCode(1_050_003_000, "设备不存在"); + } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java index 630240b86..64ece99ca 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java @@ -10,7 +10,7 @@ import lombok.Getter; */ @AllArgsConstructor @Getter -public enum IotAccessModeEnum { +public enum IotAccessModeEnum { READ("r"), WRITE("w"), @@ -18,8 +18,4 @@ public enum IotAccessModeEnum { private final String mode; - public String getMode() { - return mode; - } - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java index cd1327461..7227a0f26 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java @@ -29,10 +29,13 @@ public interface IotThinkModelFunctionMapper extends BaseMapperX selectListByProductIdAndIdentifiersAndTypes(Long productId, List list, List list1){ + default List selectListByProductIdAndIdentifiersAndTypes(Long productId, + List identifiers, + List types){ return selectList(new LambdaQueryWrapperX() .eq(IotThinkModelFunctionDO::getProductId, productId) - .in(IotThinkModelFunctionDO::getIdentifier, list) - .in(IotThinkModelFunctionDO::getType, list1)); + .in(IotThinkModelFunctionDO::getIdentifier, identifiers) + .in(IotThinkModelFunctionDO::getType, types)); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index 7d4c9ef04..0edb96db2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -55,6 +55,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe // 3. 如果创建的是属性,需要更新默认的事件和服务 if (Objects.equals(createReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { // 获取当前属性列表,并添加新插入的属性 + // TODO @haohao:是不是插入后,查询已经包含了 function List propertyList = thinkModelFunctionMapper .selectListByProductIdAndType(createReqVO.getProductId(), IotThingModelTypeEnum.PROPERTY.getType()); propertyList.add(function); @@ -85,6 +86,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe // 4. 如果更新的是属性,需要更新默认的事件和服务 if (Objects.equals(updateReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { // 获取当前属性列表,更新其中的属性 + // TODO @haohao:是不是更新后,查询出来的,已经是最新的 thinkModelFunction List propertyList = thinkModelFunctionMapper .selectListByProductIdAndType(updateReqVO.getProductId(), IotThingModelTypeEnum.PROPERTY.getType()); for (int i = 0; i < propertyList.size(); i++) { @@ -119,6 +121,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe // 3. 如果删除的是属性,需要更新默认的事件和服务 if (Objects.equals(functionDO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { // 获取当前属性列表,移除已删除的属性 + // TODO @haohao:是不是删除后,已经没有 id 对应的记录啦? List propertyList = thinkModelFunctionMapper .selectListByProductIdAndType(functionDO.getProductId(), IotThingModelTypeEnum.PROPERTY.getType()); propertyList.removeIf(property -> property.getId().equals(id)); @@ -153,21 +156,18 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe public void createDefaultEventsAndServices(Long productId, String productKey, List propertyList) { // 1. 生成新的事件和服务列表 List newFunctionList = new ArrayList<>(); - // 生成属性上报事件 ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList); if (propertyPostEvent != null) { IotThinkModelFunctionDO eventFunction = buildEventFunctionDO(productId, productKey, propertyPostEvent); newFunctionList.add(eventFunction); } - // 生成属性设置服务 ThingModelService propertySetService = generatePropertySetService(propertyList); if (propertySetService != null) { IotThinkModelFunctionDO setServiceFunction = buildServiceFunctionDO(productId, productKey, propertySetService); newFunctionList.add(setServiceFunction); } - // 生成属性获取服务 ThingModelService propertyGetService = generatePropertyGetService(propertyList); if (propertyGetService != null) { @@ -182,19 +182,15 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe Arrays.asList(IotThingModelTypeEnum.EVENT.getType(), IotThingModelTypeEnum.SERVICE.getType()) ); - // 3. 使用 diffList 方法比较新旧列表 - List> diffResult = diffList( - oldFunctionList, - newFunctionList, + // 3.1 使用 diffList 方法比较新旧列表 + List> diffResult = diffList(oldFunctionList, newFunctionList, + // TODO @haohao:是不是用 id 比较相同就 ok 哈。如果可以的化,下面的 update 可以更简单 (oldFunc, newFunc) -> Objects.equals(oldFunc.getIdentifier(), newFunc.getIdentifier()) - && Objects.equals(oldFunc.getType(), newFunc.getType()) - ); - + && Objects.equals(oldFunc.getType(), newFunc.getType())); List createList = diffResult.get(0); // 需要新增的 List updateList = diffResult.get(1); // 需要更新的 List deleteList = diffResult.get(2); // 需要删除的 - - // 4. 批量执行数据库操作 + // 3.2 批量执行数据库操作 if (CollUtil.isNotEmpty(createList)) { thinkModelFunctionMapper.insertBatch(createList); } @@ -202,8 +198,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe for (IotThinkModelFunctionDO updateFunc : updateList) { // 设置 ID,以便更新 IotThinkModelFunctionDO oldFunc = findFunctionByIdentifierAndType( - oldFunctionList, updateFunc.getIdentifier(), updateFunc.getType() - ); + oldFunctionList, updateFunc.getIdentifier(), updateFunc.getType()); if (oldFunc != null) { updateFunc.setId(oldFunc.getId()); thinkModelFunctionMapper.updateById(updateFunc); @@ -211,6 +206,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe } } if (CollUtil.isNotEmpty(deleteList)) { + // TODO @haohao:使用 convertSet 简化。 List idsToDelete = deleteList.stream().map(IotThinkModelFunctionDO::getId).collect(Collectors.toList()); thinkModelFunctionMapper.deleteByIds(idsToDelete); } @@ -221,6 +217,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe */ private IotThinkModelFunctionDO findFunctionByIdentifierAndType(List functionList, String identifier, Integer type) { + // TODO @haohao:这个可以使用 CollUtil.findOne 简化只有一行 return functionList.stream() .filter(func -> Objects.equals(func.getIdentifier(), identifier) && Objects.equals(func.getType(), type)) .findFirst() @@ -335,7 +332,9 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe List outputData = new ArrayList<>(); for (IotThinkModelFunctionDO functionDO : propertyList) { ThingModelProperty property = functionDO.getProperty(); - if (IotAccessModeEnum.READ.getMode().equals(property.getAccessMode()) || IotAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) { + // TODO @haohao:ObjectUtils.equalsAny(),进一步简化判断 + if (IotAccessModeEnum.READ.getMode().equals(property.getAccessMode()) + || IotAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) { ThingModelArgument arg = new ThingModelArgument() .setIdentifier(property.getIdentifier()) .setName(property.getName()) @@ -372,7 +371,6 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe textType.setType("text"); arraySpecs.setItem(textType); arrayType.setSpecs(arraySpecs); - inputArg.setDataType(arrayType); service.setInputData(Collections.singletonList(inputArg)); From d8d37d1bb94b5d141fdfc91a5a6dc8d293807d55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Wed, 18 Sep 2024 08:22:33 +0800 Subject: [PATCH 24/31] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91IOT=20=E7=89=A9=E6=A8=A1=E5=9E=8B=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IotThinkModelFunctionController.http | 103 ++++++++++++------ .../IotThinkModelFunctionServiceImpl.java | 56 ++++------ 2 files changed, 87 insertions(+), 72 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http index 6b9032fc6..56464dd80 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http @@ -5,39 +5,6 @@ tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} { - "productId": 1001, - "productKey": "smart-sensor-001", - "identifier": "Temperature", - "name": "温度", - "description": "当前温度值", - "type": 1, - "property": { - "identifier": "Temperature", - "name": "温度", - "accessMode": "r", - "required": true, - "dataType": { - "type": "float", - "specs": { - "min": -40.0, - "max": 125.0, - "step": 0.1, - "unit": "℃" - } - }, - "description": "当前温度值" - } -} - - -### 请求 /iot/think-model-function/update 接口 => 成功 -PUT {{baseUrl}}/iot/think-model-function/update -Content-Type: application/json -tenant-id: {{adminTenentId}} -Authorization: Bearer {{token}} - -{ - "id": 1, "productId": 1001, "productKey": "smart-sensor-001", "identifier": "Temperature", @@ -62,13 +29,79 @@ Authorization: Bearer {{token}} } } +### 请求 /iot/think-model-function/create 接口 => 成功 +POST {{baseUrl}}/iot/think-model-function/create +Content-Type: application/json +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} + +{ + "productId": 1001, + "productKey": "smart-sensor-001", + "identifier": "Humidity", + "name": "湿度", + "description": "当前湿度值", + "type": 1, + "property": { + "identifier": "Humidity", + "name": "湿度", + "accessMode": "r", + "required": true, + "dataType": { + "type": "float", + "specs": { + "min": 0.0, + "max": 100.0, + "step": 0.1, + "unit": "%" + } + }, + "description": "当前湿度值" + } +} + + + + +### 请求 /iot/think-model-function/update 接口 => 成功 +PUT {{baseUrl}}/iot/think-model-function/update +Content-Type: application/json +tenant-id: {{adminTenentId}} +Authorization: Bearer {{token}} + +{ + "id": 11, + "productId": 1001, + "productKey": "smart-sensor-001", + "identifier": "Temperature", + "name": "温度", + "description": "当前温度值", + "type": 1, + "property": { + "identifier": "Temperature", + "name": "温度", + "accessMode": "r", + "required": true, + "dataType": { + "type": "float", + "specs": { + "min": -111.0, + "max": 222.0, + "step": 0.1, + "unit": "℃" + } + }, + "description": "当前温度值" + } +} + ### 请求 /iot/think-model-function/delete 接口 => 成功 -DELETE {{baseUrl}}/iot/think-model-function/delete?id=1 +DELETE {{baseUrl}}/iot/think-model-function/delete?id=7 tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} ### 请求 /iot/think-model-function/get 接口 => 成功 -GET {{baseUrl}}/iot/think-model-function/get?id=4 +GET {{baseUrl}}/iot/think-model-function/get?id=10 tenant-id: {{adminTenentId}} Authorization: Bearer {{token}} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index 0edb96db2..9dc803e66 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.iot.service.thinkmodelfunction; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; @@ -22,7 +24,6 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; -import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList; @@ -54,12 +55,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe // 3. 如果创建的是属性,需要更新默认的事件和服务 if (Objects.equals(createReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { - // 获取当前属性列表,并添加新插入的属性 - // TODO @haohao:是不是插入后,查询已经包含了 function - List propertyList = thinkModelFunctionMapper - .selectListByProductIdAndType(createReqVO.getProductId(), IotThingModelTypeEnum.PROPERTY.getType()); - propertyList.add(function); - createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey(), propertyList); + createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); } return function.getId(); } @@ -76,6 +72,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) { // 1. 校验功能是否存在 validateThinkModelFunctionExists(updateReqVO.getId()); + // 2. 校验功能标识符是否唯一 validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier()); @@ -85,17 +82,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe // 4. 如果更新的是属性,需要更新默认的事件和服务 if (Objects.equals(updateReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { - // 获取当前属性列表,更新其中的属性 - // TODO @haohao:是不是更新后,查询出来的,已经是最新的 thinkModelFunction - List propertyList = thinkModelFunctionMapper - .selectListByProductIdAndType(updateReqVO.getProductId(), IotThingModelTypeEnum.PROPERTY.getType()); - for (int i = 0; i < propertyList.size(); i++) { - if (propertyList.get(i).getId().equals(thinkModelFunction.getId())) { - propertyList.set(i, thinkModelFunction); - break; - } - } - createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey(), propertyList); + createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey()); } } @@ -120,12 +107,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe // 3. 如果删除的是属性,需要更新默认的事件和服务 if (Objects.equals(functionDO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { - // 获取当前属性列表,移除已删除的属性 - // TODO @haohao:是不是删除后,已经没有 id 对应的记录啦? - List propertyList = thinkModelFunctionMapper - .selectListByProductIdAndType(functionDO.getProductId(), IotThingModelTypeEnum.PROPERTY.getType()); - propertyList.removeIf(property -> property.getId().equals(id)); - createDefaultEventsAndServices(functionDO.getProductId(), functionDO.getProductKey(), propertyList); + createDefaultEventsAndServices(functionDO.getProductId(), functionDO.getProductKey()); } } @@ -153,8 +135,12 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe /** * 创建默认的事件和服务 */ - public void createDefaultEventsAndServices(Long productId, String productKey, List propertyList) { - // 1. 生成新的事件和服务列表 + public void createDefaultEventsAndServices(Long productId, String productKey) { + // 1. 获取当前属性列表 + List propertyList = thinkModelFunctionMapper + .selectListByProductIdAndType(productId, IotThingModelTypeEnum.PROPERTY.getType()); + + // 2. 生成新的事件和服务列表 List newFunctionList = new ArrayList<>(); // 生成属性上报事件 ThingModelEvent propertyPostEvent = generatePropertyPostEvent(propertyList); @@ -175,7 +161,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe newFunctionList.add(getServiceFunction); } - // 2. 获取数据库中的默认的旧事件和服务列表 + // 3. 获取数据库中的默认的旧事件和服务列表 List oldFunctionList = thinkModelFunctionMapper.selectListByProductIdAndIdentifiersAndTypes( productId, Arrays.asList("post", "set", "get"), @@ -185,6 +171,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe // 3.1 使用 diffList 方法比较新旧列表 List> diffResult = diffList(oldFunctionList, newFunctionList, // TODO @haohao:是不是用 id 比较相同就 ok 哈。如果可以的化,下面的 update 可以更简单 + // 继续使用 identifier 和 type 进行比较:这样可以准确地匹配对应的功能对象。 (oldFunc, newFunc) -> Objects.equals(oldFunc.getIdentifier(), newFunc.getIdentifier()) && Objects.equals(oldFunc.getType(), newFunc.getType())); List createList = diffResult.get(0); // 需要新增的 @@ -206,8 +193,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe } } if (CollUtil.isNotEmpty(deleteList)) { - // TODO @haohao:使用 convertSet 简化。 - List idsToDelete = deleteList.stream().map(IotThinkModelFunctionDO::getId).collect(Collectors.toList()); + Set idsToDelete = CollectionUtils.convertSet(deleteList, IotThinkModelFunctionDO::getId); thinkModelFunctionMapper.deleteByIds(idsToDelete); } } @@ -217,11 +203,8 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe */ private IotThinkModelFunctionDO findFunctionByIdentifierAndType(List functionList, String identifier, Integer type) { - // TODO @haohao:这个可以使用 CollUtil.findOne 简化只有一行 - return functionList.stream() - .filter(func -> Objects.equals(func.getIdentifier(), identifier) && Objects.equals(func.getType(), type)) - .findFirst() - .orElse(null); + return CollUtil.findOne(functionList, func -> + Objects.equals(func.getIdentifier(), identifier) && Objects.equals(func.getType(), type)); } /** @@ -332,9 +315,8 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe List outputData = new ArrayList<>(); for (IotThinkModelFunctionDO functionDO : propertyList) { ThingModelProperty property = functionDO.getProperty(); - // TODO @haohao:ObjectUtils.equalsAny(),进一步简化判断 - if (IotAccessModeEnum.READ.getMode().equals(property.getAccessMode()) - || IotAccessModeEnum.READ_WRITE.getMode().equals(property.getAccessMode())) { + if (ObjectUtils.equalsAny(property.getAccessMode(), + IotAccessModeEnum.READ.getMode(), IotAccessModeEnum.READ_WRITE.getMode())) { ThingModelArgument arg = new ThingModelArgument() .setIdentifier(property.getIdentifier()) .setName(property.getName()) From bd18e730525671e1286a063d17604db483d41412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Fri, 20 Sep 2024 23:33:00 +0800 Subject: [PATCH 25/31] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E3=80=91IOT?= =?UTF-8?q?=20=E8=AE=BE=E5=A4=87=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 5 + .../iot/enums/device/IotDeviceStatusEnum.java | 43 +++ .../admin/device/IotDeviceController.java | 104 +++++++ .../admin/device/vo/IotDevicePageReqVO.java | 98 +++++++ .../admin/device/vo/IotDeviceRespVO.java | 119 ++++++++ .../admin/device/vo/IotDeviceSaveReqVO.java | 22 ++ .../module/iot/convert/package-info.java | 1 + .../dal/dataobject/device/IotDeviceDO.java | 134 +++++++++ .../iot/dal/mysql/device/IotDeviceMapper.java | 56 ++++ .../iot/service/device/DeviceServiceImpl.java | 264 ++++++++++++++++++ .../iot/service/device/IotDeviceService.java | 60 ++++ .../mapper/device/IotDeviceMapper.xml | 12 + .../service/device/DeviceServiceImplTest.java | 219 +++++++++++++++ 13 files changed, 1137 insertions(+) create mode 100644 yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStatusEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/package-info.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImplTest.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 790bbb40c..0a103b354 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -21,5 +21,10 @@ public interface ErrorCodeConstants { // ========== IoT 设备 1-050-003-000 ============ ErrorCode DEVICE_NOT_EXISTS = new ErrorCode(1_050_003_000, "设备不存在"); + ErrorCode DEVICE_NAME_EXISTS = new ErrorCode(1_050_003_001, "设备名称在同一产品下必须唯一"); + ErrorCode DEVICE_HAS_CHILDREN = new ErrorCode(1_050_003_002, "有子设备,不允许删除"); + ErrorCode DEVICE_NAME_CANNOT_BE_MODIFIED = new ErrorCode(1_050_003_003, "设备名称不能修改"); + ErrorCode DEVICE_PRODUCT_CANNOT_BE_MODIFIED = new ErrorCode(1_050_003_004, "产品不能修改"); + ErrorCode DEVICE_INVALID_DEVICE_STATUS = new ErrorCode(1_050_003_005, "无效的设备状态"); } diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStatusEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStatusEnum.java new file mode 100644 index 000000000..3d0f9fcc5 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStatusEnum.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.iot.enums.device; + +import lombok.Getter; + +/** + * IoT 设备状态枚举 + * 设备状态:0 - 未激活,1 - 在线,2 - 离线,3 - 已禁用 + */ +@Getter +public enum IotDeviceStatusEnum { + + INACTIVE(0, "未激活"), + ONLINE(1, "在线"), + OFFLINE(2, "离线"), + DISABLED(3, "已禁用"); + + /** + * 状态 + */ + private final Integer status; + /** + * 状态名 + */ + private final String name; + + IotDeviceStatusEnum(Integer status, String name) { + this.status = status; + this.name = name; + } + + public static IotDeviceStatusEnum fromStatus(Integer status) { + for (IotDeviceStatusEnum value : values()) { + if (value.getStatus().equals(status)) { + return value; + } + } + return null; + } + + public static boolean isValidStatus(Integer status) { + return fromStatus(status) != null; + } +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java new file mode 100644 index 000000000..c809a9059 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -0,0 +1,104 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device; + +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - IoT 设备") +@RestController +@RequestMapping("/iot/device") +@Validated +public class IotDeviceController { + + @Resource + private IotDeviceService deviceService; + + @PostMapping("/create") + @Operation(summary = "创建IoT 设备") + @PreAuthorize("@ss.hasPermission('iot:device:create')") + public CommonResult createDevice(@Valid @RequestBody IotDeviceSaveReqVO createReqVO) { + return success(deviceService.createDevice(createReqVO)); + } + + @PutMapping("/update-status") + @Operation(summary = "更新IoT 设备状态") + @Parameter(name = "id", description = "编号", required = true) + @Parameter(name = "status", description = "状态", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('iot:device:update')") + public CommonResult updateDeviceStatus(@RequestParam("id") Long id, + @RequestParam("status") Integer status) { + deviceService.updateDeviceStatus(id, status); + return success(true); + } + + @PutMapping("/update") + @Operation(summary = "更新IoT 设备") + @PreAuthorize("@ss.hasPermission('iot:device:update')") + public CommonResult updateDevice(@Valid @RequestBody IotDeviceSaveReqVO updateReqVO) { + deviceService.updateDevice(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除IoT 设备") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:device:delete')") + public CommonResult deleteDevice(@RequestParam("id") Long id) { + deviceService.deleteDevice(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得IoT 设备") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:device:query')") + public CommonResult getDevice(@RequestParam("id") Long id) { + IotDeviceDO device = deviceService.getDevice(id); + return success(BeanUtils.toBean(device, IotDeviceRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得IoT 设备分页") + @PreAuthorize("@ss.hasPermission('iot:device:query')") + public CommonResult> getDevicePage(@Valid IotDevicePageReqVO pageReqVO) { + PageResult pageResult = deviceService.getDevicePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotDeviceRespVO.class)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出IoT 设备 Excel") + @PreAuthorize("@ss.hasPermission('iot:device:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportDeviceExcel(@Valid IotDevicePageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = deviceService.getDevicePage(pageReqVO).getList(); + // 导出 Excel + ExcelUtils.write(response, "IoT 设备.xls", "数据", IotDeviceRespVO.class, + BeanUtils.toBean(list, IotDeviceRespVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java new file mode 100644 index 000000000..36a184871 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java @@ -0,0 +1,98 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo; + +import lombok.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import java.math.BigDecimal; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - IoT 设备分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class IotDevicePageReqVO extends PageParam { + + @Schema(description = "设备唯一标识符,全局唯一,用于识别设备") + private String deviceKey; + + @Schema(description = "设备名称,在产品内唯一,用于标识设备", example = "王五") + private String deviceName; + + @Schema(description = "产品 ID,关联 iot_product 表的 id", example = "26202") + private Long productId; + + @Schema(description = "产品 Key,关联 iot_product 表的 product_key") + private String productKey; + + @Schema(description = "设备类型:0 - 直连设备,1 - 网关子设备,2 - 网关设备", example = "1") + private Integer deviceType; + + @Schema(description = "设备备注名称,供用户自定义备注", example = "张三") + private String nickname; + + @Schema(description = "网关设备 ID,子设备需要关联的网关设备 ID", example = "16380") + private Long gatewayId; + + @Schema(description = "设备状态:0 - 未激活,1 - 在线,2 - 离线,3 - 已禁用", example = "1") + private Integer status; + + @Schema(description = "设备状态最后更新时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] statusLastUpdateTime; + + @Schema(description = "最后上线时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] lastOnlineTime; + + @Schema(description = "最后离线时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] lastOfflineTime; + + @Schema(description = "设备激活时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] activeTime; + + @Schema(description = "设备的 IP 地址") + private String ip; + + @Schema(description = "设备的固件版本") + private String firmwareVersion; + + @Schema(description = "设备密钥,用于设备认证,需安全存储") + private String deviceSecret; + + @Schema(description = "MQTT 客户端 ID", example = "24602") + private String mqttClientId; + + @Schema(description = "MQTT 用户名", example = "芋艿") + private String mqttUsername; + + @Schema(description = "MQTT 密码") + private String mqttPassword; + + @Schema(description = "认证类型(如一机一密、动态注册)", example = "2") + private String authType; + + @Schema(description = "设备位置的纬度,范围 -90.000000 ~ 90.000000") + private BigDecimal latitude; + + @Schema(description = "设备位置的经度,范围 -180.000000 ~ 180.000000") + private BigDecimal longitude; + + @Schema(description = "地区编码,符合国家地区编码标准,关联地区表", example = "16995") + private Integer areaId; + + @Schema(description = "设备详细地址") + private String address; + + @Schema(description = "设备序列号") + private String serialNumber; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java new file mode 100644 index 000000000..7cf592fc0 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java @@ -0,0 +1,119 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - IoT 设备 Response VO") +@Data +@ExcelIgnoreUnannotated +public class IotDeviceRespVO { + + @Schema(description = "设备 ID,主键,自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") + private Long id; + + @Schema(description = "设备唯一标识符", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("设备唯一标识符") + private String deviceKey; + + @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + @ExcelProperty("设备名称备") + private String deviceName; + + @Schema(description = "产品 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202") + @ExcelProperty("产品 ID") + private Long productId; + + @Schema(description = "产品 Key", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("产品 Key") + private String productKey; + + @Schema(description = "设备类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("设备类型") + private Integer deviceType; + + @Schema(description = "设备备注名称", example = "张三") + @ExcelProperty("设备备注名称") + private String nickname; + + @Schema(description = "网关设备 ID", example = "16380") + @ExcelProperty("网关设备 ID") + private Long gatewayId; + + @Schema(description = "设备状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("设备状态") + private Integer status; + + @Schema(description = "设备状态最后更新时间") + @ExcelProperty("设备状态最后更新时间") + private LocalDateTime statusLastUpdateTime; + + @Schema(description = "最后上线时间") + @ExcelProperty("最后上线时间") + private LocalDateTime lastOnlineTime; + + @Schema(description = "最后离线时间") + @ExcelProperty("最后离线时间") + private LocalDateTime lastOfflineTime; + + @Schema(description = "设备激活时间") + @ExcelProperty("设备激活时间") + private LocalDateTime activeTime; + + @Schema(description = "设备的 IP 地址") + @ExcelProperty("设备的 IP 地址") + private String ip; + + @Schema(description = "设备的固件版本") + @ExcelProperty("设备的固件版本") + private String firmwareVersion; + + @Schema(description = "设备密钥,用于设备认证,需安全存储") + @ExcelProperty("设备密钥") + private String deviceSecret; + + @Schema(description = "MQTT 客户端 ID", example = "24602") + @ExcelProperty("MQTT 客户端 ID") + private String mqttClientId; + + @Schema(description = "MQTT 用户名", example = "芋艿") + @ExcelProperty("MQTT 用户名") + private String mqttUsername; + + @Schema(description = "MQTT 密码") + @ExcelProperty("MQTT 密码") + private String mqttPassword; + + @Schema(description = "认证类型(如一机一密、动态注册)", example = "2") + @ExcelProperty("认证类型(如一机一密、动态注册)") + private String authType; + + @Schema(description = "设备位置的纬度,范围 -90.000000 ~ 90.000000") + @ExcelProperty("设备位置的纬度,范围 -90.000000 ~ 90.000000") + private BigDecimal latitude; + + @Schema(description = "设备位置的经度,范围 -180.000000 ~ 180.000000") + @ExcelProperty("设备位置的经度,范围 -180.000000 ~ 180.000000") + private BigDecimal longitude; + + @Schema(description = "地区编码,符合国家地区编码标准,关联地区表", example = "16995") + @ExcelProperty("地区编码,符合国家地区编码标准,关联地区表") + private Integer areaId; + + @Schema(description = "设备详细地址") + @ExcelProperty("设备详细地址") + private String address; + + @Schema(description = "设备序列号") + @ExcelProperty("设备序列号") + private String serialNumber; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java new file mode 100644 index 000000000..f52d8db92 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - IoT 设备新增/修改 Request VO") +@Data +public class IotDeviceSaveReqVO { + + @Schema(description = "设备 ID,主键,自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") + private Long id; + + @Schema(description = "设备名称,在产品内唯一,用于标识设备", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + private String deviceName; + + @Schema(description = "设备备注名称,供用户自定义备注", example = "张三") + private String nickname; + + @Schema(description = "产品 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202") + private Long productId; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/package-info.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/package-info.java new file mode 100644 index 000000000..c196c25c3 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.module.iot.convert; \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java new file mode 100644 index 000000000..138913f73 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java @@ -0,0 +1,134 @@ +package cn.iocoder.yudao.module.iot.dal.dataobject.device; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * IoT 设备 DO + * + * @author 芋道源码 + */ +@TableName("iot_device") +@KeySequence("iot_device_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class IotDeviceDO extends BaseDO { + + /** + * 设备 ID,主键,自增 + */ + @TableId + private Long id; + /** + * 设备唯一标识符,全局唯一,用于识别设备 + */ + private String deviceKey; + /** + * 设备名称,在产品内唯一,用于标识设备 + */ + private String deviceName; + /** + * 产品 ID,关联 iot_product 表的 id + * 关联 {@link IotProductDO#getId()} + */ + private Long productId; + /** + * 产品 Key,关联 iot_product 表的 product_key + * 关联 {@link IotProductDO#getProductKey()} + */ + private String productKey; + /** + * 设备类型:0 - 直连设备,1 - 网关子设备,2 - 网关设备 + * 关联 {@link IotProductDO#getDeviceType()} + */ + private Integer deviceType; + /** + * 设备备注名称,供用户自定义备注 + */ + private String nickname; + /** + * 网关设备 ID,子设备需要关联的网关设备 ID + */ + private Long gatewayId; + /** + * 设备状态:0 - 未激活,1 - 在线,2 - 离线,3 - 已禁用 + * 关联 {@link cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum} + */ + private Integer status; + /** + * 设备状态最后更新时间 + */ + private LocalDateTime statusLastUpdateTime; + /** + * 最后上线时间 + */ + private LocalDateTime lastOnlineTime; + /** + * 最后离线时间 + */ + private LocalDateTime lastOfflineTime; + /** + * 设备激活时间 + */ + private LocalDateTime activeTime; + /** + * 设备的 IP 地址 + */ + private String ip; + /** + * 设备的固件版本 + */ + private String firmwareVersion; + /** + * 设备密钥,用于设备认证,需安全存储 + */ + private String deviceSecret; + /** + * MQTT 客户端 ID + */ + private String mqttClientId; + /** + * MQTT 用户名 + */ + private String mqttUsername; + /** + * MQTT 密码 + */ + private String mqttPassword; + /** + * 认证类型(如一机一密、动态注册) + */ + private String authType; + /** + * 设备位置的纬度,范围 -90.000000 ~ 90.000000 + */ + private BigDecimal latitude; + /** + * 设备位置的经度,范围 -180.000000 ~ 180.000000 + */ + private BigDecimal longitude; + /** + * 地区编码,符合国家地区编码标准,关联地区表 + */ + private Integer areaId; + /** + * 设备详细地址 + */ + private String address; + /** + * 设备序列号 + */ + private String serialNumber; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java new file mode 100644 index 000000000..fc7d0a71f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.device; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * IoT 设备 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface IotDeviceMapper extends BaseMapperX { + + default PageResult selectPage(IotDevicePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(IotDeviceDO::getDeviceKey, reqVO.getDeviceKey()) + .likeIfPresent(IotDeviceDO::getDeviceName, reqVO.getDeviceName()) + .eqIfPresent(IotDeviceDO::getProductId, reqVO.getProductId()) + .eqIfPresent(IotDeviceDO::getProductKey, reqVO.getProductKey()) + .eqIfPresent(IotDeviceDO::getDeviceType, reqVO.getDeviceType()) + .likeIfPresent(IotDeviceDO::getNickname, reqVO.getNickname()) + .eqIfPresent(IotDeviceDO::getGatewayId, reqVO.getGatewayId()) + .eqIfPresent(IotDeviceDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(IotDeviceDO::getStatusLastUpdateTime, reqVO.getStatusLastUpdateTime()) + .betweenIfPresent(IotDeviceDO::getLastOnlineTime, reqVO.getLastOnlineTime()) + .betweenIfPresent(IotDeviceDO::getLastOfflineTime, reqVO.getLastOfflineTime()) + .betweenIfPresent(IotDeviceDO::getActiveTime, reqVO.getActiveTime()) + .eqIfPresent(IotDeviceDO::getIp, reqVO.getIp()) + .eqIfPresent(IotDeviceDO::getFirmwareVersion, reqVO.getFirmwareVersion()) + .eqIfPresent(IotDeviceDO::getDeviceSecret, reqVO.getDeviceSecret()) + .eqIfPresent(IotDeviceDO::getMqttClientId, reqVO.getMqttClientId()) + .likeIfPresent(IotDeviceDO::getMqttUsername, reqVO.getMqttUsername()) + .eqIfPresent(IotDeviceDO::getMqttPassword, reqVO.getMqttPassword()) + .eqIfPresent(IotDeviceDO::getAuthType, reqVO.getAuthType()) + .eqIfPresent(IotDeviceDO::getLatitude, reqVO.getLatitude()) + .eqIfPresent(IotDeviceDO::getLongitude, reqVO.getLongitude()) + .eqIfPresent(IotDeviceDO::getAreaId, reqVO.getAreaId()) + .eqIfPresent(IotDeviceDO::getAddress, reqVO.getAddress()) + .eqIfPresent(IotDeviceDO::getSerialNumber, reqVO.getSerialNumber()) + .betweenIfPresent(IotDeviceDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(IotDeviceDO::getId)); + } + + default IotDeviceDO selectByProductKeyAndDeviceName(String productKey, String deviceName) { + return selectOne(IotDeviceDO::getProductKey, productKey, + IotDeviceDO::getDeviceName, deviceName); + } + + default long selectCountByGatewayId(Long id) { + return selectCount(IotDeviceDO::getGatewayId, id); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java new file mode 100644 index 000000000..b1e7ffbdd --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java @@ -0,0 +1,264 @@ +package cn.iocoder.yudao.module.iot.service.device; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper; +import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import java.time.LocalDateTime; +import java.util.UUID; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; + +/** + * IoT 设备 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class DeviceServiceImpl implements IotDeviceService { + + @Resource + private IotDeviceMapper deviceMapper; + @Resource + private IotProductMapper productMapper; + + /** + * 创建 IoT 设备 + * + * @param createReqVO 创建请求 VO + * @return 设备 ID + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Long createDevice(IotDeviceSaveReqVO createReqVO) { + // 1. 转换 VO 为 DO + IotDeviceDO device = BeanUtils.toBean(createReqVO, IotDeviceDO.class); + + // 2. 根据产品 ID 查询产品信息 + IotProductDO product = productMapper.selectById(createReqVO.getProductId()); + if (product == null) { + throw exception(PRODUCT_NOT_EXISTS); + } + device.setProductKey(product.getProductKey()); + device.setDeviceType(product.getDeviceType()); + + // 3. DeviceName 可以为空,当为空时,自动生成产品下的唯一标识符作为 DeviceName + if (StrUtil.isBlank(device.getDeviceName())) { + device.setDeviceName(generateUniqueDeviceName(createReqVO.getProductId())); + } + + // 4. 校验设备名称在同一产品下是否唯一 + validateDeviceNameUnique(device.getProductKey(), device.getDeviceName()); + + // 5. 生成并设置必要的字段 + device.setDeviceKey(generateUniqueDeviceKey()); + device.setDeviceSecret(generateDeviceSecret()); + device.setMqttClientId(generateMqttClientId()); + device.setMqttUsername(generateMqttUsername(device.getDeviceName(), device.getProductKey())); + device.setMqttPassword(generateMqttPassword()); + + // 6. 设置设备状态为未激活 + device.setStatus(IotDeviceStatusEnum.INACTIVE.getStatus()); + device.setStatusLastUpdateTime(LocalDateTime.now()); + + // 7. 插入到数据库 + deviceMapper.insert(device); + + // 8. 返回生成的设备 ID + return device.getId(); + } + + /** + * 校验设备名称在同一产品下是否唯一 + * + * @param productKey 产品 Key + * @param deviceName 设备名称 + */ + private void validateDeviceNameUnique(String productKey, String deviceName) { + IotDeviceDO existingDevice = deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName); + if (existingDevice != null) { + throw exception(DEVICE_NAME_EXISTS); + } + } + + /** + * 生成唯一的 deviceKey + * + * @return 生成的 deviceKey + */ + private String generateUniqueDeviceKey() { + return UUID.randomUUID().toString(); + } + + /** + * 生成 deviceSecret + * + * @return 生成的 deviceSecret + */ + private String generateDeviceSecret() { + // 32 位随机字符串 + return UUID.randomUUID().toString().replace("-", ""); + } + + /** + * 生成 MQTT Client ID + * + * @return 生成的 MQTT Client ID + */ + private String generateMqttClientId() { + return UUID.randomUUID().toString(); + } + + /** + * 生成 MQTT Username + * + * @param deviceName 设备名称 + * @param productKey 产品 Key + * @return 生成的 MQTT Username + */ + private String generateMqttUsername(String deviceName, String productKey) { + return deviceName + "&" + productKey; + } + + /** + * 生成 MQTT Password + * + * @return 生成的 MQTT Password + */ + private String generateMqttPassword() { + // 在实际应用中,建议使用更安全的方法生成 MQTT Password,如加密或哈希 + return UUID.randomUUID().toString(); + } + + /** + * 生成唯一的 DeviceName + * + * @param productId 产品 ID + * @return 生成的唯一 DeviceName + */ + private String generateUniqueDeviceName(Long productId) { + // 实现逻辑以在产品下生成唯一的设备名称 + String deviceName; + String productKey = getProductKey(productId); + do { + // 20 位随机字符串 + deviceName = UUID.randomUUID().toString().replace("-", "").substring(0, 20); + } while (deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName) != null); + return deviceName; + } + + /** + * 获取产品 Key + * + * @param productId 产品 ID + * @return 产品 Key + */ + private String getProductKey(Long productId) { + IotProductDO product = productMapper.selectById(productId); + if (product == null) { + throw exception(PRODUCT_NOT_EXISTS); + } + return product.getProductKey(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateDevice(IotDeviceSaveReqVO updateReqVO) { + // 校验存在 + IotDeviceDO existingDevice = validateDeviceExists(updateReqVO.getId()); + + // 设备名称 和 产品 ID 不能修改 + if (updateReqVO.getDeviceName() != null && !updateReqVO.getDeviceName().equals(existingDevice.getDeviceName())) { + throw exception(DEVICE_NAME_CANNOT_BE_MODIFIED); + } + if (updateReqVO.getProductId() != null && !updateReqVO.getProductId().equals(existingDevice.getProductId())) { + throw exception(DEVICE_PRODUCT_CANNOT_BE_MODIFIED); + } + + // 更新 DO 对象 + IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class); + + // 更新到数据库 + deviceMapper.updateById(updateObj); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteDevice(Long id) { + // 校验存在 + IotDeviceDO iotDeviceDO = validateDeviceExists(id); + + // 如果是网关设备,检查是否有子设备 + if (iotDeviceDO.getGatewayId() != null) { + long childCount = deviceMapper.selectCountByGatewayId(id); + if (childCount > 0) { + throw exception(DEVICE_HAS_CHILDREN); + } + } + + // 删除设备 + deviceMapper.deleteById(id); + } + + /** + * 校验设备是否存在 + * + * @param id 设备 ID + * @return 设备对象 + */ + private IotDeviceDO validateDeviceExists(Long id) { + IotDeviceDO iotDeviceDO = deviceMapper.selectById(id); + if (iotDeviceDO == null) { + throw exception(DEVICE_NOT_EXISTS); + } + return iotDeviceDO; + } + + @Override + public IotDeviceDO getDevice(Long id) { + IotDeviceDO device = deviceMapper.selectById(id); + if (device == null) { + throw exception(DEVICE_NOT_EXISTS); + } + return device; + } + + @Override + public PageResult getDevicePage(IotDevicePageReqVO pageReqVO) { + return deviceMapper.selectPage(pageReqVO); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateDeviceStatus(Long id, Integer status) { + // 校验存在 + validateDeviceExists(id); + + // 校验状态是否合法 + if (!IotDeviceStatusEnum.isValidStatus(status)) { + throw exception(DEVICE_INVALID_DEVICE_STATUS); + } + + // 更新状态和更新时间 + IotDeviceDO updateObj = new IotDeviceDO() + .setId(id) + .setStatus(status) + .setStatusLastUpdateTime(LocalDateTime.now()); + deviceMapper.updateById(updateObj); + } +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java new file mode 100644 index 000000000..2802806de --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.iot.service.device; + +import jakarta.validation.*; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +/** + * IoT 设备 Service 接口 + * + * @author 芋道源码 + */ +public interface IotDeviceService { + + /** + * 创建IoT 设备 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDevice(@Valid IotDeviceSaveReqVO createReqVO); + + /** + * 更新IoT 设备 + * + * @param updateReqVO 更新信息 + */ + void updateDevice(@Valid IotDeviceSaveReqVO updateReqVO); + + /** + * 删除IoT 设备 + * + * @param id 编号 + */ + void deleteDevice(Long id); + + /** + * 获得IoT 设备 + * + * @param id 编号 + * @return IoT 设备 + */ + IotDeviceDO getDevice(Long id); + + /** + * 获得IoT 设备分页 + * + * @param pageReqVO 分页查询 + * @return IoT 设备分页 + */ + PageResult getDevicePage(IotDevicePageReqVO pageReqVO); + + /** + * 更新IoT 设备状态 + * + * @param id 编号 + * @param status 状态 + */ + void updateDeviceStatus(Long id, Integer status); +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml new file mode 100644 index 000000000..039dbd895 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImplTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImplTest.java new file mode 100644 index 000000000..a456589cb --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImplTest.java @@ -0,0 +1,219 @@ +package cn.iocoder.yudao.module.iot.service.device; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import jakarta.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.*; +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import org.springframework.context.annotation.Import; + +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static org.junit.jupiter.api.Assertions.*; + +/** + * {@link DeviceServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(DeviceServiceImpl.class) +public class DeviceServiceImplTest extends BaseDbUnitTest { + + @Resource + private DeviceServiceImpl deviceService; + + @Resource + private IotDeviceMapper deviceMapper; + + @Test + public void testCreateDevice_success() { + // 准备参数 + IotDeviceSaveReqVO createReqVO = randomPojo(IotDeviceSaveReqVO.class).setId(null); + + // 调用 + Long deviceId = deviceService.createDevice(createReqVO); + // 断言 + assertNotNull(deviceId); + // 校验记录的属性是否正确 + IotDeviceDO device = deviceMapper.selectById(deviceId); + assertPojoEquals(createReqVO, device, "id"); + } + + @Test + public void testUpdateDevice_success() { + // mock 数据 + IotDeviceDO dbDevice = randomPojo(IotDeviceDO.class); + deviceMapper.insert(dbDevice);// @Sql: 先插入出一条存在的数据 + // 准备参数 + IotDeviceSaveReqVO updateReqVO = randomPojo(IotDeviceSaveReqVO.class, o -> { + o.setId(dbDevice.getId()); // 设置更新的 ID + }); + + // 调用 + deviceService.updateDevice(updateReqVO); + // 校验是否更新正确 + IotDeviceDO device = deviceMapper.selectById(updateReqVO.getId()); // 获取最新的 + assertPojoEquals(updateReqVO, device); + } + + @Test + public void testUpdateDevice_notExists() { + // 准备参数 + IotDeviceSaveReqVO updateReqVO = randomPojo(IotDeviceSaveReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> deviceService.updateDevice(updateReqVO), DEVICE_NOT_EXISTS); + } + + @Test + public void testDeleteDevice_success() { + // mock 数据 + IotDeviceDO dbDevice = randomPojo(IotDeviceDO.class); + deviceMapper.insert(dbDevice);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbDevice.getId(); + + // 调用 + deviceService.deleteDevice(id); + // 校验数据不存在了 + assertNull(deviceMapper.selectById(id)); + } + + @Test + public void testDeleteDevice_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> deviceService.deleteDevice(id), DEVICE_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetDevicePage() { + // mock 数据 + IotDeviceDO dbDevice = randomPojo(IotDeviceDO.class, o -> { // 等会查询到 + o.setDeviceKey(null); + o.setDeviceName(null); + o.setProductId(null); + o.setProductKey(null); + o.setDeviceType(null); + o.setNickname(null); + o.setGatewayId(null); + o.setStatus(null); + o.setStatusLastUpdateTime(null); + o.setLastOnlineTime(null); + o.setLastOfflineTime(null); + o.setActiveTime(null); + o.setIp(null); + o.setFirmwareVersion(null); + o.setDeviceSecret(null); + o.setMqttClientId(null); + o.setMqttUsername(null); + o.setMqttPassword(null); + o.setAuthType(null); + o.setLatitude(null); + o.setLongitude(null); + o.setAreaId(null); + o.setAddress(null); + o.setSerialNumber(null); + o.setCreateTime(null); + }); + deviceMapper.insert(dbDevice); + // 测试 deviceKey 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setDeviceKey(null))); + // 测试 deviceName 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setDeviceName(null))); + // 测试 productId 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setProductId(null))); + // 测试 productKey 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setProductKey(null))); + // 测试 deviceType 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setDeviceType(null))); + // 测试 nickname 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setNickname(null))); + // 测试 gatewayId 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setGatewayId(null))); + // 测试 status 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setStatus(null))); + // 测试 statusLastUpdateTime 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setStatusLastUpdateTime(null))); + // 测试 lastOnlineTime 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setLastOnlineTime(null))); + // 测试 lastOfflineTime 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setLastOfflineTime(null))); + // 测试 activeTime 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setActiveTime(null))); + // 测试 ip 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setIp(null))); + // 测试 firmwareVersion 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setFirmwareVersion(null))); + // 测试 deviceSecret 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setDeviceSecret(null))); + // 测试 mqttClientId 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setMqttClientId(null))); + // 测试 mqttUsername 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setMqttUsername(null))); + // 测试 mqttPassword 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setMqttPassword(null))); + // 测试 authType 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setAuthType(null))); + // 测试 latitude 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setLatitude(null))); + // 测试 longitude 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setLongitude(null))); + // 测试 areaId 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setAreaId(null))); + // 测试 address 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setAddress(null))); + // 测试 serialNumber 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setSerialNumber(null))); + // 测试 createTime 不匹配 + deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setCreateTime(null))); + // 准备参数 + IotDevicePageReqVO reqVO = new IotDevicePageReqVO(); + reqVO.setDeviceKey(null); + reqVO.setDeviceName(null); + reqVO.setProductId(null); + reqVO.setProductKey(null); + reqVO.setDeviceType(null); + reqVO.setNickname(null); + reqVO.setGatewayId(null); + reqVO.setStatus(null); + reqVO.setStatusLastUpdateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setLastOnlineTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setLastOfflineTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setActiveTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setIp(null); + reqVO.setFirmwareVersion(null); + reqVO.setDeviceSecret(null); + reqVO.setMqttClientId(null); + reqVO.setMqttUsername(null); + reqVO.setMqttPassword(null); + reqVO.setAuthType(null); + reqVO.setLatitude(null); + reqVO.setLongitude(null); + reqVO.setAreaId(null); + reqVO.setAddress(null); + reqVO.setSerialNumber(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + + // 调用 + PageResult pageResult = deviceService.getDevicePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbDevice, pageResult.getList().get(0)); + } + +} \ No newline at end of file From 6b9cca0b79612fc3ca26f04b73b23d9f973dd873 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 21 Sep 2024 10:09:30 +0800 Subject: [PATCH 26/31] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IOT=EF=BC=9A=E8=AE=BE=E5=A4=87=E7=9A=84=20rev?= =?UTF-8?q?iew?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/enums/device/IotDeviceStatusEnum.java | 16 +- .../admin/device/IotDeviceController.java | 14 +- .../admin/device/vo/IotDevicePageReqVO.java | 31 ++- .../admin/device/vo/IotDeviceRespVO.java | 21 +- .../admin/device/vo/IotDeviceSaveReqVO.java | 8 +- .../dal/dataobject/device/IotDeviceDO.java | 64 +++-- .../iot/dal/mysql/device/IotDeviceMapper.java | 1 + .../iot/service/device/DeviceServiceImpl.java | 101 ++++---- .../iot/service/device/IotDeviceService.java | 13 +- .../IotThinkModelFunctionServiceImpl.java | 2 +- .../mapper/device/IotDeviceMapper.xml | 12 - .../IotThinkModelFunctionMapper.xml | 12 - .../service/device/DeviceServiceImplTest.java | 219 ------------------ .../IotThinkModelFunctionServiceImplTest.java | 71 ------ 14 files changed, 145 insertions(+), 440 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/thinkmodelfunction/IotThinkModelFunctionMapper.xml delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImplTest.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImplTest.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStatusEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStatusEnum.java index 3d0f9fcc5..5fd983dc0 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStatusEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStatusEnum.java @@ -1,19 +1,25 @@ package cn.iocoder.yudao.module.iot.enums.device; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; import lombok.Getter; +import java.util.Arrays; + /** * IoT 设备状态枚举 - * 设备状态:0 - 未激活,1 - 在线,2 - 离线,3 - 已禁用 + * + * @author haohao */ @Getter -public enum IotDeviceStatusEnum { +public enum IotDeviceStatusEnum implements IntArrayValuable { INACTIVE(0, "未激活"), ONLINE(1, "在线"), OFFLINE(2, "离线"), DISABLED(3, "已禁用"); + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotDeviceStatusEnum::getStatus).toArray(); + /** * 状态 */ @@ -40,4 +46,10 @@ public enum IotDeviceStatusEnum { public static boolean isValidStatus(Integer status) { return fromStatus(status) != null; } + + @Override + public int[] array() { + return ARRAYS; + } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java index c809a9059..e455c78cf 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -37,14 +37,14 @@ public class IotDeviceController { private IotDeviceService deviceService; @PostMapping("/create") - @Operation(summary = "创建IoT 设备") + @Operation(summary = "创建设备") @PreAuthorize("@ss.hasPermission('iot:device:create')") public CommonResult createDevice(@Valid @RequestBody IotDeviceSaveReqVO createReqVO) { return success(deviceService.createDevice(createReqVO)); } @PutMapping("/update-status") - @Operation(summary = "更新IoT 设备状态") + @Operation(summary = "更新设备状态") @Parameter(name = "id", description = "编号", required = true) @Parameter(name = "status", description = "状态", required = true, example = "1") @PreAuthorize("@ss.hasPermission('iot:device:update')") @@ -55,7 +55,7 @@ public class IotDeviceController { } @PutMapping("/update") - @Operation(summary = "更新IoT 设备") + @Operation(summary = "更新设备") @PreAuthorize("@ss.hasPermission('iot:device:update')") public CommonResult updateDevice(@Valid @RequestBody IotDeviceSaveReqVO updateReqVO) { deviceService.updateDevice(updateReqVO); @@ -63,7 +63,7 @@ public class IotDeviceController { } @DeleteMapping("/delete") - @Operation(summary = "删除IoT 设备") + @Operation(summary = "删除设备") @Parameter(name = "id", description = "编号", required = true) @PreAuthorize("@ss.hasPermission('iot:device:delete')") public CommonResult deleteDevice(@RequestParam("id") Long id) { @@ -72,7 +72,7 @@ public class IotDeviceController { } @GetMapping("/get") - @Operation(summary = "获得IoT 设备") + @Operation(summary = "获得设备") @Parameter(name = "id", description = "编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('iot:device:query')") public CommonResult getDevice(@RequestParam("id") Long id) { @@ -81,7 +81,7 @@ public class IotDeviceController { } @GetMapping("/page") - @Operation(summary = "获得IoT 设备分页") + @Operation(summary = "获得设备分页") @PreAuthorize("@ss.hasPermission('iot:device:query')") public CommonResult> getDevicePage(@Valid IotDevicePageReqVO pageReqVO) { PageResult pageResult = deviceService.getDevicePage(pageReqVO); @@ -89,7 +89,7 @@ public class IotDeviceController { } @GetMapping("/export-excel") - @Operation(summary = "导出IoT 设备 Excel") + @Operation(summary = "导出设备 Excel") @PreAuthorize("@ss.hasPermission('iot:device:export')") @ApiAccessLog(operateType = EXPORT) public void exportDeviceExcel(@Valid IotDevicePageReqVO pageReqVO, diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java index 36a184871..c2cd35685 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java @@ -1,10 +1,15 @@ package cn.iocoder.yudao.module.iot.controller.admin.device.vo; -import lombok.*; -import io.swagger.v3.oas.annotations.media.Schema; import cn.iocoder.yudao.framework.common.pojo.PageParam; -import java.math.BigDecimal; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; import org.springframework.format.annotation.DateTimeFormat; + +import java.math.BigDecimal; import java.time.LocalDateTime; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; @@ -15,28 +20,32 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @ToString(callSuper = true) public class IotDevicePageReqVO extends PageParam { - @Schema(description = "设备唯一标识符,全局唯一,用于识别设备") + // TODO @芋艿:需要去掉一些多余的字段; + + @Schema(description = "设备唯一标识符", example = "24602") private String deviceKey; - @Schema(description = "设备名称,在产品内唯一,用于标识设备", example = "王五") + @Schema(description = "设备名称", example = "王五") private String deviceName; - @Schema(description = "产品 ID,关联 iot_product 表的 id", example = "26202") + @Schema(description = "产品编号", example = "26202") private Long productId; - @Schema(description = "产品 Key,关联 iot_product 表的 product_key") + @Schema(description = "产品标识") private String productKey; - @Schema(description = "设备类型:0 - 直连设备,1 - 网关子设备,2 - 网关设备", example = "1") + @Schema(description = "设备类型", example = "1") + // TODO @haohao:需要有个设备类型的枚举 private Integer deviceType; - @Schema(description = "设备备注名称,供用户自定义备注", example = "张三") + @Schema(description = "备注名称", example = "张三") private String nickname; - @Schema(description = "网关设备 ID,子设备需要关联的网关设备 ID", example = "16380") + @Schema(description = "网关设备 ID", example = "16380") private Long gatewayId; - @Schema(description = "设备状态:0 - 未激活,1 - 在线,2 - 离线,3 - 已禁用", example = "1") + @Schema(description = "设备状态", example = "1") + @InEnum(IotDeviceStatusEnum.class) private Integer status; @Schema(description = "设备状态最后更新时间") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java index 7cf592fc0..0423b17a9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java @@ -13,7 +13,7 @@ import java.time.LocalDateTime; @ExcelIgnoreUnannotated public class IotDeviceRespVO { - @Schema(description = "设备 ID,主键,自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") private Long id; @Schema(description = "设备唯一标识符", requiredMode = Schema.RequiredMode.REQUIRED) @@ -24,11 +24,11 @@ public class IotDeviceRespVO { @ExcelProperty("设备名称备") private String deviceName; - @Schema(description = "产品 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202") + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202") @ExcelProperty("产品 ID") private Long productId; - @Schema(description = "产品 Key", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("产品 Key") private String productKey; @@ -72,7 +72,7 @@ public class IotDeviceRespVO { @ExcelProperty("设备的固件版本") private String firmwareVersion; - @Schema(description = "设备密钥,用于设备认证,需安全存储") + @Schema(description = "设备密钥,用于设备认证") @ExcelProperty("设备密钥") private String deviceSecret; @@ -92,16 +92,17 @@ public class IotDeviceRespVO { @ExcelProperty("认证类型(如一机一密、动态注册)") private String authType; - @Schema(description = "设备位置的纬度,范围 -90.000000 ~ 90.000000") - @ExcelProperty("设备位置的纬度,范围 -90.000000 ~ 90.000000") + // TODO @haohao:经纬度:可能 double 就够啦 + @Schema(description = "设备位置的纬度,范围") + @ExcelProperty("设备位置的纬度") private BigDecimal latitude; - @Schema(description = "设备位置的经度,范围 -180.000000 ~ 180.000000") - @ExcelProperty("设备位置的经度,范围 -180.000000 ~ 180.000000") + @Schema(description = "设备位置的经度") + @ExcelProperty("设备位置的经度") private BigDecimal longitude; - @Schema(description = "地区编码,符合国家地区编码标准,关联地区表", example = "16995") - @ExcelProperty("地区编码,符合国家地区编码标准,关联地区表") + @Schema(description = "地区编码", example = "16995") + @ExcelProperty("地区编码") private Integer areaId; @Schema(description = "设备详细地址") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java index f52d8db92..620e5310f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java @@ -7,16 +7,16 @@ import lombok.Data; @Data public class IotDeviceSaveReqVO { - @Schema(description = "设备 ID,主键,自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "177") + @Schema(description = "设备编号", example = "177") private Long id; - @Schema(description = "设备名称,在产品内唯一,用于标识设备", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") + @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") private String deviceName; - @Schema(description = "设备备注名称,供用户自定义备注", example = "张三") + @Schema(description = "备注名称", example = "张三") private String nickname; - @Schema(description = "产品 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202") + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202") private Long productId; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java index 138913f73..d61e640ae 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.dal.dataobject.device; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -13,7 +14,7 @@ import java.time.LocalDateTime; /** * IoT 设备 DO * - * @author 芋道源码 + * @author haohao */ @TableName("iot_device") @KeySequence("iot_device_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @@ -39,33 +40,48 @@ public class IotDeviceDO extends BaseDO { */ private String deviceName; /** - * 产品 ID,关联 iot_product 表的 id + * 设备备注名称 + */ + private String nickname; + /** + * 设备序列号 + */ + private String serialNumber; + + /** + * 产品编号 + * * 关联 {@link IotProductDO#getId()} */ private Long productId; /** - * 产品 Key,关联 iot_product 表的 product_key - * 关联 {@link IotProductDO#getProductKey()} + * 产品标识 + * + * 冗余 {@link IotProductDO#getProductKey()} */ private String productKey; /** - * 设备类型:0 - 直连设备,1 - 网关子设备,2 - 网关设备 - * 关联 {@link IotProductDO#getDeviceType()} + * 设备类型 + * + * 冗余 {@link IotProductDO#getDeviceType()} */ private Integer deviceType; + /** - * 设备备注名称,供用户自定义备注 - */ - private String nickname; - /** - * 网关设备 ID,子设备需要关联的网关设备 ID - */ - private Long gatewayId; - /** - * 设备状态:0 - 未激活,1 - 在线,2 - 离线,3 - 已禁用 - * 关联 {@link cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum} + * 设备状态 + * + * 枚举 {@link IotDeviceStatusEnum} */ private Integer status; + /** + * 网关设备编号 + * + * 子设备需要关联的网关设备 ID + * + * 关联 {@link IotDeviceDO#getId()} + */ + private Long gatewayId; + /** * 设备状态最后更新时间 */ @@ -82,6 +98,7 @@ public class IotDeviceDO extends BaseDO { * 设备激活时间 */ private LocalDateTime activeTime; + /** * 设备的 IP 地址 */ @@ -90,6 +107,7 @@ public class IotDeviceDO extends BaseDO { * 设备的固件版本 */ private String firmwareVersion; + /** * 设备密钥,用于设备认证,需安全存储 */ @@ -109,26 +127,26 @@ public class IotDeviceDO extends BaseDO { /** * 认证类型(如一机一密、动态注册) */ + // TODO @haohao:是不是要枚举哈 private String authType; + /** - * 设备位置的纬度,范围 -90.000000 ~ 90.000000 + * 设备位置的纬度 */ private BigDecimal latitude; /** - * 设备位置的经度,范围 -180.000000 ~ 180.000000 + * 设备位置的经度 */ private BigDecimal longitude; /** - * 地区编码,符合国家地区编码标准,关联地区表 + * 地区编码 + * + * 关联 Area 的 id */ private Integer areaId; /** * 设备详细地址 */ private String address; - /** - * 设备序列号 - */ - private String serialNumber; } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index fc7d0a71f..0224c6da3 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -53,4 +53,5 @@ public interface IotDeviceMapper extends BaseMapperX { default long selectCountByGatewayId(Long id) { return selectCount(IotDeviceDO::getGatewayId, id); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java index b1e7ffbdd..0b4db169f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.iot.service.device; +import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -34,6 +35,7 @@ public class DeviceServiceImpl implements IotDeviceService { @Resource private IotDeviceMapper deviceMapper; + // TODO @haohao:不直接调用 productmapper,通过 productservice;每一个模型,不直接使用对方的 @Resource private IotProductMapper productMapper; @@ -46,40 +48,33 @@ public class DeviceServiceImpl implements IotDeviceService { @Override @Transactional(rollbackFor = Exception.class) public Long createDevice(IotDeviceSaveReqVO createReqVO) { - // 1. 转换 VO 为 DO - IotDeviceDO device = BeanUtils.toBean(createReqVO, IotDeviceDO.class); - - // 2. 根据产品 ID 查询产品信息 + // 1.1 校验产品是否存在 IotProductDO product = productMapper.selectById(createReqVO.getProductId()); if (product == null) { throw exception(PRODUCT_NOT_EXISTS); } - device.setProductKey(product.getProductKey()); - device.setDeviceType(product.getDeviceType()); - - // 3. DeviceName 可以为空,当为空时,自动生成产品下的唯一标识符作为 DeviceName - if (StrUtil.isBlank(device.getDeviceName())) { - device.setDeviceName(generateUniqueDeviceName(createReqVO.getProductId())); + // 1.2 校验设备名称在同一产品下是否唯一 + if (StrUtil.isBlank(createReqVO.getDeviceName())) { + createReqVO.setDeviceName(generateUniqueDeviceName(product.getProductKey())); + } else { + validateDeviceNameUnique(product.getProductKey(), createReqVO.getDeviceName()); } - // 4. 校验设备名称在同一产品下是否唯一 - validateDeviceNameUnique(device.getProductKey(), device.getDeviceName()); - - // 5. 生成并设置必要的字段 + // 2.1 转换 VO 为 DO + IotDeviceDO device = BeanUtils.toBean(createReqVO, IotDeviceDO.class) + .setProductKey(product.getProductKey()) + .setDeviceType(product.getDeviceType()); + // 2.2 生成并设置必要的字段 device.setDeviceKey(generateUniqueDeviceKey()); device.setDeviceSecret(generateDeviceSecret()); device.setMqttClientId(generateMqttClientId()); device.setMqttUsername(generateMqttUsername(device.getDeviceName(), device.getProductKey())); device.setMqttPassword(generateMqttPassword()); - - // 6. 设置设备状态为未激活 + // 2.3 设置设备状态为未激活 device.setStatus(IotDeviceStatusEnum.INACTIVE.getStatus()); device.setStatusLastUpdateTime(LocalDateTime.now()); - - // 7. 插入到数据库 + // 2.4 插入到数据库 deviceMapper.insert(device); - - // 8. 返回生成的设备 ID return device.getId(); } @@ -111,7 +106,7 @@ public class DeviceServiceImpl implements IotDeviceService { * @return 生成的 deviceSecret */ private String generateDeviceSecret() { - // 32 位随机字符串 + // TODO @haohao:return IdUtil.fastSimpleUUID() return UUID.randomUUID().toString().replace("-", ""); } @@ -141,39 +136,25 @@ public class DeviceServiceImpl implements IotDeviceService { * @return 生成的 MQTT Password */ private String generateMqttPassword() { - // 在实际应用中,建议使用更安全的方法生成 MQTT Password,如加密或哈希 + // TODO @haohao:【后续优化】在实际应用中,建议使用更安全的方法生成 MQTT Password,如加密或哈希 return UUID.randomUUID().toString(); } /** * 生成唯一的 DeviceName * - * @param productId 产品 ID + * @param productKey 产品标识 * @return 生成的唯一 DeviceName */ - private String generateUniqueDeviceName(Long productId) { - // 实现逻辑以在产品下生成唯一的设备名称 - String deviceName; - String productKey = getProductKey(productId); - do { - // 20 位随机字符串 - deviceName = UUID.randomUUID().toString().replace("-", "").substring(0, 20); - } while (deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName) != null); - return deviceName; - } - - /** - * 获取产品 Key - * - * @param productId 产品 ID - * @return 产品 Key - */ - private String getProductKey(Long productId) { - IotProductDO product = productMapper.selectById(productId); - if (product == null) { - throw exception(PRODUCT_NOT_EXISTS); + private String generateUniqueDeviceName(String productKey) { + // TODO @haohao:业务逻辑里,尽量避免 while true。万一 bug = =;虽然这个不会哈。我先改了下 + for (int i = 0; i < Short.MAX_VALUE; i++) { + String deviceName = IdUtil.fastSimpleUUID().substring(0, 20); + if (deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName) != null) { + return deviceName; + } } - return product.getProductKey(); + throw new IllegalArgumentException("生成 DeviceName 失败"); } @Override @@ -183,6 +164,7 @@ public class DeviceServiceImpl implements IotDeviceService { IotDeviceDO existingDevice = validateDeviceExists(updateReqVO.getId()); // 设备名称 和 产品 ID 不能修改 + // TODO @haohao:这种,直接设置为 null 就不会更新了。忽略前端的传参 if (updateReqVO.getDeviceName() != null && !updateReqVO.getDeviceName().equals(existingDevice.getDeviceName())) { throw exception(DEVICE_NAME_CANNOT_BE_MODIFIED); } @@ -200,18 +182,14 @@ public class DeviceServiceImpl implements IotDeviceService { @Override @Transactional(rollbackFor = Exception.class) public void deleteDevice(Long id) { - // 校验存在 - IotDeviceDO iotDeviceDO = validateDeviceExists(id); - - // 如果是网关设备,检查是否有子设备 - if (iotDeviceDO.getGatewayId() != null) { - long childCount = deviceMapper.selectCountByGatewayId(id); - if (childCount > 0) { - throw exception(DEVICE_HAS_CHILDREN); - } + // 1.1 校验存在 + IotDeviceDO device = validateDeviceExists(id); + // 1.2 如果是网关设备,检查是否有子设备 + if (device.getGatewayId() != null && deviceMapper.selectCountByGatewayId(id) > 0) { + throw exception(DEVICE_HAS_CHILDREN); } - // 删除设备 + // 2. 删除设备 deviceMapper.deleteById(id); } @@ -222,11 +200,11 @@ public class DeviceServiceImpl implements IotDeviceService { * @return 设备对象 */ private IotDeviceDO validateDeviceExists(Long id) { - IotDeviceDO iotDeviceDO = deviceMapper.selectById(id); - if (iotDeviceDO == null) { + IotDeviceDO device = deviceMapper.selectById(id); + if (device == null) { throw exception(DEVICE_NOT_EXISTS); } - return iotDeviceDO; + return device; } @Override @@ -244,21 +222,20 @@ public class DeviceServiceImpl implements IotDeviceService { } @Override - @Transactional(rollbackFor = Exception.class) public void updateDeviceStatus(Long id, Integer status) { // 校验存在 validateDeviceExists(id); + // TODO @haohao:这个可以直接用 swagger 注解哈 // 校验状态是否合法 if (!IotDeviceStatusEnum.isValidStatus(status)) { throw exception(DEVICE_INVALID_DEVICE_STATUS); } // 更新状态和更新时间 - IotDeviceDO updateObj = new IotDeviceDO() - .setId(id) - .setStatus(status) + IotDeviceDO updateObj = new IotDeviceDO().setId(id).setStatus(status) .setStatusLastUpdateTime(LocalDateTime.now()); deviceMapper.updateById(updateObj); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index 2802806de..9b6de37bf 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -13,7 +13,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; public interface IotDeviceService { /** - * 创建IoT 设备 + * 创建设备 * * @param createReqVO 创建信息 * @return 编号 @@ -21,21 +21,21 @@ public interface IotDeviceService { Long createDevice(@Valid IotDeviceSaveReqVO createReqVO); /** - * 更新IoT 设备 + * 更新设备 * * @param updateReqVO 更新信息 */ void updateDevice(@Valid IotDeviceSaveReqVO updateReqVO); /** - * 删除IoT 设备 + * 删除设备 * * @param id 编号 */ void deleteDevice(Long id); /** - * 获得IoT 设备 + * 获得设备 * * @param id 编号 * @return IoT 设备 @@ -43,7 +43,7 @@ public interface IotDeviceService { IotDeviceDO getDevice(Long id); /** - * 获得IoT 设备分页 + * 获得设备分页 * * @param pageReqVO 分页查询 * @return IoT 设备分页 @@ -51,10 +51,11 @@ public interface IotDeviceService { PageResult getDevicePage(IotDevicePageReqVO pageReqVO); /** - * 更新IoT 设备状态 + * 更新设备状态 * * @param id 编号 * @param status 状态 */ void updateDeviceStatus(Long id, Integer status); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index 9dc803e66..64ff3d319 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -170,7 +170,6 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe // 3.1 使用 diffList 方法比较新旧列表 List> diffResult = diffList(oldFunctionList, newFunctionList, - // TODO @haohao:是不是用 id 比较相同就 ok 哈。如果可以的化,下面的 update 可以更简单 // 继续使用 identifier 和 type 进行比较:这样可以准确地匹配对应的功能对象。 (oldFunc, newFunc) -> Objects.equals(oldFunc.getIdentifier(), newFunc.getIdentifier()) && Objects.equals(oldFunc.getType(), newFunc.getType())); @@ -191,6 +190,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe thinkModelFunctionMapper.updateById(updateFunc); } } + // TODO @haohao:seckillProductMapper.updateBatch(diffList.get(1)); 可以直接类似这么操作哇? } if (CollUtil.isNotEmpty(deleteList)) { Set idsToDelete = CollectionUtils.convertSet(deleteList, IotThinkModelFunctionDO::getId); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml deleted file mode 100644 index 039dbd895..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMapper.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/thinkmodelfunction/IotThinkModelFunctionMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/thinkmodelfunction/IotThinkModelFunctionMapper.xml deleted file mode 100644 index 525a32bd6..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/thinkmodelfunction/IotThinkModelFunctionMapper.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImplTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImplTest.java deleted file mode 100644 index a456589cb..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImplTest.java +++ /dev/null @@ -1,219 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.device; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import jakarta.annotation.Resource; - -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; - -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.*; -import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; -import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper; -import cn.iocoder.yudao.framework.common.pojo.PageResult; - -import org.springframework.context.annotation.Import; - -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; -import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; -import static org.junit.jupiter.api.Assertions.*; - -/** - * {@link DeviceServiceImpl} 的单元测试类 - * - * @author 芋道源码 - */ -@Import(DeviceServiceImpl.class) -public class DeviceServiceImplTest extends BaseDbUnitTest { - - @Resource - private DeviceServiceImpl deviceService; - - @Resource - private IotDeviceMapper deviceMapper; - - @Test - public void testCreateDevice_success() { - // 准备参数 - IotDeviceSaveReqVO createReqVO = randomPojo(IotDeviceSaveReqVO.class).setId(null); - - // 调用 - Long deviceId = deviceService.createDevice(createReqVO); - // 断言 - assertNotNull(deviceId); - // 校验记录的属性是否正确 - IotDeviceDO device = deviceMapper.selectById(deviceId); - assertPojoEquals(createReqVO, device, "id"); - } - - @Test - public void testUpdateDevice_success() { - // mock 数据 - IotDeviceDO dbDevice = randomPojo(IotDeviceDO.class); - deviceMapper.insert(dbDevice);// @Sql: 先插入出一条存在的数据 - // 准备参数 - IotDeviceSaveReqVO updateReqVO = randomPojo(IotDeviceSaveReqVO.class, o -> { - o.setId(dbDevice.getId()); // 设置更新的 ID - }); - - // 调用 - deviceService.updateDevice(updateReqVO); - // 校验是否更新正确 - IotDeviceDO device = deviceMapper.selectById(updateReqVO.getId()); // 获取最新的 - assertPojoEquals(updateReqVO, device); - } - - @Test - public void testUpdateDevice_notExists() { - // 准备参数 - IotDeviceSaveReqVO updateReqVO = randomPojo(IotDeviceSaveReqVO.class); - - // 调用, 并断言异常 - assertServiceException(() -> deviceService.updateDevice(updateReqVO), DEVICE_NOT_EXISTS); - } - - @Test - public void testDeleteDevice_success() { - // mock 数据 - IotDeviceDO dbDevice = randomPojo(IotDeviceDO.class); - deviceMapper.insert(dbDevice);// @Sql: 先插入出一条存在的数据 - // 准备参数 - Long id = dbDevice.getId(); - - // 调用 - deviceService.deleteDevice(id); - // 校验数据不存在了 - assertNull(deviceMapper.selectById(id)); - } - - @Test - public void testDeleteDevice_notExists() { - // 准备参数 - Long id = randomLongId(); - - // 调用, 并断言异常 - assertServiceException(() -> deviceService.deleteDevice(id), DEVICE_NOT_EXISTS); - } - - @Test - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 - public void testGetDevicePage() { - // mock 数据 - IotDeviceDO dbDevice = randomPojo(IotDeviceDO.class, o -> { // 等会查询到 - o.setDeviceKey(null); - o.setDeviceName(null); - o.setProductId(null); - o.setProductKey(null); - o.setDeviceType(null); - o.setNickname(null); - o.setGatewayId(null); - o.setStatus(null); - o.setStatusLastUpdateTime(null); - o.setLastOnlineTime(null); - o.setLastOfflineTime(null); - o.setActiveTime(null); - o.setIp(null); - o.setFirmwareVersion(null); - o.setDeviceSecret(null); - o.setMqttClientId(null); - o.setMqttUsername(null); - o.setMqttPassword(null); - o.setAuthType(null); - o.setLatitude(null); - o.setLongitude(null); - o.setAreaId(null); - o.setAddress(null); - o.setSerialNumber(null); - o.setCreateTime(null); - }); - deviceMapper.insert(dbDevice); - // 测试 deviceKey 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setDeviceKey(null))); - // 测试 deviceName 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setDeviceName(null))); - // 测试 productId 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setProductId(null))); - // 测试 productKey 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setProductKey(null))); - // 测试 deviceType 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setDeviceType(null))); - // 测试 nickname 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setNickname(null))); - // 测试 gatewayId 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setGatewayId(null))); - // 测试 status 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setStatus(null))); - // 测试 statusLastUpdateTime 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setStatusLastUpdateTime(null))); - // 测试 lastOnlineTime 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setLastOnlineTime(null))); - // 测试 lastOfflineTime 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setLastOfflineTime(null))); - // 测试 activeTime 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setActiveTime(null))); - // 测试 ip 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setIp(null))); - // 测试 firmwareVersion 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setFirmwareVersion(null))); - // 测试 deviceSecret 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setDeviceSecret(null))); - // 测试 mqttClientId 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setMqttClientId(null))); - // 测试 mqttUsername 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setMqttUsername(null))); - // 测试 mqttPassword 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setMqttPassword(null))); - // 测试 authType 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setAuthType(null))); - // 测试 latitude 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setLatitude(null))); - // 测试 longitude 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setLongitude(null))); - // 测试 areaId 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setAreaId(null))); - // 测试 address 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setAddress(null))); - // 测试 serialNumber 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setSerialNumber(null))); - // 测试 createTime 不匹配 - deviceMapper.insert(cloneIgnoreId(dbDevice, o -> o.setCreateTime(null))); - // 准备参数 - IotDevicePageReqVO reqVO = new IotDevicePageReqVO(); - reqVO.setDeviceKey(null); - reqVO.setDeviceName(null); - reqVO.setProductId(null); - reqVO.setProductKey(null); - reqVO.setDeviceType(null); - reqVO.setNickname(null); - reqVO.setGatewayId(null); - reqVO.setStatus(null); - reqVO.setStatusLastUpdateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); - reqVO.setLastOnlineTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); - reqVO.setLastOfflineTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); - reqVO.setActiveTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); - reqVO.setIp(null); - reqVO.setFirmwareVersion(null); - reqVO.setDeviceSecret(null); - reqVO.setMqttClientId(null); - reqVO.setMqttUsername(null); - reqVO.setMqttPassword(null); - reqVO.setAuthType(null); - reqVO.setLatitude(null); - reqVO.setLongitude(null); - reqVO.setAreaId(null); - reqVO.setAddress(null); - reqVO.setSerialNumber(null); - reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); - - // 调用 - PageResult pageResult = deviceService.getDevicePage(reqVO); - // 断言 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - assertPojoEquals(dbDevice, pageResult.getList().get(0)); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImplTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImplTest.java deleted file mode 100644 index 762f6021b..000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImplTest.java +++ /dev/null @@ -1,71 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.thinkmodelfunction; - -import org.junit.jupiter.api.Test; - -import jakarta.annotation.Resource; - -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; - -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.*; -import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; -import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper; - -import org.springframework.context.annotation.Import; - -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; -import static org.junit.jupiter.api.Assertions.*; - -/** - * {@link IotThinkModelFunctionServiceImpl} 的单元测试类 - * - * @author 芋道源码 - */ -@Import(IotThinkModelFunctionServiceImpl.class) -public class IotThinkModelFunctionServiceImplTest extends BaseDbUnitTest { - - @Resource - private IotThinkModelFunctionServiceImpl thinkModelFunctionService; - - @Resource - private IotThinkModelFunctionMapper thinkModelFunctionMapper; - - @Test - public void testCreateThinkModelFunction_success() { - // 准备参数 - IotThinkModelFunctionSaveReqVO createReqVO = randomPojo(IotThinkModelFunctionSaveReqVO.class); - - // 调用 - Long thinkModelFunctionId = thinkModelFunctionService.createThinkModelFunction(createReqVO); - // 断言 - assertNotNull(thinkModelFunctionId); - // 校验记录的属性是否正确 - IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionMapper.selectById(thinkModelFunctionId); - assertPojoEquals(createReqVO, thinkModelFunction, "id"); - } - - @Test - public void testDeleteThinkModelFunction_success() { - // mock 数据 - IotThinkModelFunctionDO dbThinkModelFunction = randomPojo(IotThinkModelFunctionDO.class); - thinkModelFunctionMapper.insert(dbThinkModelFunction);// @Sql: 先插入出一条存在的数据 - // 准备参数 - Long id = dbThinkModelFunction.getId(); - - // 调用 - thinkModelFunctionService.deleteThinkModelFunction(id); - // 校验数据不存在了 - assertNull(thinkModelFunctionMapper.selectById(id)); - } - - @Test - public void testDeleteThinkModelFunction_notExists() { - // 准备参数 - Long id = randomLongId(); - - // 调用, 并断言异常 - assertServiceException(() -> thinkModelFunctionService.deleteThinkModelFunction(id), THINK_MODEL_FUNCTION_NOT_EXISTS); - } - -} \ No newline at end of file From 643e28938458a740b5975f99992533c0c10d70e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sun, 22 Sep 2024 13:16:32 +0800 Subject: [PATCH 27/31] =?UTF-8?q?=E3=80=90=E4=BC=98=E5=8C=96=E3=80=91IOT?= =?UTF-8?q?=20=E8=AE=BE=E5=A4=87=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/device/IotDeviceController.java | 21 ++--------- .../admin/device/vo/IotDevicePageReqVO.java | 30 +++------------- .../admin/device/vo/IotDeviceRespVO.java | 32 +---------------- .../device/vo/IotDeviceStatusUpdateReqVO.java | 21 +++++++++++ .../admin/product/IotProductController.java | 11 ++++++ .../product/vo/IotProductSimpleRespVO.java | 16 +++++++++ .../dal/dataobject/device/IotDeviceDO.java | 14 ++++---- .../iot/dal/mysql/device/IotDeviceMapper.java | 7 ---- .../dal/mysql/product/IotProductMapper.java | 1 + .../iot/service/device/DeviceServiceImpl.java | 36 ++++++------------- .../iot/service/device/IotDeviceService.java | 5 ++- .../service/product/IotProductService.java | 10 ++++++ .../product/IotProductServiceImpl.java | 6 ++++ .../IotThinkModelFunctionServiceImpl.java | 20 ++++++++--- 14 files changed, 110 insertions(+), 120 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceStatusUpdateReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSimpleRespVO.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java index e455c78cf..15c54b6ab 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceRespVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceStatusUpdateReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import io.swagger.v3.oas.annotations.Operation; @@ -45,12 +46,9 @@ public class IotDeviceController { @PutMapping("/update-status") @Operation(summary = "更新设备状态") - @Parameter(name = "id", description = "编号", required = true) - @Parameter(name = "status", description = "状态", required = true, example = "1") @PreAuthorize("@ss.hasPermission('iot:device:update')") - public CommonResult updateDeviceStatus(@RequestParam("id") Long id, - @RequestParam("status") Integer status) { - deviceService.updateDeviceStatus(id, status); + public CommonResult updateDeviceStatus(@Valid @RequestBody IotDeviceStatusUpdateReqVO updateReqVO) { + deviceService.updateDeviceStatus(updateReqVO); return success(true); } @@ -88,17 +86,4 @@ public class IotDeviceController { return success(BeanUtils.toBean(pageResult, IotDeviceRespVO.class)); } - @GetMapping("/export-excel") - @Operation(summary = "导出设备 Excel") - @PreAuthorize("@ss.hasPermission('iot:device:export')") - @ApiAccessLog(operateType = EXPORT) - public void exportDeviceExcel(@Valid IotDevicePageReqVO pageReqVO, - HttpServletResponse response) throws IOException { - pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); - List list = deviceService.getDevicePage(pageReqVO).getList(); - // 导出 Excel - ExcelUtils.write(response, "IoT 设备.xls", "数据", IotDeviceRespVO.class, - BeanUtils.toBean(list, IotDeviceRespVO.class)); - } - } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java index c2cd35685..26bdaca05 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.device.vo; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; +import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; @@ -28,6 +29,9 @@ public class IotDevicePageReqVO extends PageParam { @Schema(description = "设备名称", example = "王五") private String deviceName; + @Schema(description = "备注名称", example = "张三") + private String nickname; + @Schema(description = "产品编号", example = "26202") private Long productId; @@ -35,12 +39,9 @@ public class IotDevicePageReqVO extends PageParam { private String productKey; @Schema(description = "设备类型", example = "1") - // TODO @haohao:需要有个设备类型的枚举 + @InEnum(IotProductDeviceTypeEnum.class) private Integer deviceType; - @Schema(description = "备注名称", example = "张三") - private String nickname; - @Schema(description = "网关设备 ID", example = "16380") private Long gatewayId; @@ -64,12 +65,6 @@ public class IotDevicePageReqVO extends PageParam { @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] activeTime; - @Schema(description = "设备的 IP 地址") - private String ip; - - @Schema(description = "设备的固件版本") - private String firmwareVersion; - @Schema(description = "设备密钥,用于设备认证,需安全存储") private String deviceSecret; @@ -85,21 +80,6 @@ public class IotDevicePageReqVO extends PageParam { @Schema(description = "认证类型(如一机一密、动态注册)", example = "2") private String authType; - @Schema(description = "设备位置的纬度,范围 -90.000000 ~ 90.000000") - private BigDecimal latitude; - - @Schema(description = "设备位置的经度,范围 -180.000000 ~ 180.000000") - private BigDecimal longitude; - - @Schema(description = "地区编码,符合国家地区编码标准,关联地区表", example = "16995") - private Integer areaId; - - @Schema(description = "设备详细地址") - private String address; - - @Schema(description = "设备序列号") - private String serialNumber; - @Schema(description = "创建时间") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java index 0423b17a9..488f6b907 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java @@ -25,7 +25,7 @@ public class IotDeviceRespVO { private String deviceName; @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202") - @ExcelProperty("产品 ID") + @ExcelProperty("产品编号") private Long productId; @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED) @@ -41,7 +41,6 @@ public class IotDeviceRespVO { private String nickname; @Schema(description = "网关设备 ID", example = "16380") - @ExcelProperty("网关设备 ID") private Long gatewayId; @Schema(description = "设备状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @@ -64,14 +63,6 @@ public class IotDeviceRespVO { @ExcelProperty("设备激活时间") private LocalDateTime activeTime; - @Schema(description = "设备的 IP 地址") - @ExcelProperty("设备的 IP 地址") - private String ip; - - @Schema(description = "设备的固件版本") - @ExcelProperty("设备的固件版本") - private String firmwareVersion; - @Schema(description = "设备密钥,用于设备认证") @ExcelProperty("设备密钥") private String deviceSecret; @@ -92,27 +83,6 @@ public class IotDeviceRespVO { @ExcelProperty("认证类型(如一机一密、动态注册)") private String authType; - // TODO @haohao:经纬度:可能 double 就够啦 - @Schema(description = "设备位置的纬度,范围") - @ExcelProperty("设备位置的纬度") - private BigDecimal latitude; - - @Schema(description = "设备位置的经度") - @ExcelProperty("设备位置的经度") - private BigDecimal longitude; - - @Schema(description = "地区编码", example = "16995") - @ExcelProperty("地区编码") - private Integer areaId; - - @Schema(description = "设备详细地址") - @ExcelProperty("设备详细地址") - private String address; - - @Schema(description = "设备序列号") - @ExcelProperty("设备序列号") - private String serialNumber; - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("创建时间") private LocalDateTime createTime; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceStatusUpdateReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceStatusUpdateReqVO.java new file mode 100644 index 000000000..a91a58690 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceStatusUpdateReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.iot.controller.admin.device.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(description = "管理后台 - IoT 设备状态更新 Request VO") +@Data +public class IotDeviceStatusUpdateReqVO { + + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "设备编号不能为空") + private Long id; + + @Schema(description = "设备状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "设备状态不能为空") + @InEnum(IotDeviceStatusEnum.class) + private Integer status; +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java index 2a298e6a3..80cc2c4e5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductRespVO; import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSimpleRespVO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.service.product.IotProductService; import io.swagger.v3.oas.annotations.Operation; @@ -17,6 +18,8 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import java.util.List; + import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @Tag(name = "管理后台 - IoT 产品") @@ -80,4 +83,12 @@ public class IotProductController { return success(BeanUtils.toBean(pageResult, IotProductRespVO.class)); } + @GetMapping("/list-all-simple") + @Operation(summary = "获得所有产品列表") + @PreAuthorize("@ss.hasPermission('iot:product:query')") + public CommonResult> listAllSimpleProducts() { + List list = productService.listAllProducts(); + return success(BeanUtils.toBean(list, IotProductSimpleRespVO.class)); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSimpleRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSimpleRespVO.java new file mode 100644 index 000000000..83855eaaf --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSimpleRespVO.java @@ -0,0 +1,16 @@ +package cn.iocoder.yudao.module.iot.controller.admin.product.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - IoT 产品 Response VO") +@Data +public class IotProductSimpleRespVO { + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26087") + private Long id; + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + private String name; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java index d61e640ae..d3f6547a1 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java @@ -50,34 +50,34 @@ public class IotDeviceDO extends BaseDO { /** * 产品编号 - * + *

* 关联 {@link IotProductDO#getId()} */ private Long productId; /** * 产品标识 - * + *

* 冗余 {@link IotProductDO#getProductKey()} */ private String productKey; /** * 设备类型 - * + *

* 冗余 {@link IotProductDO#getDeviceType()} */ private Integer deviceType; /** * 设备状态 - * + *

* 枚举 {@link IotDeviceStatusEnum} */ private Integer status; /** * 网关设备编号 - * + *

* 子设备需要关联的网关设备 ID - * + *

* 关联 {@link IotDeviceDO#getId()} */ private Long gatewayId; @@ -140,7 +140,7 @@ public class IotDeviceDO extends BaseDO { private BigDecimal longitude; /** * 地区编码 - * + *

* 关联 Area 的 id */ private Integer areaId; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index 0224c6da3..1fa9334f4 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -29,18 +29,11 @@ public interface IotDeviceMapper extends BaseMapperX { .betweenIfPresent(IotDeviceDO::getLastOnlineTime, reqVO.getLastOnlineTime()) .betweenIfPresent(IotDeviceDO::getLastOfflineTime, reqVO.getLastOfflineTime()) .betweenIfPresent(IotDeviceDO::getActiveTime, reqVO.getActiveTime()) - .eqIfPresent(IotDeviceDO::getIp, reqVO.getIp()) - .eqIfPresent(IotDeviceDO::getFirmwareVersion, reqVO.getFirmwareVersion()) .eqIfPresent(IotDeviceDO::getDeviceSecret, reqVO.getDeviceSecret()) .eqIfPresent(IotDeviceDO::getMqttClientId, reqVO.getMqttClientId()) .likeIfPresent(IotDeviceDO::getMqttUsername, reqVO.getMqttUsername()) .eqIfPresent(IotDeviceDO::getMqttPassword, reqVO.getMqttPassword()) .eqIfPresent(IotDeviceDO::getAuthType, reqVO.getAuthType()) - .eqIfPresent(IotDeviceDO::getLatitude, reqVO.getLatitude()) - .eqIfPresent(IotDeviceDO::getLongitude, reqVO.getLongitude()) - .eqIfPresent(IotDeviceDO::getAreaId, reqVO.getAreaId()) - .eqIfPresent(IotDeviceDO::getAddress, reqVO.getAddress()) - .eqIfPresent(IotDeviceDO::getSerialNumber, reqVO.getSerialNumber()) .betweenIfPresent(IotDeviceDO::getCreateTime, reqVO.getCreateTime()) .orderByDesc(IotDeviceDO::getId)); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java index 694d7c007..0341e2492 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java @@ -25,4 +25,5 @@ public interface IotProductMapper extends BaseMapperX { default IotProductDO selectByProductKey(String productKey) { return selectOne(new LambdaQueryWrapperX().eq(IotProductDO::getProductKey, productKey)); } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java index 0b4db169f..72475626a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java @@ -6,11 +6,12 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceStatusUpdateReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper; -import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper; import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum; +import cn.iocoder.yudao.module.iot.service.product.IotProductService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -35,9 +36,8 @@ public class DeviceServiceImpl implements IotDeviceService { @Resource private IotDeviceMapper deviceMapper; - // TODO @haohao:不直接调用 productmapper,通过 productservice;每一个模型,不直接使用对方的 @Resource - private IotProductMapper productMapper; + private IotProductService productService; /** * 创建 IoT 设备 @@ -49,7 +49,7 @@ public class DeviceServiceImpl implements IotDeviceService { @Transactional(rollbackFor = Exception.class) public Long createDevice(IotDeviceSaveReqVO createReqVO) { // 1.1 校验产品是否存在 - IotProductDO product = productMapper.selectById(createReqVO.getProductId()); + IotProductDO product = productService.getProduct(createReqVO.getProductId()); if (product == null) { throw exception(PRODUCT_NOT_EXISTS); } @@ -106,8 +106,7 @@ public class DeviceServiceImpl implements IotDeviceService { * @return 生成的 deviceSecret */ private String generateDeviceSecret() { - // TODO @haohao:return IdUtil.fastSimpleUUID() - return UUID.randomUUID().toString().replace("-", ""); + return IdUtil.fastSimpleUUID(); } /** @@ -147,7 +146,6 @@ public class DeviceServiceImpl implements IotDeviceService { * @return 生成的唯一 DeviceName */ private String generateUniqueDeviceName(String productKey) { - // TODO @haohao:业务逻辑里,尽量避免 while true。万一 bug = =;虽然这个不会哈。我先改了下 for (int i = 0; i < Short.MAX_VALUE; i++) { String deviceName = IdUtil.fastSimpleUUID().substring(0, 20); if (deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName) != null) { @@ -161,16 +159,11 @@ public class DeviceServiceImpl implements IotDeviceService { @Transactional(rollbackFor = Exception.class) public void updateDevice(IotDeviceSaveReqVO updateReqVO) { // 校验存在 - IotDeviceDO existingDevice = validateDeviceExists(updateReqVO.getId()); + validateDeviceExists(updateReqVO.getId()); // 设备名称 和 产品 ID 不能修改 - // TODO @haohao:这种,直接设置为 null 就不会更新了。忽略前端的传参 - if (updateReqVO.getDeviceName() != null && !updateReqVO.getDeviceName().equals(existingDevice.getDeviceName())) { - throw exception(DEVICE_NAME_CANNOT_BE_MODIFIED); - } - if (updateReqVO.getProductId() != null && !updateReqVO.getProductId().equals(existingDevice.getProductId())) { - throw exception(DEVICE_PRODUCT_CANNOT_BE_MODIFIED); - } + updateReqVO.setDeviceName(null); + updateReqVO.setProductId(null); // 更新 DO 对象 IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class); @@ -222,19 +215,12 @@ public class DeviceServiceImpl implements IotDeviceService { } @Override - public void updateDeviceStatus(Long id, Integer status) { + public void updateDeviceStatus(IotDeviceStatusUpdateReqVO updateReqVO) { // 校验存在 - validateDeviceExists(id); - - // TODO @haohao:这个可以直接用 swagger 注解哈 - // 校验状态是否合法 - if (!IotDeviceStatusEnum.isValidStatus(status)) { - throw exception(DEVICE_INVALID_DEVICE_STATUS); - } + validateDeviceExists(updateReqVO.getId()); // 更新状态和更新时间 - IotDeviceDO updateObj = new IotDeviceDO().setId(id).setStatus(status) - .setStatusLastUpdateTime(LocalDateTime.now()); + IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class); deviceMapper.updateById(updateObj); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index 9b6de37bf..725848f4f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -53,9 +53,8 @@ public interface IotDeviceService { /** * 更新设备状态 * - * @param id 编号 - * @param status 状态 + * @param updateReqVO 更新信息 */ - void updateDeviceStatus(Long id, Integer status); + void updateDeviceStatus(IotDeviceStatusUpdateReqVO updateReqVO); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java index 9677701f1..0e32b6dfd 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java @@ -6,6 +6,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSaveReq import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; import jakarta.validation.Valid; +import java.util.List; + /** * IoT 产品 Service 接口 * @@ -58,4 +60,12 @@ public interface IotProductService { * @param status 状态 */ void updateProductStatus(Long id, Integer status); + + /** + * 获得所有产品 + * + * @return 产品列表 + */ + List listAllProducts(); + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index 96975c27f..0ebe24933 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -12,6 +12,7 @@ import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.List; import java.util.Objects; import java.util.UUID; @@ -113,4 +114,9 @@ public class IotProductServiceImpl implements IotProductService { productMapper.updateById(updateObj); } + @Override + public List listAllProducts() { + return productMapper.selectList(); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index 64ff3d319..9feb619aa 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -24,6 +24,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; +import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList; @@ -176,22 +177,33 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe List createList = diffResult.get(0); // 需要新增的 List updateList = diffResult.get(1); // 需要更新的 List deleteList = diffResult.get(2); // 需要删除的 + // 3.2 批量执行数据库操作 + // 新增数据库中的新事件和服务列表 if (CollUtil.isNotEmpty(createList)) { thinkModelFunctionMapper.insertBatch(createList); } + // 更新数据库中的事件和服务列表 if (CollUtil.isNotEmpty(updateList)) { - for (IotThinkModelFunctionDO updateFunc : updateList) { - // 设置 ID,以便更新 + // 首先,为每个需要更新的对象设置其对应的 ID + updateList.forEach(updateFunc -> { IotThinkModelFunctionDO oldFunc = findFunctionByIdentifierAndType( oldFunctionList, updateFunc.getIdentifier(), updateFunc.getType()); if (oldFunc != null) { updateFunc.setId(oldFunc.getId()); - thinkModelFunctionMapper.updateById(updateFunc); } + }); + // 过滤掉没有设置 ID 的对象 + List validUpdateList = updateList.stream() + .filter(func -> func.getId() != null) + .collect(Collectors.toList()); + // 执行批量更新 + if (CollUtil.isNotEmpty(validUpdateList)) { + thinkModelFunctionMapper.updateBatch(validUpdateList); } - // TODO @haohao:seckillProductMapper.updateBatch(diffList.get(1)); 可以直接类似这么操作哇? } + + // 删除数据库中的旧事件和服务列表 if (CollUtil.isNotEmpty(deleteList)) { Set idsToDelete = CollectionUtils.convertSet(deleteList, IotThinkModelFunctionDO::getId); thinkModelFunctionMapper.deleteByIds(idsToDelete); From 1719b69ef7366f12ebbe7f4443957fc3f27326f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Mon, 23 Sep 2024 23:35:09 +0800 Subject: [PATCH 28/31] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E3=80=91IOT?= =?UTF-8?q?=20=E8=AE=BE=E5=A4=87=E7=AE=A1=E7=90=86=EF=BC=8C=E8=8E=B7?= =?UTF-8?q?=E5=BE=97=E8=AE=BE=E5=A4=87=E6=95=B0=E9=87=8F=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/device/IotDeviceController.java | 16 ++++++++-------- .../iot/dal/mysql/device/IotDeviceMapper.java | 3 +++ .../iot/service/device/DeviceServiceImpl.java | 5 +++++ .../iot/service/device/IotDeviceService.java | 7 +++++++ 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java index 15c54b6ab..f6185a95f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -1,11 +1,8 @@ package cn.iocoder.yudao.module.iot.controller.admin.device; -import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceRespVO; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO; @@ -16,16 +13,11 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import java.io.IOException; -import java.util.List; - -import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @Tag(name = "管理后台 - IoT 设备") @@ -86,4 +78,12 @@ public class IotDeviceController { return success(BeanUtils.toBean(pageResult, IotDeviceRespVO.class)); } + @GetMapping("/count") + @Operation(summary = "获得设备数量") + @Parameter(name = "productId", description = "产品编号", example = "1") + @PreAuthorize("@ss.hasPermission('iot:device:query')") + public CommonResult getDeviceCount(@RequestParam("productId") Long productId) { + return success(deviceService.getDeviceCount(productId)); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index 1fa9334f4..0e5552f83 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -47,4 +47,7 @@ public interface IotDeviceMapper extends BaseMapperX { return selectCount(IotDeviceDO::getGatewayId, id); } + default Long selectCountByProductId(Long productId) { + return selectCount(IotDeviceDO::getProductId, productId); + } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java index 72475626a..fbd6da96d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java @@ -224,4 +224,9 @@ public class DeviceServiceImpl implements IotDeviceService { deviceMapper.updateById(updateObj); } + @Override + public Long getDeviceCount(Long productId) { + return deviceMapper.selectCountByProductId(productId); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index 725848f4f..a62d8d858 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -57,4 +57,11 @@ public interface IotDeviceService { */ void updateDeviceStatus(IotDeviceStatusUpdateReqVO updateReqVO); + /** + * 获得设备数量 + * + * @param productId 产品编号 + * @return 设备数量 + */ + Long getDeviceCount(Long productId); } \ No newline at end of file From 1995c322e7085aa125f90cc5ed1d557a7cf35d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sun, 29 Sep 2024 21:37:40 +0800 Subject: [PATCH 29/31] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E3=80=91=20?= =?UTF-8?q?=E4=BA=A7=E5=93=81=E7=89=A9=E6=A8=A1=E5=9E=8B=E5=88=86=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...m.java => IotProductFunctionTypeEnum.java} | 6 ++-- .../IotThinkModelFunctionController.java | 11 +++++++ .../vo/IotThinkModelFunctionPageReqVO.java | 32 +++++++++++++++++++ .../vo/IotThinkModelFunctionSaveReqVO.java | 4 +-- .../IotThinkModelFunctionConvert.java | 8 ++--- .../IotThinkModelFunctionDO.java | 3 +- .../IotThinkModelFunctionMapper.java | 12 +++++++ .../IotThinkModelFunctionService.java | 10 ++++++ .../IotThinkModelFunctionServiceImpl.java | 23 ++++++++----- 9 files changed, 91 insertions(+), 18 deletions(-) rename yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/{IotThingModelTypeEnum.java => IotProductFunctionTypeEnum.java} (81%) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionPageReqVO.java diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotThingModelTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java similarity index 81% rename from yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotThingModelTypeEnum.java rename to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java index 872dda6a3..9ba3d81b4 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotThingModelTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java @@ -7,13 +7,13 @@ import lombok.Getter; import java.util.Arrays; /** - * IOT 物模型功能类型枚举类 + * IOT 产品功能类型枚举类 * * @author ahh */ @AllArgsConstructor @Getter -public enum IotThingModelTypeEnum implements IntArrayValuable { +public enum IotProductFunctionTypeEnum implements IntArrayValuable { /** * 属性 @@ -28,7 +28,7 @@ public enum IotThingModelTypeEnum implements IntArrayValuable { */ EVENT(3, "事件"); - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotThingModelTypeEnum::getType).toArray(); + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotProductFunctionTypeEnum::getType).toArray(); /** * 类型 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java index 36b91e85b..6bf516378 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java @@ -1,6 +1,9 @@ package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert; @@ -71,4 +74,12 @@ public class IotThinkModelFunctionController { List respVO = IotThinkModelFunctionConvert.INSTANCE.convertList(thinkModelFunctionListByProductId); return success(respVO); } + + @GetMapping("/page") + @Operation(summary = "获得IoT 产品物模型分页") + @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')") + public CommonResult> getThinkModelFunctionPage(@Valid IotThinkModelFunctionPageReqVO pageReqVO) { + PageResult pageResult = thinkModelFunctionService.getThinkModelFunctionPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotThinkModelFunctionRespVO.class)); + } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionPageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionPageReqVO.java new file mode 100644 index 000000000..8a590d429 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionPageReqVO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - IoT 产品物模型分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class IotThinkModelFunctionPageReqVO extends PageParam { + + @Schema(description = "功能标识") + private String identifier; + + @Schema(description = "功能名称", example = "张三") + private String name; + + @Schema(description = "功能类型", example = "1") + @InEnum(IotProductFunctionTypeEnum.class) + private Integer type; + + @Schema(description = "产品ID", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "产品ID不能为空") + private Long productId; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java index 106972fe3..7d51ce504 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; -import cn.iocoder.yudao.module.iot.enums.product.IotThingModelTypeEnum; +import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; @@ -38,7 +38,7 @@ public class IotThinkModelFunctionSaveReqVO { @Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "功能类型不能为空") - @InEnum(IotThingModelTypeEnum.class) + @InEnum(IotProductFunctionTypeEnum.class) private Integer type; @Schema(description = "属性", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java index 08dabd5d6..764d4c030 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java @@ -6,7 +6,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingMode import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; -import cn.iocoder.yudao.module.iot.enums.product.IotThingModelTypeEnum; +import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; @@ -26,21 +26,21 @@ public interface IotThinkModelFunctionConvert { IotThinkModelFunctionDO convert(IotThinkModelFunctionSaveReqVO bean); default ThingModelProperty convertToProperty(IotThinkModelFunctionSaveReqVO bean) { - if (Objects.equals(bean.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { + if (Objects.equals(bean.getType(), IotProductFunctionTypeEnum.PROPERTY.getType())) { return bean.getProperty(); } return null; } default ThingModelEvent convertToEvent(IotThinkModelFunctionSaveReqVO bean) { - if (Objects.equals(bean.getType(), IotThingModelTypeEnum.EVENT.getType())) { + if (Objects.equals(bean.getType(), IotProductFunctionTypeEnum.EVENT.getType())) { return bean.getEvent(); } return null; } default ThingModelService convertToService(IotThinkModelFunctionSaveReqVO bean) { - if (Objects.equals(bean.getType(), IotThingModelTypeEnum.SERVICE.getType())) { + if (Objects.equals(bean.getType(), IotProductFunctionTypeEnum.SERVICE.getType())) { return bean.getService(); } return null; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java index f05562452..02b2f9707 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thinkmodelfunction/IotThinkModelFunctionDO.java @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingMode import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO; +import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; @@ -65,7 +66,7 @@ public class IotThinkModelFunctionDO extends BaseDO { /** * 功能类型 *

- * 枚举 {@link cn.iocoder.yudao.module.iot.enums.product.IotThingModelTypeEnum} + * 枚举 {@link IotProductFunctionTypeEnum} */ private Integer type; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java index 7227a0f26..be8bde652 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction; +import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionPageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import org.apache.ibatis.annotations.Mapper; @@ -15,6 +17,16 @@ import java.util.List; @Mapper public interface IotThinkModelFunctionMapper extends BaseMapperX { + default PageResult selectPage(IotThinkModelFunctionPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(IotThinkModelFunctionDO::getIdentifier, reqVO.getIdentifier()) + .likeIfPresent(IotThinkModelFunctionDO::getName, reqVO.getName()) + .eqIfPresent(IotThinkModelFunctionDO::getType, reqVO.getType()) + .eqIfPresent(IotThinkModelFunctionDO::getProductId, reqVO.getProductId()) + .orderByDesc(IotThinkModelFunctionDO::getId)); + } + + default IotThinkModelFunctionDO selectByProductIdAndIdentifier(Long productId, String identifier) { return selectOne(IotThinkModelFunctionDO::getProductId, productId, IotThinkModelFunctionDO::getIdentifier, identifier); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java index e2a5ad38d..7e7ab5916 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.iot.service.thinkmodelfunction; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import jakarta.validation.Valid; @@ -51,4 +53,12 @@ public interface IotThinkModelFunctionService { * @return 产品物模型列表 */ List getThinkModelFunctionListByProductId(Long productId); + + /** + * 获得产品物模型分页 + * + * @param pageReqVO 分页查询 + * @return 产品物模型分页 + */ + PageResult getThinkModelFunctionPage(IotThinkModelFunctionPageReqVO pageReqVO); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java index 9feb619aa..21759a145 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.service.thinkmodelfunction; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; @@ -11,12 +12,13 @@ import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingMode import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArraySpecs; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelArrayType; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.dataType.ThingModelTextType; +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert; import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; import cn.iocoder.yudao.module.iot.dal.mysql.thinkmodelfunction.IotThinkModelFunctionMapper; import cn.iocoder.yudao.module.iot.enums.product.IotAccessModeEnum; -import cn.iocoder.yudao.module.iot.enums.product.IotThingModelTypeEnum; +import cn.iocoder.yudao.module.iot.enums.product.IotProductFunctionTypeEnum; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -55,7 +57,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe thinkModelFunctionMapper.insert(function); // 3. 如果创建的是属性,需要更新默认的事件和服务 - if (Objects.equals(createReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { + if (Objects.equals(createReqVO.getType(), IotProductFunctionTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(createReqVO.getProductId(), createReqVO.getProductKey()); } return function.getId(); @@ -82,7 +84,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe thinkModelFunctionMapper.updateById(thinkModelFunction); // 4. 如果更新的是属性,需要更新默认的事件和服务 - if (Objects.equals(updateReqVO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { + if (Objects.equals(updateReqVO.getType(), IotProductFunctionTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(updateReqVO.getProductId(), updateReqVO.getProductKey()); } } @@ -107,7 +109,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe thinkModelFunctionMapper.deleteById(id); // 3. 如果删除的是属性,需要更新默认的事件和服务 - if (Objects.equals(functionDO.getType(), IotThingModelTypeEnum.PROPERTY.getType())) { + if (Objects.equals(functionDO.getType(), IotProductFunctionTypeEnum.PROPERTY.getType())) { createDefaultEventsAndServices(functionDO.getProductId(), functionDO.getProductKey()); } } @@ -133,13 +135,18 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe return thinkModelFunctionMapper.selectListByProductId(productId); } + @Override + public PageResult getThinkModelFunctionPage(IotThinkModelFunctionPageReqVO pageReqVO) { + return thinkModelFunctionMapper.selectPage(pageReqVO); + } + /** * 创建默认的事件和服务 */ public void createDefaultEventsAndServices(Long productId, String productKey) { // 1. 获取当前属性列表 List propertyList = thinkModelFunctionMapper - .selectListByProductIdAndType(productId, IotThingModelTypeEnum.PROPERTY.getType()); + .selectListByProductIdAndType(productId, IotProductFunctionTypeEnum.PROPERTY.getType()); // 2. 生成新的事件和服务列表 List newFunctionList = new ArrayList<>(); @@ -166,7 +173,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe List oldFunctionList = thinkModelFunctionMapper.selectListByProductIdAndIdentifiersAndTypes( productId, Arrays.asList("post", "set", "get"), - Arrays.asList(IotThingModelTypeEnum.EVENT.getType(), IotThingModelTypeEnum.SERVICE.getType()) + Arrays.asList(IotProductFunctionTypeEnum.EVENT.getType(), IotProductFunctionTypeEnum.SERVICE.getType()) ); // 3.1 使用 diffList 方法比较新旧列表 @@ -229,7 +236,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe .setIdentifier(event.getIdentifier()) .setName(event.getName()) .setDescription(event.getDescription()) - .setType(IotThingModelTypeEnum.EVENT.getType()) + .setType(IotProductFunctionTypeEnum.EVENT.getType()) .setEvent(event); } @@ -243,7 +250,7 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe .setIdentifier(service.getIdentifier()) .setName(service.getName()) .setDescription(service.getDescription()) - .setType(IotThingModelTypeEnum.SERVICE.getType()) + .setType(IotProductFunctionTypeEnum.SERVICE.getType()) .setService(service); } From 5a456a95e7832f35e4632740afc5af47b6dab0f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Mon, 30 Sep 2024 12:21:53 +0800 Subject: [PATCH 30/31] =?UTF-8?q?=E3=80=90=E4=BC=98=E5=8C=96=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E3=80=91=20=E6=96=B0=E5=A2=9E=E4=BA=A7=E5=93=81?= =?UTF-8?q?=E7=89=A9=E6=A8=A1=E5=9E=8B=EF=BC=8C=E6=A0=A1=E9=AA=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/iot/enums/ErrorCodeConstants.java | 4 ++- .../IotThinkModelFunctionMapper.java | 5 +++ .../IotThinkModelFunctionServiceImpl.java | 34 +++++++++++++++---- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index 0a103b354..31702e1e6 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -17,7 +17,9 @@ public interface ErrorCodeConstants { // ========== IoT 产品物模型 1-050-002-000 ============ ErrorCode THINK_MODEL_FUNCTION_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在"); ErrorCode THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY = new ErrorCode(1_050_002_001, "ProductKey 对应的产品物模型已存在"); - ErrorCode THINK_MODEL_FUNCTION_EXISTS_BY_IDENTIFIER = new ErrorCode(1_050_002_002, "产品物模型标识已存在"); + ErrorCode THINK_MODEL_FUNCTION_IDENTIFIER_EXISTS = new ErrorCode(1_050_002_002, "存在重复的功能标识符。"); + ErrorCode THINK_MODEL_FUNCTION_NAME_EXISTS = new ErrorCode(1_050_002_003, "存在重复的功能名称。"); + ErrorCode THINK_MODEL_FUNCTION_IDENTIFIER_INVALID = new ErrorCode(1_050_002_003, "产品物模型标识无效"); // ========== IoT 设备 1-050-003-000 ============ ErrorCode DEVICE_NOT_EXISTS = new ErrorCode(1_050_003_000, "设备不存在"); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java index be8bde652..25459072b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java @@ -23,6 +23,7 @@ public interface IotThinkModelFunctionMapper extends BaseMapperX Date: Tue, 1 Oct 2024 19:39:12 +0800 Subject: [PATCH 31/31] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E8=AF=84?= =?UTF-8?q?=E5=AE=A1=E3=80=91IoT=EF=BC=9A=E4=BA=A7=E5=93=81=E3=80=81?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E3=80=81=E7=89=A9=E6=A8=A1=E5=9E=8B=E7=9A=84?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/IotProductFunctionTypeEnum.java | 11 +-------- .../admin/device/IotDeviceController.java | 2 +- .../admin/product/IotProductController.java | 3 ++- .../IotThinkModelFunctionController.java | 23 +++++++++---------- .../IotThinkModelFunctionMapper.java | 2 +- .../iot/service/device/DeviceServiceImpl.java | 15 ++++-------- .../iot/service/device/IotDeviceService.java | 2 +- .../service/product/IotProductService.java | 2 +- .../product/IotProductServiceImpl.java | 2 +- .../IotThinkModelFunctionService.java | 1 + 10 files changed, 25 insertions(+), 38 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java index 9ba3d81b4..7a924997a 100644 --- a/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java +++ b/yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java @@ -7,7 +7,7 @@ import lombok.Getter; import java.util.Arrays; /** - * IOT 产品功能类型枚举类 + * IOT 产品功能(物模型)类型枚举类 * * @author ahh */ @@ -15,17 +15,8 @@ import java.util.Arrays; @Getter public enum IotProductFunctionTypeEnum implements IntArrayValuable { - /** - * 属性 - */ PROPERTY(1, "属性"), - /** - * 服务 - */ SERVICE(2, "服务"), - /** - * 事件 - */ EVENT(3, "事件"); public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(IotProductFunctionTypeEnum::getType).toArray(); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java index f6185a95f..6d75f1cdd 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -83,7 +83,7 @@ public class IotDeviceController { @Parameter(name = "productId", description = "产品编号", example = "1") @PreAuthorize("@ss.hasPermission('iot:device:query')") public CommonResult getDeviceCount(@RequestParam("productId") Long productId) { - return success(deviceService.getDeviceCount(productId)); + return success(deviceService.getDeviceCountByProductId(productId)); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java index 80cc2c4e5..5b0ecb27a 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java @@ -83,11 +83,12 @@ public class IotProductController { return success(BeanUtils.toBean(pageResult, IotProductRespVO.class)); } + // TODO @haohao:改成 simple-list 哈 @GetMapping("/list-all-simple") @Operation(summary = "获得所有产品列表") @PreAuthorize("@ss.hasPermission('iot:product:query')") public CommonResult> listAllSimpleProducts() { - List list = productService.listAllProducts(); + List list = productService.getProductList(); return success(BeanUtils.toBean(list, IotProductSimpleRespVO.class)); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java index 6bf516378..4f48f3628 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.java @@ -32,14 +32,14 @@ public class IotThinkModelFunctionController { private IotThinkModelFunctionService thinkModelFunctionService; @PostMapping("/create") - @Operation(summary = "创建IoT 产品物模型") + @Operation(summary = "创建产品物模型") @PreAuthorize("@ss.hasPermission('iot:think-model-function:create')") public CommonResult createThinkModelFunction(@Valid @RequestBody IotThinkModelFunctionSaveReqVO createReqVO) { return success(thinkModelFunctionService.createThinkModelFunction(createReqVO)); } @PutMapping("/update") - @Operation(summary = "更新IoT 产品物模型") + @Operation(summary = "更新产品物模型") @PreAuthorize("@ss.hasPermission('iot:think-model-function:update')") public CommonResult updateThinkModelFunction(@Valid @RequestBody IotThinkModelFunctionSaveReqVO updateReqVO) { thinkModelFunctionService.updateThinkModelFunction(updateReqVO); @@ -47,7 +47,7 @@ public class IotThinkModelFunctionController { } @DeleteMapping("/delete") - @Operation(summary = "删除IoT 产品物模型") + @Operation(summary = "删除产品物模型") @Parameter(name = "id", description = "编号", required = true) @PreAuthorize("@ss.hasPermission('iot:think-model-function:delete')") public CommonResult deleteThinkModelFunction(@RequestParam("id") Long id) { @@ -56,30 +56,29 @@ public class IotThinkModelFunctionController { } @GetMapping("/get") - @Operation(summary = "获得IoT 产品物模型") + @Operation(summary = "获得产品物模型") @Parameter(name = "id", description = "编号", required = true) @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')") public CommonResult getThinkModelFunction(@RequestParam("id") Long id) { - IotThinkModelFunctionDO thinkModelFunction = thinkModelFunctionService.getThinkModelFunction(id); - IotThinkModelFunctionRespVO respVO = IotThinkModelFunctionConvert.INSTANCE.convert(thinkModelFunction); - return success(respVO); + IotThinkModelFunctionDO function = thinkModelFunctionService.getThinkModelFunction(id); + return success(IotThinkModelFunctionConvert.INSTANCE.convert(function)); } @GetMapping("/list-by-product-id") - @Operation(summary = "获得IoT 产品物模型") + @Operation(summary = "获得产品物模型") @Parameter(name = "productId", description = "产品ID", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')") public CommonResult> getThinkModelFunctionListByProductId(@RequestParam("productId") Long productId) { - List thinkModelFunctionListByProductId = thinkModelFunctionService.getThinkModelFunctionListByProductId(productId); - List respVO = IotThinkModelFunctionConvert.INSTANCE.convertList(thinkModelFunctionListByProductId); - return success(respVO); + List list = thinkModelFunctionService.getThinkModelFunctionListByProductId(productId); + return success(IotThinkModelFunctionConvert.INSTANCE.convertList(list)); } @GetMapping("/page") - @Operation(summary = "获得IoT 产品物模型分页") + @Operation(summary = "获得产品物模型分页") @PreAuthorize("@ss.hasPermission('iot:think-model-function:query')") public CommonResult> getThinkModelFunctionPage(@Valid IotThinkModelFunctionPageReqVO pageReqVO) { PageResult pageResult = thinkModelFunctionService.getThinkModelFunctionPage(pageReqVO); return success(BeanUtils.toBean(pageResult, IotThinkModelFunctionRespVO.class)); } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java index 25459072b..e8b96e022 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thinkmodelfunction/IotThinkModelFunctionMapper.java @@ -27,7 +27,6 @@ public interface IotThinkModelFunctionMapper extends BaseMapperX listAllProducts(); + List getProductList(); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index 0ebe24933..15391f70b 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -115,7 +115,7 @@ public class IotProductServiceImpl implements IotProductService { } @Override - public List listAllProducts() { + public List getProductList() { return productMapper.selectList(); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java index 7e7ab5916..ce8e472f5 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionService.java @@ -61,4 +61,5 @@ public interface IotThinkModelFunctionService { * @return 产品物模型分页 */ PageResult getThinkModelFunctionPage(IotThinkModelFunctionPageReqVO pageReqVO); + } \ No newline at end of file