diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java index b074be47d8..99bbf2c4c2 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java @@ -22,7 +22,7 @@ public interface RedisKeyConstants { /** * 设备的最后上报时间,采用 ZSET 结构 * - * KEY 格式:{productKey},${deviceName} + * KEY 格式:{deviceId} * SCORE:上报时间 */ String DEVICE_REPORT_TIMES = "iot:device_report_times"; @@ -39,7 +39,7 @@ public interface RedisKeyConstants { /** * 设备信息的数据缓存,使用 Spring Cache 操作(忽略租户) * - * KEY 格式 1:device_${id} + * KEY 格式 1:device_${deviceId} * KEY 格式 2:device_${productKey}_${deviceName} * VALUE 数据类型:String(JSON) */ @@ -48,7 +48,7 @@ public interface RedisKeyConstants { /** * 产品信息的数据缓存,使用 Spring Cache 操作(忽略租户) * - * KEY 格式:product_${id} + * KEY 格式:product_${productId} * VALUE 数据类型:String(JSON) */ String PRODUCT = "iot:product"; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DeviceReportTimeRedisDAO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DeviceReportTimeRedisDAO.java index 27089283f2..0b28855833 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DeviceReportTimeRedisDAO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DeviceReportTimeRedisDAO.java @@ -1,8 +1,6 @@ package cn.iocoder.yudao.module.iot.dal.redis.device; import cn.hutool.core.date.LocalDateTimeUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants; import jakarta.annotation.Resource; import org.springframework.data.redis.core.StringRedisTemplate; @@ -11,6 +9,8 @@ import org.springframework.stereotype.Repository; import java.time.LocalDateTime; import java.util.Set; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + /** * 设备的最后上报时间的 Redis DAO * @@ -22,17 +22,15 @@ public class DeviceReportTimeRedisDAO { @Resource private StringRedisTemplate stringRedisTemplate; - public void update(String productKey, String deviceName, LocalDateTime reportTime) { - String value = productKey + StrUtil.COMMA + deviceName; // 使用 , 分隔 - stringRedisTemplate.opsForZSet().add(RedisKeyConstants.DEVICE_REPORT_TIMES, value, + public void update(Long deviceId, LocalDateTime reportTime) { + stringRedisTemplate.opsForZSet().add(RedisKeyConstants.DEVICE_REPORT_TIMES, String.valueOf(deviceId), LocalDateTimeUtil.toEpochMilli(reportTime)); } - public Set range(LocalDateTime maxReportTime) { - Set values = stringRedisTemplate.opsForZSet().rangeByScore(RedisKeyConstants.DEVICE_REPORT_TIMES, 0, - LocalDateTimeUtil.toEpochMilli(maxReportTime)); - return CollectionUtils.convertSet(values, - value -> value.split(StrUtil.COMMA)); // 使用, 分隔 + public Set range(LocalDateTime maxReportTime) { + Set values = stringRedisTemplate.opsForZSet().rangeByScore(RedisKeyConstants.DEVICE_REPORT_TIMES, + 0, LocalDateTimeUtil.toEpochMilli(maxReportTime)); + return convertSet(values, Long::parseLong); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DeviceServerIdRedisDAO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DeviceServerIdRedisDAO.java index e8f96a1ad5..cef78f3cff 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DeviceServerIdRedisDAO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DeviceServerIdRedisDAO.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.iot.dal.redis.device; -import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants; import jakarta.annotation.Resource; import org.springframework.data.redis.core.StringRedisTemplate; @@ -17,40 +16,15 @@ public class DeviceServerIdRedisDAO { @Resource private StringRedisTemplate stringRedisTemplate; - /** - * 更新设备关联的网关 serverId - * - * @param productKey 产品标识 - * @param deviceName 设备名称 - * @param serverId 网关 serverId - */ - public void update(String productKey, String deviceName, String serverId) { - String hashKey = buildHashKey(productKey, deviceName); - stringRedisTemplate.opsForHash().put(RedisKeyConstants.DEVICE_SERVER_ID, hashKey, serverId); + public void update(Long deviceId, String serverId) { + stringRedisTemplate.opsForHash().put(RedisKeyConstants.DEVICE_SERVER_ID, + String.valueOf(deviceId), serverId); } - /** - * 获得设备关联的网关 serverId - * - * @param productKey 产品标识 - * @param deviceName 设备名称 - * @return 网关 serverId - */ - public String get(String productKey, String deviceName) { - String hashKey = buildHashKey(productKey, deviceName); - Object value = stringRedisTemplate.opsForHash().get(RedisKeyConstants.DEVICE_SERVER_ID, hashKey); + public String get(Long deviceId) { + Object value = stringRedisTemplate.opsForHash().get(RedisKeyConstants.DEVICE_SERVER_ID, + String.valueOf(deviceId)); return value != null ? (String) value : null; } - /** - * 构建 HASH KEY - * - * @param productKey 产品标识 - * @param deviceName 设备名称 - * @return HASH KEY - */ - private String buildHashKey(String productKey, String deviceName) { - return productKey + StrUtil.COMMA + deviceName; - } - } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/device/IotDeviceOfflineCheckJob.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/device/IotDeviceOfflineCheckJob.java index 11b1934417..b14beafe23 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/device/IotDeviceOfflineCheckJob.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/device/IotDeviceOfflineCheckJob.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.iot.job.device; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; @@ -20,8 +19,6 @@ import java.util.Collections; import java.util.List; import java.util.Set; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; - /** * IoT 设备离线检查 Job * @@ -46,7 +43,6 @@ public class IotDeviceOfflineCheckJob implements JobHandler { @Resource private IotDeviceMessageService deviceMessageService; - // TODO @芋艿:需要重构下; @Override @TenantJob public String execute(String param) { @@ -56,22 +52,20 @@ public class IotDeviceOfflineCheckJob implements JobHandler { return JsonUtils.toJsonString(Collections.emptyList()); } // 1.2 获取超时的设备集合 - Set timeoutDevices = devicePropertyService.getProductKeyDeviceNameListByReportTime( + Set timeoutDeviceIds = devicePropertyService.getDeviceIdListByReportTime( LocalDateTime.now().minus(OFFLINE_TIMEOUT)); - Set timeoutDevices2 = convertSet(timeoutDevices, item -> item[0] + StrUtil.COMMA + item[1]); // 2. 下线设备 - List offlineDeviceKeys = CollUtil.newArrayList(); + List offlineDevices = CollUtil.newArrayList(); for (IotDeviceDO device : devices) { - String timeoutDeviceKey = device.getProductKey() + StrUtil.COMMA + device.getDeviceName(); - if (!timeoutDevices2.contains(timeoutDeviceKey)) { + if (!timeoutDeviceIds.contains(device.getId())) { continue; } - offlineDeviceKeys.add(new String[]{device.getProductKey(), device.getDeviceName()}); + offlineDevices.add(new String[]{device.getProductKey(), device.getDeviceName()}); // 为什么不直接更新状态呢?因为通过 IotDeviceMessage 可以经过一系列的处理,例如说记录日志等等 deviceMessageService.sendDeviceMessage(IotDeviceMessage.buildStateOffline().setDeviceId(device.getId())); } - return JsonUtils.toJsonString(offlineDeviceKeys); + return JsonUtils.toJsonString(offlineDevices); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceMessageSubscriber.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceMessageSubscriber.java index d830812e75..9f975ba32d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceMessageSubscriber.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceMessageSubscriber.java @@ -65,9 +65,9 @@ public class IotDeviceMessageSubscriber implements IotMessageSubscriber { // 1.1 更新设备的最后时间 IotDeviceDO device = deviceService.validateDeviceExistsFromCache(message.getDeviceId()); - devicePropertyService.updateDeviceReportTime(device.getProductKey(), device.getDeviceName(), LocalDateTime.now()); + devicePropertyService.updateDeviceReportTimeAsync(device.getId(), LocalDateTime.now()); // 1.2 更新设备的连接 server - devicePropertyService.updateDeviceServerId(device.getProductKey(), device.getDeviceName(), message.getServerId()); + devicePropertyService.updateDeviceServerIdAsync(device.getId(), message.getServerId()); // 2. 未上线的设备,强制上线 forceDeviceOnline(message, device); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/message/IotDeviceMessageServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/message/IotDeviceMessageServiceImpl.java index 5ea75f3ce0..838295fc03 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/message/IotDeviceMessageServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/message/IotDeviceMessageServiceImpl.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.iot.service.device.message; import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.exception.ServiceException; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum; @@ -16,6 +18,7 @@ import cn.iocoder.yudao.module.iot.service.device.property.IotDevicePropertyServ import com.google.common.base.Objects; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -56,10 +59,16 @@ public class IotDeviceMessageServiceImpl implements IotDeviceMessageService { log.info("[defineDeviceMessageStable][设备消息超级表不存在,创建成功]"); } - // TODO @芋艿:要不要异步记录; - private void createDeviceLog(IotDeviceMessage message) { + @Async + void createDeviceLogAsync(IotDeviceMessage message) { IotDeviceMessageDO messageDO = BeanUtils.toBean(message, IotDeviceMessageDO.class) .setUpstream(IotDeviceMessageUtils.isUpstreamMessage(message)); + if (message.getParams() != null) { + messageDO.setParams(JsonUtils.toJsonString(messageDO.getData())); + } + if (messageDO.getData() != null) { + messageDO.setData(JsonUtils.toJsonString(messageDO.getData())); + } deviceLogMapper.insert(messageDO); } @@ -72,6 +81,10 @@ public class IotDeviceMessageServiceImpl implements IotDeviceMessageService { // TODO @芋艿:针对连接网关的设备,是不是 productKey、deviceName 需要调整下; @Override public IotDeviceMessage sendDeviceMessage(IotDeviceMessage message, IotDeviceDO device) { + return sendDeviceMessage(message, device, null); + } + + private IotDeviceMessage sendDeviceMessage(IotDeviceMessage message, IotDeviceDO device, String serverId) { // 1. 补充信息 appendDeviceMessage(message, device); @@ -84,31 +97,31 @@ public class IotDeviceMessageServiceImpl implements IotDeviceMessageService { // 2.2 情况二:发送下行消息 // 如果是下行消息,需要校验 serverId 存在 - String serverId = devicePropertyService.getDeviceServerId(device.getProductKey(), device.getDeviceName()); if (StrUtil.isEmpty(serverId)) { - throw exception(DEVICE_DOWNSTREAM_FAILED_SERVER_ID_NULL); + serverId = devicePropertyService.getDeviceServerId(device.getId()); + if (StrUtil.isEmpty(serverId)) { + throw exception(DEVICE_DOWNSTREAM_FAILED_SERVER_ID_NULL); + } } deviceMessageProducer.sendDeviceMessageToGateway(serverId, message); // 特殊:记录消息日志。原因:上行消息,消费时,已经会记录;下行消息,因为消费在 Gateway 端,所以需要在这里记录 - createDeviceLog(message); + getSelf().createDeviceLogAsync(message); return message; } /** * 补充消息的后端字段 * - * @param message 消息 - * @param device 设备信息 - * @return 消息 + * @param message 消息 + * @param device 设备信息 */ - private IotDeviceMessage appendDeviceMessage(IotDeviceMessage message, IotDeviceDO device) { + private void appendDeviceMessage(IotDeviceMessage message, IotDeviceDO device) { message.setId(IotDeviceMessageUtils.generateMessageId()).setReportTime(LocalDateTime.now()) .setDeviceId(device.getId()).setTenantId(device.getTenantId()); // 特殊:如果设备没有指定 requestId,则使用 messageId if (StrUtil.isEmpty(message.getRequestId())) { message.setRequestId(message.getId()); } - return message; } @Override @@ -120,26 +133,33 @@ public class IotDeviceMessageServiceImpl implements IotDeviceMessageService { replyData = handleUpstreamDeviceMessage0(message, device); } catch (ServiceException ex) { serviceException = ex; - log.warn("[onMessage][message({}) 业务异常]", message, serviceException); + log.warn("[handleUpstreamDeviceMessage][message({}) 业务异常]", message, serviceException); } catch (Exception ex) { - log.error("[onMessage][message({}) 发生异常]", message, ex); + log.error("[handleUpstreamDeviceMessage][message({}) 发生异常]", message, ex); throw ex; } // 2. 记录消息 - createDeviceLog(message); + getSelf().createDeviceLogAsync(message); // 3. 回复消息。前提:非 _reply 消息,并且非禁用回复的消息 if (IotDeviceMessageUtils.isReplyMessage(message) - || IotDeviceMessageMethodEnum.isReplyDisabled(message.getMethod())) { + || IotDeviceMessageMethodEnum.isReplyDisabled(message.getMethod()) + || StrUtil.isEmpty(message.getServerId())) { return; } - sendDeviceMessage(IotDeviceMessage.replyOf(message.getRequestId(), message.getMethod(), replyData, - serviceException != null ? serviceException.getCode() : null, - serviceException != null ? serviceException.getMessage() : null)); + try { + IotDeviceMessage replyMessage = IotDeviceMessage.replyOf(message.getRequestId(), message.getMethod(), replyData, + serviceException != null ? serviceException.getCode() : null, + serviceException != null ? serviceException.getMessage() : null); + sendDeviceMessage(replyMessage, device, message.getServerId()); + } catch (Exception ex) { + log.error("[handleUpstreamDeviceMessage][message({}) 回复消息失败]", message, ex); + } } // TODO @芋艿:可优化:未来逻辑复杂后,可以独立拆除 Processor 处理器 + @SuppressWarnings("SameReturnValue") private Object handleUpstreamDeviceMessage0(IotDeviceMessage message, IotDeviceDO device) { // 设备上线 if (Objects.equal(message.getMethod(), IotDeviceMessageMethodEnum.STATE_ONLINE.getMethod())) { @@ -164,4 +184,8 @@ public class IotDeviceMessageServiceImpl implements IotDeviceMessageService { return null; } + private IotDeviceMessageServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyService.java index c6e3a67067..6f81ec4c9c 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyService.java @@ -55,38 +55,35 @@ public interface IotDevicePropertyService { // ========== 设备时间相关操作 ========== /** - * 获得最后上报时间小于指定时间的设备标识 + * 获得最后上报时间小于指定时间的设备编号集合 * * @param maxReportTime 最大上报时间 - * @return [productKey, deviceName] 列表 + * @return 设备编号集合 */ - Set getProductKeyDeviceNameListByReportTime(LocalDateTime maxReportTime); + Set getDeviceIdListByReportTime(LocalDateTime maxReportTime); /** * 更新设备上报时间 * - * @param productKey 产品标识 - * @param deviceName 设备名称 + * @param id 设备编号 * @param reportTime 上报时间 */ - void updateDeviceReportTime(String productKey, String deviceName, LocalDateTime reportTime); + void updateDeviceReportTimeAsync(Long id, LocalDateTime reportTime); /** - * 更新设备关联的网关 serverId + * 更新设备关联的网关服务 serverId * - * @param productKey 产品标识 - * @param deviceName 设备名称 + * @param id 设备编号 * @param serverId 网关 serverId */ - void updateDeviceServerId(String productKey, String deviceName, String serverId); + void updateDeviceServerIdAsync(Long id, String serverId); /** - * 获得设备关联的网关 serverId + * 获得设备关联的网关服务 serverId * - * @param productKey 产品标识 - * @param deviceName 设备名称 + * @param id 设备编号 * @return 网关 serverId */ - String getDeviceServerId(String productKey, String deviceName); + String getDeviceServerId(Long id); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java index 185251cf08..b15aec82ad 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java @@ -27,6 +27,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.time.LocalDateTime; @@ -183,26 +184,27 @@ public class IotDevicePropertyServiceImpl implements IotDevicePropertyService { // ========== 设备时间相关操作 ========== @Override - public Set getProductKeyDeviceNameListByReportTime(LocalDateTime maxReportTime) { + public Set getDeviceIdListByReportTime(LocalDateTime maxReportTime) { return deviceReportTimeRedisDAO.range(maxReportTime); } @Override - public void updateDeviceReportTime(String productKey, String deviceName, LocalDateTime reportTime) { - deviceReportTimeRedisDAO.update(productKey, deviceName, reportTime); + @Async + public void updateDeviceReportTimeAsync(Long id, LocalDateTime reportTime) { + deviceReportTimeRedisDAO.update(id, reportTime); } @Override - public void updateDeviceServerId(String productKey, String deviceName, String serverId) { + public void updateDeviceServerIdAsync(Long id, String serverId) { if (StrUtil.isEmpty(serverId)) { return; } - deviceServerIdRedisDAO.update(productKey, deviceName, serverId); + deviceServerIdRedisDAO.update(id, serverId); } @Override - public String getDeviceServerId(String productKey, String deviceName) { - return deviceServerIdRedisDAO.get(productKey, deviceName); + public String getDeviceServerId(Long id) { + return deviceServerIdRedisDAO.get(id); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMessageMapper.xml b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMessageMapper.xml index 3fd63e2788..c211964922 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMessageMapper.xml +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceMessageMapper.xml @@ -12,11 +12,13 @@ tenant_id BIGINT, server_id NCHAR(50), upstream BOOL, + reply BOOL, request_id NCHAR(50), method NCHAR(100), params NCHAR(2048), data NCHAR(2048), - code INT + code INT, + msg NCHAR(256) ) TAGS ( device_id BIGINT ) @@ -29,21 +31,22 @@ INSERT INTO device_message_${deviceId} ( ts, id, report_time, tenant_id, server_id, - upstream, request_id, method, params, data, - code + upstream, reply, request_id, method, params, + data, code, msg ) USING device_message TAGS (#{deviceId}) VALUES ( - #{ts}, #{id}, #{reportTime}, #{tenantId}, #{serverId}, - #{upstream}, #{requestId}, #{method}, #{params}, #{data}, - #{code} + NOW, #{id}, #{reportTime}, #{tenantId}, #{serverId}, + #{upstream}, #{reply}, #{requestId}, #{method}, #{params}, + #{data}, #{code}, #{msg} )