Browse Source

fix:保存预置位缺少 NVR IP 时按 cameraCode 反查所属 NVR

master
WangGuangYuan 2 weeks ago
parent
commit
647d19ab53
2 changed files with 91 additions and 14 deletions
  1. +26
    -6
      src/main/java/com/inspect/nvr/hik/controller/HikNvrUiActionController.java
  2. +65
    -8
      src/main/java/com/inspect/nvr/hik/service/HikNvrCameraTargetService.java

+ 26
- 6
src/main/java/com/inspect/nvr/hik/controller/HikNvrUiActionController.java View File

@ -2,12 +2,14 @@ package com.inspect.nvr.hik.controller;
import com.inspect.nvr.dahua.DahuaIvsVendorService; import com.inspect.nvr.dahua.DahuaIvsVendorService;
import com.inspect.nvr.domain.Infrared.NvrInfo; import com.inspect.nvr.domain.Infrared.NvrInfo;
import com.inspect.nvr.hik.domain.HikNvrCameraTarget;
import com.inspect.nvr.hik.domain.HikNvrLiveStreamResponse; import com.inspect.nvr.hik.domain.HikNvrLiveStreamResponse;
import com.inspect.nvr.hik.domain.HikNvrPlaybackErrorResponse; import com.inspect.nvr.hik.domain.HikNvrPlaybackErrorResponse;
import com.inspect.nvr.hik.domain.HikNvrPresetListResponse; import com.inspect.nvr.hik.domain.HikNvrPresetListResponse;
import com.inspect.nvr.hik.domain.HikNvrUiActionRequest; import com.inspect.nvr.hik.domain.HikNvrUiActionRequest;
import com.inspect.nvr.hik.domain.HikNvrUiActionResponse; import com.inspect.nvr.hik.domain.HikNvrUiActionResponse;
import com.inspect.nvr.hik.exception.HikNvrPlaybackException; import com.inspect.nvr.hik.exception.HikNvrPlaybackException;
import com.inspect.nvr.hik.service.HikNvrCameraTargetService;
import com.inspect.nvr.hik.service.HikNvrCredentialService; import com.inspect.nvr.hik.service.HikNvrCredentialService;
import com.inspect.nvr.hik.service.HikNvrLivePublicBaseUrlResolver; import com.inspect.nvr.hik.service.HikNvrLivePublicBaseUrlResolver;
import com.inspect.nvr.hik.service.HikNvrLiveStreamService; import com.inspect.nvr.hik.service.HikNvrLiveStreamService;
@ -45,6 +47,9 @@ public class HikNvrUiActionController {
/** 按页面选择的 NVR IP 从数据库读取服务端凭据。 */ /** 按页面选择的 NVR IP 从数据库读取服务端凭据。 */
@Resource @Resource
private HikNvrCredentialService credentialService; private HikNvrCredentialService credentialService;
/** 按 IVS 完整 cameraCode 反查所属 NVR 与通道,供汇聚页面使用。 */
@Resource
private HikNvrCameraTargetService cameraTargetService;
/** 大华工作台预置位保存能力。 */ /** 大华工作台预置位保存能力。 */
@Resource @Resource
private DahuaIvsVendorService dahuaVendorService; private DahuaIvsVendorService dahuaVendorService;
@ -182,7 +187,10 @@ public class HikNvrUiActionController {
/** /**
* 为页面请求绑定数据库中已启用的目标 NVR。 * 为页面请求绑定数据库中已启用的目标 NVR。
* *
* @param request 页面操作请求,必须包含所选 NVR IP
* <p>页面显式提交 NVR IP 时按 IP 精确绑定;汇聚预览页只提交 cameraCode,
* 此时按 ivs_camera 与基于台账反查摄像机所属 NVR,禁止回退到默认设备。</p>
*
* @param request 页面操作请求,必须包含 NVR IP 或 cameraCode
* @return 绑定数据库目标 NVR 的海康操作服务 * @return 绑定数据库目标 NVR 的海康操作服务
*/ */
private HikNvrUiActionService actionServiceFor(HikNvrUiActionRequest request) { private HikNvrUiActionService actionServiceFor(HikNvrUiActionRequest request) {
@ -191,12 +199,24 @@ public class HikNvrUiActionController {
/** 按页面请求读取并校验数据库中的目标 NVR。 */ /** 按页面请求读取并校验数据库中的目标 NVR。 */
private NvrInfo nvrInfoFor(HikNvrUiActionRequest request) { private NvrInfo nvrInfoFor(HikNvrUiActionRequest request) {
// 多 NVR 环境必须明确目标 IP,禁止按固定配置或隐式默认设备执行控制。
if (request == null || !hasText(request.getNvrIp())) {
throw HikNvrPlaybackException.badRequest("NVR IP不能为空");
// 页面显式选择 NVR 时以页面选择为准,多 NVR 环境不允许隐式换设备。
if (request != null && hasText(request.getNvrIp())) {
return credentialService.resolveByIp(request.getNvrIp().trim());
}
// 汇聚页面不带 NVR IP,只能按摄像机编码确定其唯一所属 NVR。
if (request != null && hasText(request.getCameraCode())) {
HikNvrCameraTarget target = cameraTargetService.resolve(request.getCameraCode());
NvrInfo nvr = target.getNvrInfo();
// 回填解析结果,后续海康与大华分支统一从请求读取 NVR IP。
request.setNvrIp(nvr.getNvrIp());
// 汇聚页面可能未传通道号,按 cameraCode 末尾通道补齐,避免落到默认通道。
if (request.getChannel() == null || request.getChannel() <= 0) {
request.setChannel(target.getChannel());
}
return nvr;
} }
// 只允许绑定数据库中已启用的 NVR,页面无法直接提供账号密码。
return credentialService.resolveByIp(request.getNvrIp().trim());
// 既没有 NVR IP 也没有 cameraCode 时无法安全定位数据库 NVR。
throw HikNvrPlaybackException.badRequest("NVR IP不能为空");
} }
/** 判断数据库厂商字段是否表示大华。 */ /** 判断数据库厂商字段是否表示大华。 */


+ 65
- 8
src/main/java/com/inspect/nvr/hik/service/HikNvrCameraTargetService.java View File

@ -49,6 +49,26 @@ public class HikNvrCameraTargetService {
public HikNvrCameraTarget resolve(String cameraCode) { public HikNvrCameraTarget resolve(String cameraCode) {
// 先校验完整编码结构,确保后续拆分不会把错误输入映射到其他设备。 // 先校验完整编码结构,确保后续拆分不会把错误输入映射到其他设备。
String normalizedCode = normalizeCameraCode(cameraCode); String normalizedCode = normalizeCameraCode(cameraCode);
// 摄像机必须已同步到 ivs_camera,禁止仅凭编码格式访问未同步设备。
requireSyncedCamera(normalizedCode);
// 设备编码最后三位是 IVS 页面逻辑通道号。
int channel = parseChannel(normalizedCode);
// 去掉通道三位后恢复摄像机所属 NVR 的完整 IVS 编码。
String expectedNvrCode = buildExpectedNvrCode(normalizedCode);
// 从现有 NVR 数据表中寻找唯一启用且编码完全匹配的设备。
IvsNvr matchedNvr = findUniqueEnabledNvr(normalizedCode, expectedNvrCode);
// 按匹配出的数据库 IP 读取完整端口和凭据,供海康回放能力在服务端使用。
NvrInfo nvrInfo = resolveNvrCredential(matchedNvr);
// 返回统一目标,调用方不再接受浏览器提交的 NVR IP 或通道号。
return new HikNvrCameraTarget(normalizedCode, channel, nvrInfo);
}
/**
* 校验规范化后的完整编码确实存在于 ivs_camera。
*
* @param normalizedCode 已规范化的完整摄像机编码
*/
private void requireSyncedCamera(String normalizedCode) {
// 必须在 ivs_camera 中精确命中该编码,禁止仅凭编码格式访问未同步设备。 // 必须在 ivs_camera 中精确命中该编码,禁止仅凭编码格式访问未同步设备。
IvsCamera camera = ivsCameraMapper.selectByCode(normalizedCode); IvsCamera camera = ivsCameraMapper.selectByCode(normalizedCode);
// 数据库没有该摄像机时返回明确的资源不存在错误。 // 数据库没有该摄像机时返回明确的资源不存在错误。
@ -56,12 +76,18 @@ public class HikNvrCameraTargetService {
throw HikNvrPlaybackException.notFound( throw HikNvrPlaybackException.notFound(
"ivs_camera中未找到cameraCode:" + normalizedCode); "ivs_camera中未找到cameraCode:" + normalizedCode);
} }
}
// 拆出 # 前设备编码和 # 后域编码,二者共同唯一定位所属 NVR。
/**
* 从完整编码的设备段末尾解析 IVS 页面逻辑通道号。
*
* @param normalizedCode 已规范化的完整摄像机编码
* @return 大于 0 的页面逻辑通道号
*/
private int parseChannel(String normalizedCode) {
// 拆出 # 前设备编码,末尾三位即通道号。
int separator = normalizedCode.indexOf('#'); int separator = normalizedCode.indexOf('#');
String deviceCode = normalizedCode.substring(0, separator); String deviceCode = normalizedCode.substring(0, separator);
String domainCode = normalizedCode.substring(separator + 1);
// 设备编码最后三位是 IVS 页面逻辑通道号。
int channel = Integer.parseInt( int channel = Integer.parseInt(
deviceCode.substring(deviceCode.length() - CHANNEL_CODE_LENGTH)); deviceCode.substring(deviceCode.length() - CHANNEL_CODE_LENGTH));
// 000 不能作为可寻址通道,避免把无效摄像机编码交给海康 SDK。 // 000 不能作为可寻址通道,避免把无效摄像机编码交给海康 SDK。
@ -69,11 +95,35 @@ public class HikNvrCameraTargetService {
throw HikNvrPlaybackException.badRequest( throw HikNvrPlaybackException.badRequest(
"cameraCode未包含有效的三位通道号:" + normalizedCode); "cameraCode未包含有效的三位通道号:" + normalizedCode);
} }
return channel;
}
/**
* 由完整摄像机编码推导所属 NVR 的完整 IVS 编码。
*
* @param normalizedCode 已规范化的完整摄像机编码
* @return 设备编码去掉通道位后拼接域编码得到的 NVR 编码
*/
private String buildExpectedNvrCode(String normalizedCode) {
// 拆出 # 前设备编码和 # 后域编码,二者共同唯一定位所属 NVR。
int separator = normalizedCode.indexOf('#');
String deviceCode = normalizedCode.substring(0, separator);
String domainCode = normalizedCode.substring(separator + 1);
// 去掉通道三位后恢复摄像机所属 NVR 的完整 IVS 编码。 // 去掉通道三位后恢复摄像机所属 NVR 的完整 IVS 编码。
String expectedNvrCode = deviceCode.substring(
return deviceCode.substring(
0, deviceCode.length() - CHANNEL_CODE_LENGTH) 0, deviceCode.length() - CHANNEL_CODE_LENGTH)
+ "#" + domainCode; + "#" + domainCode;
}
/**
* 在启用 NVR 中查找编码与推导结果完全匹配且唯一的设备。
*
* @param normalizedCode 已规范化的完整摄像机编码,用于错误提示
* @param expectedNvrCode 由摄像机编码推导出的 NVR 完整编码
* @return 唯一匹配的启用 NVR 记录
*/
private IvsNvr findUniqueEnabledNvr(
String normalizedCode, String expectedNvrCode) {
// 从现有 NVR 数据表中寻找唯一启用且编码完全匹配的设备。 // 从现有 NVR 数据表中寻找唯一启用且编码完全匹配的设备。
List<IvsNvr> nvrs = ivsNvrMapper.selectAll(); List<IvsNvr> nvrs = ivsNvrMapper.selectAll();
IvsNvr matchedNvr = null; IvsNvr matchedNvr = null;
@ -102,12 +152,19 @@ public class HikNvrCameraTargetService {
throw HikNvrPlaybackException.notFound( throw HikNvrPlaybackException.notFound(
"未找到cameraCode对应的启用NVR:" + normalizedCode); "未找到cameraCode对应的启用NVR:" + normalizedCode);
} }
return matchedNvr;
}
// 按匹配出的数据库 IP 读取完整端口和凭据,供海康回放能力在服务端使用。
NvrInfo nvrInfo = credentialService.resolveByIp(
/**
* 按匹配 NVR 的数据库 IP 读取回放所需的端口与凭据。
*
* @param matchedNvr 已唯一匹配的启用 NVR 记录
* @return 包含端口和凭据的 NVR 连接信息
*/
private NvrInfo resolveNvrCredential(IvsNvr matchedNvr) {
// IP 已在 isEnabledTarget 中确认非空,这里统一去除首尾空白。
return credentialService.resolveByIp(
matchedNvr.getNvrIp().trim()); matchedNvr.getNvrIp().trim());
// 返回统一目标,调用方不再接受浏览器提交的 NVR IP 或通道号。
return new HikNvrCameraTarget(normalizedCode, channel, nvrInfo);
} }
/** /**


Loading…
Cancel
Save