Commit 341e72c0b180611abaa1aec496ca90d4186b27cc
1 parent
5ae0224b
feat: 【IoT 物联网】新增简单类型处理器配置和处理器,优化 JSON 解析问题
Showing
5 changed files
with
93 additions
and
9 deletions
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 | --- #################### 日志相关配置 #################### |