功能:边缘设备心跳 HTTP 端点 + stream_count/config_version 字段
- 新增 POST /api/ai/device/heartbeat 端点,接收边缘端心跳上报 - 心跳端点加入安全白名单(无需认证) - AiEdgeDevice 新增 streamCount、configVersion 字段 - Mapper INSERT/UPDATE 同步新增字段 - Service 从心跳 payload 提取并保存新字段 - 数据库升级 SQL 添加 stream_count、config_version 列 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,12 @@ public class AiEdgeDevice {
|
||||
@Schema(description = "流统计信息JSON")
|
||||
private String streamStats;
|
||||
|
||||
@Schema(description = "活跃视频流数量")
|
||||
private Integer streamCount;
|
||||
|
||||
@Schema(description = "当前配置版本")
|
||||
private String configVersion;
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
private String updatedAt;
|
||||
}
|
||||
|
||||
@@ -56,4 +56,21 @@ public class AiEdgeDeviceController {
|
||||
public WVPResult<Map<String, Object>> statistics() {
|
||||
return WVPResult.success(edgeDeviceService.getStatistics());
|
||||
}
|
||||
|
||||
@Operation(summary = "边缘设备心跳上报")
|
||||
@PostMapping("/heartbeat")
|
||||
public WVPResult<String> heartbeat(@RequestBody String payload) {
|
||||
try {
|
||||
com.alibaba.fastjson2.JSONObject json = com.alibaba.fastjson2.JSON.parseObject(payload);
|
||||
String deviceId = json.getString("device_id");
|
||||
if (deviceId == null || deviceId.isEmpty()) {
|
||||
return WVPResult.fail(400, "device_id 不能为空");
|
||||
}
|
||||
edgeDeviceService.saveOrUpdateHeartbeat(deviceId, payload);
|
||||
return WVPResult.success("ok");
|
||||
} catch (Exception e) {
|
||||
log.error("[AiEdgeDevice] 心跳上报处理失败", e);
|
||||
return WVPResult.fail(500, "心跳处理失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,15 +9,16 @@ import java.util.List;
|
||||
public interface AiEdgeDeviceMapper {
|
||||
|
||||
@Insert("INSERT INTO wvp_ai_edge_device (device_id, status, last_heartbeat, uptime_seconds, " +
|
||||
"frames_processed, alerts_generated, stream_stats, updated_at) " +
|
||||
"frames_processed, alerts_generated, stream_stats, stream_count, config_version, updated_at) " +
|
||||
"VALUES (#{deviceId}, #{status}, #{lastHeartbeat}, #{uptimeSeconds}, " +
|
||||
"#{framesProcessed}, #{alertsGenerated}, #{streamStats}, #{updatedAt})")
|
||||
"#{framesProcessed}, #{alertsGenerated}, #{streamStats}, #{streamCount}, #{configVersion}, #{updatedAt})")
|
||||
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
|
||||
int add(AiEdgeDevice device);
|
||||
|
||||
@Update("UPDATE wvp_ai_edge_device SET status=#{status}, last_heartbeat=#{lastHeartbeat}, " +
|
||||
"uptime_seconds=#{uptimeSeconds}, frames_processed=#{framesProcessed}, " +
|
||||
"alerts_generated=#{alertsGenerated}, stream_stats=#{streamStats}, " +
|
||||
"stream_count=#{streamCount}, config_version=#{configVersion}, " +
|
||||
"updated_at=#{updatedAt} WHERE device_id=#{deviceId}")
|
||||
int updateByDeviceId(AiEdgeDevice device);
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@ public class AiEdgeDeviceServiceImpl implements IAiEdgeDeviceService {
|
||||
device.setAlertsGenerated(status != null ? status.getLong("alerts_generated") : null);
|
||||
device.setStreamStats(status != null && status.containsKey("stream_stats") ?
|
||||
status.getJSONObject("stream_stats").toJSONString() : null);
|
||||
device.setStreamCount(status != null ? status.getInteger("stream_count") : null);
|
||||
device.setConfigVersion(status != null ? status.getString("config_version") : null);
|
||||
device.setUpdatedAt(now);
|
||||
deviceMapper.add(device);
|
||||
log.info("[AiEdgeDevice] 新设备上线: deviceId={}", deviceId);
|
||||
@@ -57,6 +59,8 @@ public class AiEdgeDeviceServiceImpl implements IAiEdgeDeviceService {
|
||||
device.setAlertsGenerated(status != null ? status.getLong("alerts_generated") : null);
|
||||
device.setStreamStats(status != null && status.containsKey("stream_stats") ?
|
||||
status.getJSONObject("stream_stats").toJSONString() : null);
|
||||
device.setStreamCount(status != null ? status.getInteger("stream_count") : null);
|
||||
device.setConfigVersion(status != null ? status.getString("config_version") : null);
|
||||
device.setUpdatedAt(now);
|
||||
deviceMapper.updateByDeviceId(device);
|
||||
log.debug("[AiEdgeDevice] 心跳更新: deviceId={}", deviceId);
|
||||
|
||||
@@ -108,6 +108,7 @@ public class WebSecurityConfig {
|
||||
defaultExcludes.add("/api/ai/alert/edge/**");
|
||||
defaultExcludes.add("/api/ai/alert/image");
|
||||
defaultExcludes.add("/api/ai/device/edge/**");
|
||||
defaultExcludes.add("/api/ai/device/heartbeat");
|
||||
|
||||
if (userSetting.getInterfaceAuthentication() && !userSetting.getInterfaceAuthenticationExcludes().isEmpty()) {
|
||||
defaultExcludes.addAll(userSetting.getInterfaceAuthenticationExcludes());
|
||||
|
||||
@@ -53,10 +53,16 @@ CREATE TABLE IF NOT EXISTS wvp_ai_edge_device (
|
||||
frames_processed BIGINT NULL COMMENT '已处理帧数',
|
||||
alerts_generated BIGINT NULL COMMENT '已生成告警数',
|
||||
stream_stats TEXT NULL COMMENT 'JSON流统计',
|
||||
stream_count INT NULL COMMENT '活跃视频流数量',
|
||||
config_version VARCHAR(64) NULL COMMENT '当前配置版本',
|
||||
updated_at VARCHAR(50) NULL COMMENT '更新时间',
|
||||
UNIQUE KEY uk_device_id (device_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='边缘设备状态';
|
||||
|
||||
-- 升级:wvp_ai_edge_device 新增字段(已有表执行)
|
||||
ALTER TABLE wvp_ai_edge_device ADD COLUMN IF NOT EXISTS stream_count INT NULL COMMENT '活跃视频流数量' AFTER stream_stats;
|
||||
ALTER TABLE wvp_ai_edge_device ADD COLUMN IF NOT EXISTS config_version VARCHAR(64) NULL COMMENT '当前配置版本' AFTER stream_count;
|
||||
|
||||
-- 4. 算法参数模板表
|
||||
CREATE TABLE IF NOT EXISTS wvp_ai_algo_template (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
|
||||
Reference in New Issue
Block a user