浏览代码

完善监控功能

11868 1 周之前
父节点
当前提交
c1ac978fee

+ 50 - 49
supervision-admin/src/main/java/com/supervision/web/videoManage/controller/VideoController.java

@@ -12,6 +12,9 @@ import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -37,10 +40,14 @@ import java.util.Map;
 @Slf4j
 public class VideoController {
 
+    private static final Logger logger = LoggerFactory.getLogger(VideoController.class);
+
+    @Autowired
     private VideoService videoService;
 
-//    @Autowired
-//    private TaskServiceV2 taskServiceV2;
+
+    // FFmpegManager 作为单例
+    private final FFmpegManager ffmpegManager;
 
     /** Windows系统* */
     private static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().contains("win");
@@ -85,6 +92,7 @@ public class VideoController {
 //        }
 //        return ResponseResult.success(videoVo);
 //    }
+
     /** 关闭ffmpeg.exe程序 */
     @GetMapping("/videoClose")
     public ResponseResult<Void> close() {
@@ -131,13 +139,12 @@ public class VideoController {
 
     @ApiOperation("分页查询视频列表(支持视频名称模糊查询)")
     @PostMapping("/list")
-    public Map<String, Object> listAllPaged(@RequestBody Map<String, Object> params) {
+    public Map<String, Object> listVideos(@RequestBody Map<String, Object> params) {
         int page = (int) params.getOrDefault("page", 1);
         int size = (int) params.getOrDefault("size", 10);
-        String name = (String) params.getOrDefault("name", ""); // 视频名称模糊查询
+        String name = (String) params.getOrDefault("name", "");
 
         List<Video> list = videoService.listAllPaged(page, size, name);
-
         PageInfo<Video> pageInfo = new PageInfo<>(list);
 
         Map<String, Object> result = new HashMap<>();
@@ -146,68 +153,61 @@ public class VideoController {
         return result;
     }
 
-    @ApiOperation("分页查询视频列表(支持视频名称模糊查询)")
-    @PostMapping("/listVideo")
-    public Map<String, Object> listVideoAllPaged(@RequestBody Map<String, Object> params) {
-        int page = (int) params.getOrDefault("page", 1);
-        int size = (int) params.getOrDefault("size", 10);
-        String name = (String) params.getOrDefault("name", ""); // 视频名称模糊查询
-
-        List<Video> list = videoService.listVideoAllPaged(page, size, name);
+    @ApiOperation("播放视频,点击时才推流")
+    @GetMapping("/play/{id}")
+    public ResponseResult<String> playVideo(@PathVariable Long id) {
+        Video video = videoService.getById(id);
+        if (video == null) {
+            return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
+        }
 
-        PageInfo<Video> pageInfo = new PageInfo<>(list);
+        String cameraId = video.getId() + "_" + video.getChannel();
+        try {
+            ffmpegManager.ensureStream(cameraId, video.getRtspUrl());
+        } catch (Exception e) {
+            log.error("FFmpeg生成流失败: {}-{}", video.getId(), video.getChannel(), e);
+            return ResponseResult.error(ErrorCodeEnum.FFMPEG_GENERATE_STREAM_FAILED);
+        }
 
-        Map<String, Object> result = new HashMap<>();
-        result.put("total", pageInfo.getTotal());
-        result.put("list", list);
-        return result;
+        return ResponseResult.success(ffmpegManager.getPlayUrl(cameraId));
     }
 
-    /**
-     * 根据ID查询单个视频
-     * @param id 视频ID
-     * @return 视频对象
-     */
     @ApiOperation("根据ID查询视频")
     @GetMapping("/{id}")
-    public Video getById(@PathVariable Long id) {
-        return videoService.getById(id);
+    public ResponseResult<Video> getById(@PathVariable Long id) {
+        Video video = videoService.getById(id);
+        if (video == null) {
+            return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
+        }
+        return ResponseResult.success(video);
     }
 
-    /**
-     * 新增视频
-     * @param video 视频对象
-     * @return 操作结果
-     */
     @ApiOperation("新增视频")
-    @PostMapping
-    public String add(@RequestBody Video video) {
+    @PostMapping("/add")
+    public ResponseResult<String> add(@RequestBody Video video) {
         videoService.add(video);
-        return "新增成功";
+        return ResponseResult.success("新增成功");
     }
 
-    /**
-     * 更新视频
-     * @param video 视频对象
-     * @return 操作结果
-     */
     @ApiOperation("更新视频")
-    @PutMapping
-    public String update(@RequestBody Video video) {
+    @PutMapping("/update")
+    public ResponseResult<String> update(@RequestBody Video video) {
         videoService.update(video);
-        return "更新成功";
+        return ResponseResult.success("更新成功");
     }
 
-    /**
-     * 删除视频
-     * @param id 视频ID
-     * @return 操作结果
-     */
     @ApiOperation("删除视频")
-    @DeleteMapping("/{id}")
-    public String delete(@PathVariable Long id) {
+    @DeleteMapping("/delete/{id}")
+    public ResponseResult<String> delete(@PathVariable Long id) {
         videoService.delete(id);
-        return "删除成功";
+        return ResponseResult.success("删除成功");
+    }
+
+    @ApiOperation("删除本地TS缓存文件")
+    @GetMapping("/deleteTs")
+    public ResponseResult<Void> deleteTsFiles() {
+        videoService.deleteTsFile();
+        return ResponseResult.success();
     }
 
     /**
@@ -253,6 +253,7 @@ public class VideoController {
             }
         }
     }
+
     public void closeHistoryProgram(String processName) {
         String cmd = "taskkill /f /t /im " + processName;
 //        try {

+ 36 - 10
supervision-admin/src/main/java/com/supervision/web/videoManage/domain/Video.java

@@ -3,6 +3,8 @@ package com.supervision.web.videoManage.domain;
 
 import lombok.Data;
 
+import java.time.LocalDateTime;
+
 /**
  * 视频信息实体类,对应数据库表 video
  * 用于存储视频的基本连接与账户信息
@@ -13,20 +15,17 @@ public class Video {
     /** 主键ID */
     private Long id;
 
-    /** 视频流访问URL */
-    private String url;       // 原始 RTSP 地址
-
-    // transient 表示不映射到数据库字段
-    private transient String playUrl;   // m3u8 播放地址
-
-    /** 视频名称 */
+    /** 视频名称 / 前端显示名称 */
     private String name;
 
+    /** 视频设备类型:IPC、MINMOE、LPR_GATE、TURNSTILE */
+    private String deviceType;
+
     /** 视频设备IP地址 */
     private String ip;
 
-    /** 设备端口号 */
-    private String port;
+    /** 视频设备端口号 */
+    private Integer port;
 
     /** 登录用户名 */
     private String username;
@@ -34,7 +33,34 @@ public class Video {
     /** 登录密码 */
     private String password;
 
-    /** 视频通道名称 */
+    /** 视频通道号 */
+    private Integer channel;
+
+    /** 视频通道名称,可用于标识前/后摄像头 */
     private String channelName;
 
+    /** 视频流 RTSP 地址 */
+    private String rtspUrl;
+
+    /** 前端播放地址(WebRTC/HLS),不存数据库 */
+    private transient String playUrl;
+
+    /** 取流方式:RTSP / SDK / ISAPI */
+    private String previewType;
+
+    /** 流标识,用于媒体服务器 */
+    private String streamKey;
+
+    /** 所属主设备ID(门禁前后摄像头关联) */
+    private Long parentDeviceId;
+
+    /** 是否启用:1=启用,0=禁用 */
+    private Boolean enable;
+
+    /** 创建时间 */
+    private LocalDateTime createTime;
+
+    /** 更新时间 */
+    private LocalDateTime updateTime;
+
 }

+ 5 - 4
supervision-admin/src/main/java/com/supervision/web/videoManage/mapper/VideoMapper.java

@@ -17,14 +17,16 @@ public interface VideoMapper {
      * 查询所有视频信息
      * @return 视频列表
      */
-    List<Video> selectAll();
+    List<Video> searchAll();
 
     /**
      * 根据ID查询视频信息
      * @param id 视频ID
      * @return 视频对象
      */
-    Video selectById(Long id);
+    Video searchById(Long id);
+
+    List<Video> searchByName(String name);
 
     /**
      * 新增视频记录
@@ -47,6 +49,5 @@ public interface VideoMapper {
      */
     int deleteById(Long id);
 
-    List<Video> selectByNameLike(String name);
-
+    List<Video> searchByParentDeviceId(Long parentDeviceId);
 }

+ 41 - 19
supervision-admin/src/main/java/com/supervision/web/videoManage/mapper/VideoMapper.xml

@@ -7,52 +7,74 @@
     <!-- 结果映射,将数据库字段映射到实体属性 -->
     <resultMap id="VideoResultMap" type="com.supervision.web.videoManage.domain.Video">
         <id property="id" column="id"/>
-        <result property="url" column="url"/>
         <result property="name" column="name"/>
+        <result property="deviceType" column="device_type"/>
         <result property="ip" column="ip"/>
         <result property="port" column="port"/>
         <result property="username" column="username"/>
         <result property="password" column="password"/>
+        <result property="channel" column="channel"/>
         <result property="channelName" column="channel_name"/>
+        <result property="rtspUrl" column="rtsp_url"/>
+        <result property="previewType" column="preview_type"/>
+        <result property="streamKey" column="stream_key"/>
+        <result property="parentDeviceId" column="parent_device_id"/>
+        <result property="enable" column="enable"/>
+        <result property="createTime" column="create_time"/>
+        <result property="updateTime" column="update_time"/>
     </resultMap>
 
-    <!-- 查询所有视频 -->
-    <select id="selectAll" resultMap="VideoResultMap">
-        SELECT * FROM new_video
+    <!-- 查询所有视频设备 -->
+    <select id="searchAll" resultMap="VideoResultMap">
+        SELECT * FROM new_video_info
     </select>
 
     <!-- 根据视频名称模糊查询 -->
-    <select id="selectByNameLike" parameterType="String" resultMap="VideoResultMap">
-        SELECT * FROM new_video
+    <select id="searchByName" parameterType="String" resultMap="VideoResultMap">
+        SELECT * FROM new_video_info
         WHERE name LIKE CONCAT('%', #{name}, '%')
     </select>
 
-    <!-- 根据ID查询视频 -->
-    <select id="selectById" parameterType="long" resultMap="VideoResultMap">
-        SELECT * FROM new_video WHERE id = #{id}
+    <!-- 根据ID查询视频设备 -->
+    <select id="searchById" parameterType="long" resultMap="VideoResultMap">
+        SELECT * FROM new_video_info WHERE id = #{id}
     </select>
 
-    <!-- 新增视频 -->
+    <!-- 新增视频设备 -->
     <insert id="insert" parameterType="com.supervision.web.videoManage.domain.Video" useGeneratedKeys="true" keyProperty="id">
-        INSERT INTO new_video (url, name, ip, port, username, password, channel_name)
-        VALUES (#{url}, #{name}, #{ip}, #{port}, #{username}, #{password}, #{channelName})
+        INSERT INTO new_video_info
+        (name, device_type, ip, port, username, password, channel, channel_name, rtsp_url, preview_type, stream_key, parent_device_id, enable)
+        VALUES
+            (#{name}, #{deviceType}, #{ip}, #{port}, #{username}, #{password}, #{channel}, #{channelName}, #{rtspUrl}, #{previewType}, #{streamKey}, #{parentDeviceId}, #{enable})
     </insert>
 
-    <!-- 更新视频信息 -->
+    <!-- 更新视频设备信息 -->
     <update id="update" parameterType="com.supervision.web.videoManage.domain.Video">
-        UPDATE new_video
-        SET url = #{url},
-            name = #{name},
+        UPDATE new_video_info
+        SET name = #{name},
+            device_type = #{deviceType},
             ip = #{ip},
             port = #{port},
             username = #{username},
             password = #{password},
-            channel_name = #{channelName}
+            channel = #{channel},
+            channel_name = #{channelName},
+            rtsp_url = #{rtspUrl},
+            preview_type = #{previewType},
+            stream_key = #{streamKey},
+            parent_device_id = #{parentDeviceId},
+            enable = #{enable}
         WHERE id = #{id}
     </update>
 
-    <!-- 根据ID删除视频 -->
+    <!-- 根据ID删除视频设备 -->
     <delete id="deleteById" parameterType="long">
-        DELETE FROM new_video WHERE id = #{id}
+        DELETE FROM new_video_info WHERE id = #{id}
     </delete>
+
+    <!-- 根据 parentDeviceId 查询门禁/多通道视频 -->
+    <select id="searchByParentDeviceId" parameterType="long" resultMap="VideoResultMap">
+        SELECT * FROM new_video_info WHERE parent_device_id = #{parentDeviceId} AND enable = 1
+    </select>
+
 </mapper>

+ 2 - 0
supervision-admin/src/main/java/com/supervision/web/videoManage/other/ErrorCodeEnum.java

@@ -18,6 +18,8 @@ public enum ErrorCodeEnum {
      */
     UNHANDLED_EXCEPTION("未处理的异常!"),
 
+    FFMPEG_GENERATE_STREAM_FAILED ("FFmpeg生成流失败"),
+
     ARGUMENT_NULL_EXIST("数据验证失败,接口调用参数存在空值,请核对!"),
     ARGUMENT_PK_ID_NULL("数据验证失败,接口调用主键Id参数为空,请核对!"),
     INVALID_ARGUMENT_FORMAT("数据验证失败,不合法的参数格式,请核对!"),

+ 4 - 1
supervision-admin/src/main/java/com/supervision/web/videoManage/service/VideoService.java

@@ -18,7 +18,7 @@ public interface VideoService {
      */
     List<Video> listAll();
 
-    List<Video> listAllPaged(int pageNum, int pageSize, String videoName);
+    List<Video> listAllPaged(int pageNum, int pageSize, String name);
 
     List<Video> listVideoAllPaged(int pageNum, int pageSize, String name);
 
@@ -50,10 +50,13 @@ public interface VideoService {
      */
     int delete(Long id);
 
+    List<Video> listByParentDeviceId(Long parentDeviceId);
+
     List<VideoVo> getSubjectVideo(String subjectName);
 
     List<VideoVo> getSystemVideo(String systemId);
 
     Boolean deleteTsFile();
+
 }
 

+ 25 - 46
supervision-admin/src/main/java/com/supervision/web/videoManage/service/VideoServiceImpl.java

@@ -51,7 +51,7 @@ public class VideoServiceImpl implements VideoService {
     /** 查询所有视频 */
     @Override
     public List<Video> listAll() {
-        return videoMapper.selectAll();
+        return videoMapper.searchAll();
     }
 
     /**
@@ -63,11 +63,8 @@ public class VideoServiceImpl implements VideoService {
      */
     @Override
     public List<Video> listAllPaged(int pageNum, int pageSize, String name) {
-        // 启用分页
         PageHelper.startPage(pageNum, pageSize);
-        // 模糊查询数据库
-        List<Video> list = videoMapper.selectByNameLike(name);
-        return list;
+        return videoMapper.searchByName(name);
     }
 
     /**
@@ -79,55 +76,40 @@ public class VideoServiceImpl implements VideoService {
      */
     @Override
     public List<Video> listVideoAllPaged(int pageNum, int pageSize, String name) {
-        // 启用分页
         PageHelper.startPage(pageNum, pageSize);
-
-        // 模糊查询数据库
-        List<Video> list = videoMapper.selectByNameLike(name);
-
-        // 异步生成 m3u8 地址
-        for (Video video : list) {
-            String cameraId = String.valueOf(video.getId());
-            String playUrl = ffmpegManager.getPlayUrl(cameraId);  // 获取 m3u8 播放地址
-            video.setPlayUrl(playUrl);
-
-            String rtspUrl = video.getUrl();
-            CompletableFuture.runAsync(() -> {
-                try {
-                    ffmpegManager.ensureStream(cameraId, rtspUrl);  // 异步生成 m3u8 文件
-                } catch (Exception e) {
-                    log.error("FFmpeg 生成流失败: {}", cameraId, e);
-                }
-            });
-        }
-
-        return list;
+        return videoMapper.searchByName(name);
     }
 
-    /** 根据ID查询视频 */
+    /** 根据ID查询视频设备 */
     @Override
     public Video getById(Long id) {
-        return videoMapper.selectById(id);
+        return videoMapper.searchById(id);
     }
 
-    /** 新增视频 */
+    /** 新增视频设备 */
     @Override
     public int add(Video video) {
         return videoMapper.insert(video);
     }
 
-    /** 更新视频 */
+    /** 更新视频设备 */
     @Override
     public int update(Video video) {
         return videoMapper.update(video);
     }
 
-    /** 删除视频 */
+    /** 删除视频设备 */
     @Override
     public int delete(Long id) {
         return videoMapper.deleteById(id);
     }
 
+    /** 按 parentDeviceId 查询门禁/多通道视频 */
+    @Override
+    public List<Video> listByParentDeviceId(Long parentDeviceId) {
+        return videoMapper.searchByParentDeviceId(parentDeviceId);
+    }
+
     @Override
     public List<VideoVo> getSubjectVideo(String subjectName) {
 //        List<Map<String,String>> urlAndNameList = videoMapper.getSubjectVideoUrl(subjectName);
@@ -173,28 +155,25 @@ public class VideoServiceImpl implements VideoService {
         return new ArrayList<>();
     }
 
+    /** 删除本地 ts 文件缓存 */
     @Override
     public Boolean deleteTsFile() {
-        File file = new File(videoFilePath);
-        String[] fileList = file.list();
+        File dir = new File(videoFilePath);
         boolean res = true;
-        if (fileList != null) {
-            for (String s : fileList) {
-                File delfile = new File(videoFilePath + s);
-                if (!delfile.isDirectory()) {
-                    if (delfile.getName().endsWith("ts")) {
-                        boolean delete = delfile.delete();
-                        if (delete) {
-                            log.info("删除文件{}成功", delfile.getAbsolutePath());
-                        } else {
-                            log.warn("删除文件{}失败", delfile.getAbsolutePath());
-                            res = false;
-                        }
+        if (dir.exists() && dir.isDirectory()) {
+            for (File f : Objects.requireNonNull(dir.listFiles())) {
+                if (f.isFile() && f.getName().endsWith(".ts")) {
+                    if (f.delete()) {
+                        log.info("删除文件{}成功", f.getAbsolutePath());
+                    } else {
+                        log.warn("删除文件{}失败", f.getAbsolutePath());
+                        res = false;
                     }
                 }
             }
         }
         return res;
     }
+
 }