mirror of
https://github.com/YunaiV/ruoyi-vue-pro.git
synced 2025-11-01 13:05:53 +08:00
feat: 【IoT 物联网】新增简单类型处理器配置和处理器,优化 JSON 解析问题
This commit is contained in:
@ -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 解析错误");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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); // 直接返回字符串
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
--- #################### 日志相关配置 ####################
|
--- #################### 日志相关配置 ####################
|
||||||
|
|||||||
Reference in New Issue
Block a user