Java 后端实战:视频接口在线离线统计功能设计与实现

在视频监控模块中,前端列表页需要展示在线/离线摄像头的全局总数。本文记录了在现有 /api/video/list 接口中添加 onlineCountofflineCount 字段的完整设计与实现过程,包括方案对比、核心代码实现以及开发中遇到的两个典型问题。

🎧 文章导读

🎵 背景音乐

前言

视频监控模块的列表页面有一个常见需求:展示在线和离线摄像头的总数。原有的 /api/video/list 接口只返回过滤后的视频列表,前端无法得知全局的在线/离线视频总数。

这个需求看起来简单,但有一个关键点:统计数据必须基于全量数据,而不是过滤后的子集。也就是说,无论用户当前筛选了什么条件(只看在线视频、按关键字搜索),onlineCountofflineCount 始终反映全局数据。


方案对比

Controller 层 vs Service 层架构对比
图1:两种实现方案的架构对比

在设计阶段,我考虑了两种实现方案:

方案 实现位置 改动范围 优点 缺点
方案A:Controller 层处理 VideoController.java 仅改一个文件 改动最小,逻辑集中 每次请求获取全量数据
方案B:Service 层统计方法 新增 getVideoStats() 改 Service + DTO 职责分离更清晰 改动较大,过度设计

最终选择了方案A,理由是:

  • 视频数据量通常在几百到几千条,全量查询的性能开销可以接受
  • 只改一个文件,逻辑集中在一个方法里,容易理解和维护
  • 方案B 需要修改 Service 层和可能的 DTO,对于这个简单需求来说过度设计

后续优化思路:如果数据量增长导致性能问题,可以在 Service 层加缓存或改用数据库 COUNT 查询。


核心实现

接口设计

接口地址不变,仍然是 GET /api/video/list,返回数据中新增两个字段:

字段 类型 说明
onlineCount long 全量数据中在线视频数量
offlineCount long 全量数据中离线视频数量

关键约束:这两个字段的统计范围是全量数据,不受 isOnlinekeywordpageNumpageSize 参数影响。

实现逻辑

实现分为四步:获取全量数据 → 统计 → 过滤 → 分页返回

核心代码在 VideoController.javagetVideoList 方法中:

Java Stream API 实现在线离线统计
图2:使用 Stream API 统计在线/离线数量

1
2
3
4
5
6
7
8
9
10
11
// 1. 获取全量数据用于统计在线/离线数量
VideoListDTO allDataResult = videoService.getVideoList(null);
List<VideoListDTO.VideoInfo> allVideoList = allDataResult != null && allDataResult.getData() != null
? allDataResult.getData()
: Collections.emptyList();

// 2. 统计全量数据的在线/离线数量(status == 1 为在线)
long onlineCount = allVideoList.stream()
.filter(v -> v.getStatus() != null && v.getStatus() == 1)
.count();
long offlineCount = allVideoList.size() - onlineCount;

videoService.getVideoList(null)null 表示不按在线状态过滤,获取全部数据。然后通过 Java Stream 统计 status == 1 的数量作为在线数,总数减去在线数即为离线数。

接下来按参数过滤、分页,最后在返回结果中带上统计字段:

1
2
3
4
5
6
return AjaxResult.success("获取视频列表成功", pagedList)
.put("total", total)
.put("pageNum", normalizedPageNum)
.put("pageSize", normalizedPageSize)
.put("onlineCount", onlineCount)
.put("offlineCount", offlineCount);

注意区分total 是过滤后的总数,onlineCount/offlineCount 是全量统计,两者含义不同。


测试验证

可以通过以下场景验证功能正确性:

场景 请求 预期结果
无参数调用 GET /api/video/list onlineCount + offlineCount 等于列表长度
只看在线 GET /api/video/list?isOnline=1 data 只包含在线视频,统计字段不受影响
关键字搜索 GET /api/video/list?keyword=xxx data 是搜索结果,统计字段不受影响
分页 GET /api/video/list?pageNum=1&pageSize=5 data 最多 5 条,统计字段不受影响

踩坑记录

坑1:错误创建 Mapper XML 导致启动失败

在之前的开发中,我凭猜测创建了 StReachInfraMapper.xml 文件(以为缺少 SQL 映射),结果 Spring Boot 启动时报错:

1
IOException: Failed to parse mapping resource

删除该文件后恢复正常。

经验教训:在不确定是否真正缺少某个文件时,应该先验证接口是否能正常工作,而不是凭猜测创建文件。先跑通再补全,比先补全再排查要高效得多。

坑2:PUT 请求 405 错误

调用 PUT /basic/station/archive/reachInfra 时报错 不支持'PUT'请求

排查后发现原因是调用方漏掉了路径参数 stcd,正确的路径应该是:

1
PUT /basic/station/archive/reachInfra/{stcd}

经验教训:遇到 405 错误,除了检查 HTTP 方法是否正确,还要检查 URL 路径是否完整,特别是路径参数。


总结

这个改动的核心设计决策是**”统计全量、过滤返回”**——onlineCountofflineCount 始终反映全局数据,不受任何筛选条件影响。

从实现来看,方案A 确实是最小改动方案,只改了 VideoController.java 一个文件。如果后续性能成为瓶颈,可以考虑在 Service 层添加专门的统计方法或缓存。

相关文件

文件 说明
cnsci-admin/.../video/VideoController.java 接口层,主要改动文件
cnsci-admin/.../dto/video/VideoListDTO.java 视频列表 DTO,未改动