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 | 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 | 66 | DESCRIBE product_property_${productId} |
| 67 | 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 | 76 | <select id="selectListByHistory" |
| 70 | - resultType="cn.iocoder.yudao.module.iot.controller.admin.device.vo.property.IotDevicePropertyRespVO"> | |
| 77 | + resultMap="IotDevicePropertyRespVOMap"> | |
| 71 | 78 | SELECT ${@cn.hutool.core.util.StrUtil@toUnderlineCase(reqVO.identifier)} AS `value`, ts AS update_time |
| 72 | 79 | FROM device_property_${reqVO.deviceId} |
| 73 | 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 | 68 | |
| 69 | 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 | 78 | endpoint.exceptionHandler(ex -> { |
| 73 | 79 | log.warn("[handle][连接异常,客户端 ID: {},地址: {}]", clientId, connectionManager.getEndpointAddress(endpoint)); |
| 74 | 80 | cleanupConnection(endpoint); |
| ... | ... | @@ -77,7 +83,7 @@ public class IotMqttUpstreamHandler { |
| 77 | 83 | cleanupConnection(endpoint); |
| 78 | 84 | }); |
| 79 | 85 | |
| 80 | - // 3. 设置消息处理器 | |
| 86 | + // 4. 设置消息处理器 | |
| 81 | 87 | endpoint.publishHandler(message -> { |
| 82 | 88 | try { |
| 83 | 89 | processMessage(clientId, message.topicName(), message.payload().getBytes()); |
| ... | ... | @@ -100,7 +106,7 @@ public class IotMqttUpstreamHandler { |
| 100 | 106 | } |
| 101 | 107 | }); |
| 102 | 108 | |
| 103 | - // 4. 设置订阅处理器 | |
| 109 | + // 5. 设置订阅处理器 | |
| 104 | 110 | endpoint.subscribeHandler(subscribe -> { |
| 105 | 111 | // 提取主题名称列表用于日志显示 |
| 106 | 112 | List<String> topicNames = subscribe.topicSubscriptions().stream() |
| ... | ... | @@ -115,22 +121,22 @@ public class IotMqttUpstreamHandler { |
| 115 | 121 | endpoint.subscribeAcknowledge(subscribe.messageId(), grantedQoSLevels); |
| 116 | 122 | }); |
| 117 | 123 | |
| 118 | - // 5. 设置取消订阅处理器 | |
| 124 | + // 6. 设置取消订阅处理器 | |
| 119 | 125 | endpoint.unsubscribeHandler(unsubscribe -> { |
| 120 | 126 | log.debug("[handle][设备取消订阅,客户端 ID: {},主题: {}]", clientId, unsubscribe.topics()); |
| 121 | 127 | endpoint.unsubscribeAcknowledge(unsubscribe.messageId()); |
| 122 | 128 | }); |
| 123 | 129 | |
| 124 | - // 6. 设置 QoS 2消息的 PUBREL 处理器 | |
| 130 | + // 7. 设置 QoS 2消息的 PUBREL 处理器 | |
| 125 | 131 | endpoint.publishReleaseHandler(endpoint::publishComplete); |
| 126 | 132 | |
| 127 | - // 7. 设置断开连接处理器 | |
| 133 | + // 8. 设置断开连接处理器 | |
| 128 | 134 | endpoint.disconnectHandler(v -> { |
| 129 | 135 | log.debug("[handle][设备断开连接,客户端 ID: {}]", clientId); |
| 130 | 136 | cleanupConnection(endpoint); |
| 131 | 137 | }); |
| 132 | 138 | |
| 133 | - // 8. 接受连接 | |
| 139 | + // 9. 接受连接 | |
| 134 | 140 | endpoint.accept(false); |
| 135 | 141 | } |
| 136 | 142 | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml