Commit 341e72c0b180611abaa1aec496ca90d4186b27cc

Authored by haohao
1 parent 5ae0224b

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

yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/mybatis/config/SimpleTypeHandlerConfig.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.framework.mybatis.config;
  2 +
  3 +import cn.iocoder.yudao.module.iot.framework.mybatis.handler.SimpleObjectTypeHandler;
  4 +import jakarta.annotation.PostConstruct;
  5 +import jakarta.annotation.Resource;
  6 +import lombok.extern.slf4j.Slf4j;
  7 +import org.apache.ibatis.session.SqlSessionFactory;
  8 +import org.apache.ibatis.type.TypeHandlerRegistry;
  9 +import org.springframework.context.annotation.Configuration;
  10 +
  11 +/**
  12 + * 简单类型处理器配置
  13 + * 注册自定义的类型处理器,避免 JSON 解析错误
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Slf4j
  18 +@Configuration
  19 +public class SimpleTypeHandlerConfig {
  20 +
  21 + @Resource
  22 + private SqlSessionFactory sqlSessionFactory;
  23 +
  24 + @PostConstruct
  25 + public void registerTypeHandlers() {
  26 + TypeHandlerRegistry registry = sqlSessionFactory.getConfiguration().getTypeHandlerRegistry();
  27 +
  28 + // 注册简单的 Object 类型处理器,避免 JSON 解析问题
  29 + registry.register(java.lang.Object.class, new SimpleObjectTypeHandler());
  30 +
  31 + log.info("简单类型处理器注册完成,避免 JSON 解析错误");
  32 + }
  33 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/mybatis/handler/SimpleObjectTypeHandler.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.framework.mybatis.handler;
  2 +
  3 +import org.apache.ibatis.type.BaseTypeHandler;
  4 +import org.apache.ibatis.type.JdbcType;
  5 +
  6 +import java.sql.CallableStatement;
  7 +import java.sql.PreparedStatement;
  8 +import java.sql.ResultSet;
  9 +import java.sql.SQLException;
  10 +
  11 +/**
  12 + * 简单的 Object 类型处理器
  13 + * 直接返回字符串,避免 JSON 解析问题
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +public class SimpleObjectTypeHandler extends BaseTypeHandler<Object> {
  18 +
  19 + @Override
  20 + public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType)
  21 + throws SQLException {
  22 + ps.setString(i, parameter.toString());
  23 + }
  24 +
  25 + @Override
  26 + public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
  27 + return rs.getString(columnName); // 直接返回字符串
  28 + }
  29 +
  30 + @Override
  31 + public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
  32 + return rs.getString(columnIndex); // 直接返回字符串
  33 + }
  34 +
  35 + @Override
  36 + public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
  37 + return cs.getString(columnIndex); // 直接返回字符串
  38 + }
  39 +}
0 \ No newline at end of file 40 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml
@@ -66,8 +66,15 @@ @@ -66,8 +66,15 @@
66 DESCRIBE product_property_${productId} 66 DESCRIBE product_property_${productId}
67 </select> 67 </select>
68 68
  69 + <resultMap id="IotDevicePropertyRespVOMap"
  70 + type="cn.iocoder.yudao.module.iot.controller.admin.device.vo.property.IotDevicePropertyRespVO">
  71 + <result property="value" column="value"
  72 + typeHandler="cn.iocoder.yudao.module.iot.framework.mybatis.handler.SimpleObjectTypeHandler"/>
  73 + <result property="updateTime" column="update_time" javaType="java.lang.Long"/>
  74 + </resultMap>
  75 +
69 <select id="selectListByHistory" 76 <select id="selectListByHistory"
70 - resultType="cn.iocoder.yudao.module.iot.controller.admin.device.vo.property.IotDevicePropertyRespVO"> 77 + resultMap="IotDevicePropertyRespVOMap">
71 SELECT ${@cn.hutool.core.util.StrUtil@toUnderlineCase(reqVO.identifier)} AS `value`, ts AS update_time 78 SELECT ${@cn.hutool.core.util.StrUtil@toUnderlineCase(reqVO.identifier)} AS `value`, ts AS update_time
72 FROM device_property_${reqVO.deviceId} 79 FROM device_property_${reqVO.deviceId}
73 WHERE ${@cn.hutool.core.util.StrUtil@toUnderlineCase(reqVO.identifier)} IS NOT NULL 80 WHERE ${@cn.hutool.core.util.StrUtil@toUnderlineCase(reqVO.identifier)} IS NOT NULL
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 { @@ -68,7 +68,13 @@ public class IotMqttUpstreamHandler {
68 68
69 log.info("[handle][设备认证成功,建立连接,客户端 ID: {},用户名: {}]", clientId, username); 69 log.info("[handle][设备认证成功,建立连接,客户端 ID: {},用户名: {}]", clientId, username);
70 70
71 - // 2. 设置异常和关闭处理器 71 + // 2. 设置心跳处理器(监听客户端的 PINGREQ 消息)
  72 + endpoint.pingHandler(v -> {
  73 + log.debug("[handle][收到客户端心跳,客户端 ID: {}]", clientId);
  74 + // Vert.x 会自动发送 PINGRESP 响应,无需手动处理
  75 + });
  76 +
  77 + // 3. 设置异常和关闭处理器
72 endpoint.exceptionHandler(ex -> { 78 endpoint.exceptionHandler(ex -> {
73 log.warn("[handle][连接异常,客户端 ID: {},地址: {}]", clientId, connectionManager.getEndpointAddress(endpoint)); 79 log.warn("[handle][连接异常,客户端 ID: {},地址: {}]", clientId, connectionManager.getEndpointAddress(endpoint));
74 cleanupConnection(endpoint); 80 cleanupConnection(endpoint);
@@ -77,7 +83,7 @@ public class IotMqttUpstreamHandler { @@ -77,7 +83,7 @@ public class IotMqttUpstreamHandler {
77 cleanupConnection(endpoint); 83 cleanupConnection(endpoint);
78 }); 84 });
79 85
80 - // 3. 设置消息处理器 86 + // 4. 设置消息处理器
81 endpoint.publishHandler(message -> { 87 endpoint.publishHandler(message -> {
82 try { 88 try {
83 processMessage(clientId, message.topicName(), message.payload().getBytes()); 89 processMessage(clientId, message.topicName(), message.payload().getBytes());
@@ -100,7 +106,7 @@ public class IotMqttUpstreamHandler { @@ -100,7 +106,7 @@ public class IotMqttUpstreamHandler {
100 } 106 }
101 }); 107 });
102 108
103 - // 4. 设置订阅处理器 109 + // 5. 设置订阅处理器
104 endpoint.subscribeHandler(subscribe -> { 110 endpoint.subscribeHandler(subscribe -> {
105 // 提取主题名称列表用于日志显示 111 // 提取主题名称列表用于日志显示
106 List<String> topicNames = subscribe.topicSubscriptions().stream() 112 List<String> topicNames = subscribe.topicSubscriptions().stream()
@@ -115,22 +121,22 @@ public class IotMqttUpstreamHandler { @@ -115,22 +121,22 @@ public class IotMqttUpstreamHandler {
115 endpoint.subscribeAcknowledge(subscribe.messageId(), grantedQoSLevels); 121 endpoint.subscribeAcknowledge(subscribe.messageId(), grantedQoSLevels);
116 }); 122 });
117 123
118 - // 5. 设置取消订阅处理器 124 + // 6. 设置取消订阅处理器
119 endpoint.unsubscribeHandler(unsubscribe -> { 125 endpoint.unsubscribeHandler(unsubscribe -> {
120 log.debug("[handle][设备取消订阅,客户端 ID: {},主题: {}]", clientId, unsubscribe.topics()); 126 log.debug("[handle][设备取消订阅,客户端 ID: {},主题: {}]", clientId, unsubscribe.topics());
121 endpoint.unsubscribeAcknowledge(unsubscribe.messageId()); 127 endpoint.unsubscribeAcknowledge(unsubscribe.messageId());
122 }); 128 });
123 129
124 - // 6. 设置 QoS 2消息的 PUBREL 处理器 130 + // 7. 设置 QoS 2消息的 PUBREL 处理器
125 endpoint.publishReleaseHandler(endpoint::publishComplete); 131 endpoint.publishReleaseHandler(endpoint::publishComplete);
126 132
127 - // 7. 设置断开连接处理器 133 + // 8. 设置断开连接处理器
128 endpoint.disconnectHandler(v -> { 134 endpoint.disconnectHandler(v -> {
129 log.debug("[handle][设备断开连接,客户端 ID: {}]", clientId); 135 log.debug("[handle][设备断开连接,客户端 ID: {}]", clientId);
130 cleanupConnection(endpoint); 136 cleanupConnection(endpoint);
131 }); 137 });
132 138
133 - // 8. 接受连接 139 + // 9. 接受连接
134 endpoint.accept(false); 140 endpoint.accept(false);
135 } 141 }
136 142
yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml
@@ -103,7 +103,6 @@ yudao: @@ -103,7 +103,6 @@ yudao:
103 port: 1883 103 port: 1883
104 max-message-size: 8192 104 max-message-size: 8192
105 connect-timeout-seconds: 60 105 connect-timeout-seconds: 60
106 - keep-alive-timeout-seconds: 300  
107 ssl-enabled: false 106 ssl-enabled: false
108 107
109 --- #################### 日志相关配置 #################### 108 --- #################### 日志相关配置 ####################