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

This commit is contained in:
haohao
2025-09-22 23:10:26 +08:00
parent 5ae0224b55
commit 341e72c0b1
5 changed files with 93 additions and 9 deletions

View File

@ -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 解析错误");
}
}

View File

@ -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); // 直接返回字符串
}
}

View File

@ -66,8 +66,15 @@
DESCRIBE product_property_${productId} DESCRIBE product_property_${productId}
</select> </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" <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 SELECT ${@cn.hutool.core.util.StrUtil@toUnderlineCase(reqVO.identifier)} AS `value`, ts AS update_time
FROM device_property_${reqVO.deviceId} FROM device_property_${reqVO.deviceId}
WHERE ${@cn.hutool.core.util.StrUtil@toUnderlineCase(reqVO.identifier)} IS NOT NULL WHERE ${@cn.hutool.core.util.StrUtil@toUnderlineCase(reqVO.identifier)} IS NOT NULL

View File

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

View File

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