From 0a6931e0935fa748ce07f0390fdfa025ecbb32e2 Mon Sep 17 00:00:00 2001 From: 16337 <1633794139@qq.com> Date: Thu, 5 Feb 2026 13:32:07 +0800 Subject: [PATCH] =?UTF-8?q?feat(aiot):=20AiConfigService=E6=94=AF=E6=8C=81?= =?UTF-8?q?Redis=E9=85=8D=E7=BD=AE=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 pushConfigToRedis 方法 - pushConfig 改为通过 Redis 推送配置 - 支持配置快照生成 Co-Authored-By: Claude Opus 4.5 --- .../vmp/aiot/service/IAiConfigService.java | 6 +- .../service/impl/AiConfigServiceImpl.java | 85 ++++++++++--------- 2 files changed, 49 insertions(+), 42 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/aiot/service/IAiConfigService.java b/src/main/java/com/genersoft/iot/vmp/aiot/service/IAiConfigService.java index 2741aadb2..6cfc47782 100644 --- a/src/main/java/com/genersoft/iot/vmp/aiot/service/IAiConfigService.java +++ b/src/main/java/com/genersoft/iot/vmp/aiot/service/IAiConfigService.java @@ -6,5 +6,9 @@ public interface IAiConfigService { Map exportConfig(String cameraId); - void pushConfig(String cameraId); + /** + * 推送配置到边缘端(Redis写入 + Pub/Sub通知) + * @return 推送结果,含版本号 + */ + Map pushConfig(String cameraId); } diff --git a/src/main/java/com/genersoft/iot/vmp/aiot/service/impl/AiConfigServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/aiot/service/impl/AiConfigServiceImpl.java index c74b90d8e..7f04937bd 100644 --- a/src/main/java/com/genersoft/iot/vmp/aiot/service/impl/AiConfigServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/aiot/service/impl/AiConfigServiceImpl.java @@ -1,21 +1,21 @@ package com.genersoft.iot.vmp.aiot.service.impl; +import com.alibaba.fastjson2.JSON; import com.fasterxml.jackson.databind.ObjectMapper; import com.genersoft.iot.vmp.aiot.bean.AiAlgorithm; +import com.genersoft.iot.vmp.aiot.bean.AiConfigSnapshot; import com.genersoft.iot.vmp.aiot.bean.AiRoi; import com.genersoft.iot.vmp.aiot.bean.AiRoiAlgoBind; -import com.genersoft.iot.vmp.aiot.config.AiMqttConfig; -import com.genersoft.iot.vmp.aiot.config.AiServiceConfig; import com.genersoft.iot.vmp.aiot.dao.AiAlgorithmMapper; import com.genersoft.iot.vmp.aiot.dao.AiRoiAlgoBindMapper; import com.genersoft.iot.vmp.aiot.dao.AiRoiMapper; import com.genersoft.iot.vmp.aiot.service.IAiConfigService; -import com.genersoft.iot.vmp.aiot.service.MqttService; +import com.genersoft.iot.vmp.aiot.service.IAiConfigSnapshotService; +import com.genersoft.iot.vmp.aiot.service.IAiRedisConfigService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.*; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; import java.util.*; @@ -33,13 +33,11 @@ public class AiConfigServiceImpl implements IAiConfigService { private AiAlgorithmMapper algorithmMapper; @Autowired - private AiServiceConfig aiServiceConfig; + private IAiRedisConfigService redisConfigService; + @Lazy @Autowired - private AiMqttConfig mqttConfig; - - @Autowired - private MqttService mqttService; + private IAiConfigSnapshotService snapshotService; private final ObjectMapper objectMapper = new ObjectMapper(); @@ -56,6 +54,7 @@ public class AiConfigServiceImpl implements IAiConfigService { roiMap.put("roi_type", roi.getRoiType()); roiMap.put("name", roi.getName()); roiMap.put("enabled", roi.getEnabled() == 1); + roiMap.put("priority", roi.getPriority()); try { roiMap.put("coordinates", objectMapper.readValue(roi.getCoordinates(), Object.class)); @@ -67,13 +66,23 @@ public class AiConfigServiceImpl implements IAiConfigService { List> algoList = new ArrayList<>(); for (AiRoiAlgoBind bind : binds) { Map algoMap = new LinkedHashMap<>(); + algoMap.put("bind_id", bind.getBindId()); algoMap.put("algo_code", bind.getAlgoCode()); algoMap.put("enabled", bind.getEnabled() == 1); + algoMap.put("priority", bind.getPriority()); + algoMap.put("template_id", bind.getTemplateId()); + algoMap.put("param_override", bind.getParamOverride()); try { algoMap.put("params", objectMapper.readValue(bind.getParams(), Object.class)); } catch (Exception e) { algoMap.put("params", bind.getParams()); } + // 获取算法信息 + AiAlgorithm algo = algorithmMapper.queryByCode(bind.getAlgoCode()); + if (algo != null) { + algoMap.put("algo_name", algo.getAlgoName()); + algoMap.put("target_class", algo.getTargetClass()); + } algoList.add(algoMap); } roiMap.put("algorithms", algoList); @@ -84,38 +93,32 @@ public class AiConfigServiceImpl implements IAiConfigService { } @Override - public void pushConfig(String cameraId) { + public Map pushConfig(String cameraId) { + // 1. 构建完整配置JSON Map config = exportConfig(cameraId); - if (mqttConfig.isEnabled()) { - // MQTT推送优先 - try { - String configJson = objectMapper.writeValueAsString(config); - mqttService.pushConfig(cameraId, configJson); - log.info("MQTT配置推送成功: cameraId={}", cameraId); - } catch (Exception e) { - log.error("MQTT配置推送失败: cameraId={}", cameraId, e); - throw new RuntimeException("MQTT推送失败: " + e.getMessage()); - } - } else if (aiServiceConfig.isEnabled()) { - // HTTP REST推送 - try { - RestTemplate restTemplate = new RestTemplate(); - String url = aiServiceConfig.getUrl() + "/api/config/receive"; - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - HttpEntity> entity = new HttpEntity<>(config, headers); - ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class); - if (!response.getStatusCode().is2xxSuccessful()) { - throw new RuntimeException("推送失败,边缘端返回: " + response.getStatusCode()); - } - log.info("HTTP配置推送成功: cameraId={}", cameraId); - } catch (Exception e) { - log.error("HTTP配置推送失败: cameraId={}", cameraId, e); - throw new RuntimeException("推送失败: " + e.getMessage()); - } - } else { - throw new RuntimeException("AI配置推送未启用,请设置ai.mqtt.enabled=true或ai.service.enabled=true"); - } + // 2. 保存快照到 wvp_ai_config_snapshot (版本化) + AiConfigSnapshot snapshot = snapshotService.createSnapshot( + "CAMERA", cameraId, cameraId, + JSON.toJSONString(config), + "PUSH", "推送配置到边缘端", null); + + // 3. 将每个ROI和Bind写入Redis + redisConfigService.syncCameraConfigToRedis(cameraId); + + // 4. 发布 config_update 到 Redis Pub/Sub 通知边缘端 + List ids = new ArrayList<>(); + ids.add(cameraId); + redisConfigService.publishConfigUpdate("full", ids); + + // 5. 返回推送结果 + Map result = new LinkedHashMap<>(); + result.put("camera_id", cameraId); + result.put("version", snapshot.getVersion()); + result.put("push_status", "success"); + result.put("message", "配置已推送到Redis并通知边缘端"); + + log.info("[AiConfig] 配置推送完成: cameraId={}, version={}", cameraId, snapshot.getVersion()); + return result; } }