Selaa lähdekoodia

feat: 【IoT 物联网】新增简单类型处理器配置和处理器,优化 JSON 解析问题

haohao 8 kuukautta sitten
vanhempi
commit
341e72c0b1

+ 33 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/mybatis/config/SimpleTypeHandlerConfig.java

@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.module.iot.framework.mybatis.config;
+
+import cn.iocoder.yudao.module.iot.framework.mybatis.handler.SimpleObjectTypeHandler;
+import jakarta.annotation.PostConstruct;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.apache.ibatis.type.TypeHandlerRegistry;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 简单类型处理器配置
+ * 注册自定义的类型处理器,避免 JSON 解析错误
+ *
+ * @author 芋道源码
+ */
+@Slf4j
+@Configuration
+public class SimpleTypeHandlerConfig {
+
+    @Resource
+    private SqlSessionFactory sqlSessionFactory;
+
+    @PostConstruct
+    public void registerTypeHandlers() {
+        TypeHandlerRegistry registry = sqlSessionFactory.getConfiguration().getTypeHandlerRegistry();
+
+        // 注册简单的 Object 类型处理器,避免 JSON 解析问题
+        registry.register(java.lang.Object.class, new SimpleObjectTypeHandler());
+
+        log.info("简单类型处理器注册完成,避免 JSON 解析错误");
+    }
+}

+ 39 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/mybatis/handler/SimpleObjectTypeHandler.java

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.iot.framework.mybatis.handler;
+
+import org.apache.ibatis.type.BaseTypeHandler;
+import org.apache.ibatis.type.JdbcType;
+
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * 简单的 Object 类型处理器
+ * 直接返回字符串,避免 JSON 解析问题
+ *
+ * @author 芋道源码
+ */
+public class SimpleObjectTypeHandler extends BaseTypeHandler<Object> {
+
+    @Override
+    public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType)
+            throws SQLException {
+        ps.setString(i, parameter.toString());
+    }
+
+    @Override
+    public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
+        return rs.getString(columnName); // 直接返回字符串
+    }
+
+    @Override
+    public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
+        return rs.getString(columnIndex); // 直接返回字符串
+    }
+
+    @Override
+    public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
+        return cs.getString(columnIndex); // 直接返回字符串
+    }
+}

+ 8 - 1
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml

@@ -66,8 +66,15 @@
         DESCRIBE product_property_${productId}
     </select>
 
+    <resultMap id="IotDevicePropertyRespVOMap"
+               type="cn.iocoder.yudao.module.iot.controller.admin.device.vo.property.IotDevicePropertyRespVO">
+        <result property="value" column="value"
+                typeHandler="cn.iocoder.yudao.module.iot.framework.mybatis.handler.SimpleObjectTypeHandler"/>
+        <result property="updateTime" column="update_time" javaType="java.lang.Long"/>
+    </resultMap>
+
     <select id="selectListByHistory"
-            resultType="cn.iocoder.yudao.module.iot.controller.admin.device.vo.property.IotDevicePropertyRespVO">
+            resultMap="IotDevicePropertyRespVOMap">
         SELECT ${@cn.hutool.core.util.StrUtil@toUnderlineCase(reqVO.identifier)} AS `value`, ts AS update_time
         FROM device_property_${reqVO.deviceId}
         WHERE ${@cn.hutool.core.util.StrUtil@toUnderlineCase(reqVO.identifier)} IS NOT NULL

+ 13 - 7
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/mqtt/router/IotMqttUpstreamHandler.java

@@ -68,7 +68,13 @@ public class IotMqttUpstreamHandler {
 
         log.info("[handle][设备认证成功,建立连接,客户端 ID: {},用户名: {}]", clientId, username);
 
-        // 2. 设置异常和关闭处理器
+        // 2. 设置心跳处理器(监听客户端的 PINGREQ 消息)
+        endpoint.pingHandler(v -> {
+            log.debug("[handle][收到客户端心跳,客户端 ID: {}]", clientId);
+            // Vert.x 会自动发送 PINGRESP 响应,无需手动处理
+        });
+
+        // 3. 设置异常和关闭处理器
         endpoint.exceptionHandler(ex -> {
             log.warn("[handle][连接异常,客户端 ID: {},地址: {}]", clientId, connectionManager.getEndpointAddress(endpoint));
             cleanupConnection(endpoint);
@@ -77,7 +83,7 @@ public class IotMqttUpstreamHandler {
             cleanupConnection(endpoint);
         });
 
-        // 3. 设置消息处理器
+        // 4. 设置消息处理器
         endpoint.publishHandler(message -> {
             try {
                 processMessage(clientId, message.topicName(), message.payload().getBytes());
@@ -100,7 +106,7 @@ public class IotMqttUpstreamHandler {
             }
         });
 
-        // 4. 设置订阅处理器
+        // 5. 设置订阅处理器
         endpoint.subscribeHandler(subscribe -> {
             // 提取主题名称列表用于日志显示
             List<String> topicNames = subscribe.topicSubscriptions().stream()
@@ -115,22 +121,22 @@ public class IotMqttUpstreamHandler {
             endpoint.subscribeAcknowledge(subscribe.messageId(), grantedQoSLevels);
         });
 
-        // 5. 设置取消订阅处理器
+        // 6. 设置取消订阅处理器
         endpoint.unsubscribeHandler(unsubscribe -> {
             log.debug("[handle][设备取消订阅,客户端 ID: {},主题: {}]", clientId, unsubscribe.topics());
             endpoint.unsubscribeAcknowledge(unsubscribe.messageId());
         });
 
-        // 6. 设置 QoS 2消息的 PUBREL 处理器
+        // 7. 设置 QoS 2消息的 PUBREL 处理器
         endpoint.publishReleaseHandler(endpoint::publishComplete);
 
-        // 7. 设置断开连接处理器
+        // 8. 设置断开连接处理器
         endpoint.disconnectHandler(v -> {
             log.debug("[handle][设备断开连接,客户端 ID: {}]", clientId);
             cleanupConnection(endpoint);
         });
 
-        // 8. 接受连接
+        // 9. 接受连接
         endpoint.accept(false);
     }
 

+ 0 - 1
yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml

@@ -103,7 +103,6 @@ yudao:
           port: 1883
           max-message-size: 8192
           connect-timeout-seconds: 60
-          keep-alive-timeout-seconds: 300
           ssl-enabled: false
 
 --- #################### 日志相关配置 ####################