liusuyi
2026-01-16 05f799b8a5ce57b1f98dc5f8ab08308c32a6ec63
优化
6 files modified
1 files deleted
1 files renamed
513 ■■■■■ changed files
ard-device/src/main/java/com/ard/device/camera/service/impl/ArdCameraServiceImpl.java 83 ●●●●● patch | view | raw | blame | history
ard-device/src/main/java/com/ard/device/channel/service/impl/ArdChannelServiceImpl.java 113 ●●●●● patch | view | raw | blame | history
ard-quartz/src/main/java/com/ard/quartz/task/DeviceTask.java 258 ●●●●● patch | view | raw | blame | history
ard-vtdu/src/main/java/com/ard/vtdu/service/impl/ArdVtduServiceImpl.java 36 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/service/impl/ArdDroneInfoServiceImpl.java 5 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskPartServiceImpl.java 6 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskServiceImpl.java 4 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/work/service/task/MediaTask.java 8 ●●●●● patch | view | raw | blame | history
ard-device/src/main/java/com/ard/device/camera/service/impl/ArdCameraServiceImpl.java
@@ -373,4 +373,87 @@
        redisService.setCacheObject(getCacheKey(camera.getId()), camera);
    }
    /**
     * 定时执行登录失败相机重新登录
     */
    @Scheduled(cron = "0/10 * * * * ?")
    public void failedReconnect() {
        try {
            log.debug("定时执行失败相机重连任务");
            // 从数据库取全部设备
            ArdCamera ardCamera = new ArdCamera();
            ardCamera.setUseDataScope(false);
            List<ArdCamera> cameraList = this.selectArdCameraList(ardCamera);
            cameraList.stream()
                    // 只处理登录失败或离线的设备
                    .filter(camera -> camera.getLoginId() == null || camera.getLoginId() < 0 || "0".equals(camera.getState()))
                    .forEach(camera -> {
                        log.info("尝试重新登录设备 {}:{}", camera.getIp(), camera.getPort());
                        cameraSDKService.login(camera);
                    });
        } catch (Exception ex) {
            log.error("定时执行失败相机重连任务异常:{}", ex.getMessage());
        }
    }
    /**
     * 同步相机在线状态
     */
    @Scheduled(cron = "0/10 * * * * ?")
    public void syncCameraState() {
        try {
            log.debug("定时执行同步相机在线状态任务");
            //调用查询方法
            ArdCamera ardCamera = new ArdCamera();
            ardCamera.setUseDataScope(false);
            List<ArdCamera> ardCameraList = this.selectArdCameraList(ardCamera);
            ardCameraList
                    .forEach(camera -> {
                        boolean onLineNew = cameraSDKService.isOnLine(camera);
                        boolean onLineOld = "1".equals(camera.getState());
                        if (onLineNew != onLineOld) {
                            if (onLineNew) {
                                camera.setState("1");
                            } else {
                                camera.setState("0");
                            }
                            camera.setUpdateTime(DateUtils.getNowDate());
                            ardCameraMapper.updateArdCamera(camera);
                        }
                    });
        } catch (Exception ex) {
            log.error("同步相机在线状态异常:{}", ex.getMessage());
        }
    }
    /**
     * 同步相机通道
     */
    @Scheduled(cron = "0/10 * * * * ?")
    public void syncChannel() {
        try {
            log.debug("定时执行同步通道任务");
            ArdCamera camera = new ArdCamera();
            camera.setUseDataScope(false);
            List<ArdCamera> ardCameraList = this.selectArdCameraList(camera);
            if (!ardCameraList.isEmpty()) {
                ardCameraList
                        .forEach(ardCamera -> {
                            //SDK获取实际通道
                            List<ArdChannel> ardChannelListSDK = cameraSDKService.getChannels(ardCamera);
                            //数据库获取通道
                            ArdChannel ardChannel = new ArdChannel();
                            ardChannel.setUseDataScope(false);
                            ardChannel.setDeviceId(ardCamera.getId());
                            List<ArdChannel> ardChannelListDb = ardChannelService.selectArdChannelList(ardChannel);
                            //同步通道
                            asyncChannel(ardChannelListDb, ardChannelListSDK);
                        });
            }
        } catch (Exception ex) {
            log.error("定时执行同步通道任务异常:{}", ex.getMessage());
        }
    }
}
ard-device/src/main/java/com/ard/device/channel/service/impl/ArdChannelServiceImpl.java
@@ -33,7 +33,12 @@
    @Resource
    private ArdChannelMapper ardChannelMapper;
    @Resource
    private RedisCache redisCache;
    @Resource
    private IArdVtduService ardVtduService;
    @Resource
    private MediamtxConfig mediamtxConfig;
    /**
     * 查询通道管理
     *
@@ -137,4 +142,110 @@
        }
        return UserConstants.UNIQUE;
    }
    /**
     * 同步通道流媒体
     */
    @Scheduled(cron = "0/10 * * * * ?")
    public void syncVtdu() {
        log.debug("定时同步Vtdu任务");
        try {
            ArdChannel ardChannel = new ArdChannel();
            ardChannel.setUseDataScope(false);
            List<ArdChannel> channels = this.selectArdChannelList(ardChannel);
            if (channels == null || channels.isEmpty()) {
                // log.warn("没有获取到通道数据,退出同步");
                return;
            }
            List<ArdVtdu> ardVtduList = ardVtduService.selectArdVtduList(new ArdVtdu());
            Set<String> validNames = channels.stream()
                    .map(channel -> channel.getDeviceId() + "_" + channel.getChanNo())
                    .collect(Collectors.toSet());
            // 2. 合并操作:增、删、改
            channels.forEach(channel -> {
                String name = channel.getDeviceId() + "_" + channel.getChanNo();  // 生成媒体表的 name
                String cameraId = channel.getDeviceId();  // cameraId 就是通道的 deviceId
                String rtspSourceUrl = getRtspSource(channel);
                String rtspUrl =
                        "rtsp://" + mediamtxConfig.getPlayHost() + ":" + mediamtxConfig.getRtspPort() + "/" + name;  //
                // 拼接 webrtcUrl
                String rtmpUrl =
                        "rtmp://" + mediamtxConfig.getPlayHost() + ":" + mediamtxConfig.getRtmpPort() + "/" + name;  // 拼接
                // webrtcUrl
                String protocol = mediamtxConfig.isHttps() ? "https://" : "http://";
                String webrtcUrl =
                        protocol + mediamtxConfig.getPlayHost() + ":" + mediamtxConfig.getWebrtcPort() + "/" + name;
                // 拼接 webrtcUrl
                // 先检查媒体表是否已有此记录
                Optional<ArdVtdu> existingMedia = ardVtduList.stream()
                        .filter(media -> media.getName().equals(name))  // 查找是否已有对应的媒体记录
                        .findFirst();
                if (existingMedia.isPresent()) {
                    // 如果已有,更新现有记录
                    ArdVtdu vtdu = existingMedia.get();
                    // 更新前后内容相同则不进行更新
                    if (!vtdu.getRtspSource().equals(rtspSourceUrl) ||
                            !vtdu.getWebrtcUrl().equals(webrtcUrl) ||
                            !vtdu.getRtspUrl().equals(rtspUrl) ||
                            !vtdu.getRtmpUrl().equals(rtmpUrl)) {
                        vtdu.setRtspUrl(rtspUrl);
                        vtdu.setRtmpUrl(rtmpUrl);
                        vtdu.setWebrtcUrl(webrtcUrl);
                        ardVtduService.updateArdVtdu(vtdu);
                        log.info("更新媒体记录:{}", vtdu.getName());
                    }
                } else {
                    // 如果没有,插入新的记录
                    ArdVtdu vtdu = new ArdVtdu();
                    vtdu.setName(name);
                    vtdu.setRtspSource(rtspSourceUrl);
                    vtdu.setCameraId(cameraId);
                    vtdu.setRtspUrl(rtspUrl);
                    vtdu.setRtmpUrl(rtmpUrl);
                    vtdu.setWebrtcUrl(webrtcUrl);
                    ardVtduService.insertArdVtdu(vtdu);  // 保存到媒体表
                    log.info("插入新媒体记录:{}", vtdu.getName());
                }
            });
            // 3. 删除操作:删除媒体表中多余的记录
            List<String> invalidNames = ardVtduList.stream()
                    .filter(vtdu -> !validNames.contains(vtdu.getName()))
                    .filter(vtdu -> !"publisher".equalsIgnoreCase(vtdu.getRtspSource())) // 不是机场流
                    .map(ArdVtdu::getName)
                    .collect(Collectors.toList());
            if (!invalidNames.isEmpty()) {
                // 将 List<String> 转换为 String[]
                String[] namesArray = invalidNames.toArray(new String[0]);
                ardVtduService.deleteArdVtduByNames(namesArray); // 传递数组
                log.info("删除不再存在的媒体记录:{}", Arrays.toString(namesArray));
            }
        } catch (Exception e) {
          log.error("定时同步Vtdu任务异常:{}", e.getMessage());
        }
    }
    // 根据通道信息获取rtsp源地址
    private String getRtspSource(ArdChannel channel) {
        String rtspSource = "";
        ArdCamera ardCamera = redisCache.getCacheObject(CacheConstants.CAMERA_LIST_KEY + channel.getDeviceId());
        if (ardCamera != null) {
            switch (ardCamera.getFactory()) {
                case "1":
                    rtspSource =
                            "rtsp://" + ardCamera.getUsername() + ":" + ardCamera.getPassword() + "@" + ardCamera.getIp() + ":" + ardCamera.getRtspPort() + "/h264/ch" + channel.getChanNo() + "/main/av_stream";
                    break;
                case "2":
                    rtspSource =
                            "rtsp://" + ardCamera.getUsername() + ":" + ardCamera.getPassword() + "@" + ardCamera.getIp() + ":" + ardCamera.getRtspPort() + "/cam/realmonitor?channel=" + channel.getChanNo() + "&subtype=0";
                    break;
            }
        }
        return rtspSource;
    }
}
ard-quartz/src/main/java/com/ard/quartz/task/DeviceTask.java
File was deleted
ard-vtdu/src/main/java/com/ard/vtdu/service/impl/ArdVtduServiceImpl.java
@@ -28,14 +28,14 @@
    @Resource
    private ArdVtduMapper ardVtduMapper;
    @Resource
    private IArdMediaService mediaService;
    private IArdMediaService ardMediaService;
    @PostConstruct
    public void initMediaMTX() {
        //清空mediamtx流媒体数据
        mediaService.clearAll();
        ardMediaService.clearAll();
    }
    /**
@@ -69,7 +69,7 @@
    @Override
    public int insertArdVtdu(ArdVtdu ardVtdu) {
        ardVtdu.setCreateTime(DateUtils.getNowDate());
        ardVtdu = mediaService.addPath(ardVtdu);
        ardVtdu = ardMediaService.addPath(ardVtdu);
        return ardVtduMapper.insertArdVtdu(ardVtdu);
    }
@@ -82,7 +82,7 @@
    @Override
    public int updateArdVtdu(ArdVtdu ardVtdu) {
        ardVtdu.setUpdateTime(DateUtils.getNowDate());
        ardVtdu = mediaService.editPath(ardVtdu);
        ardVtdu = ardMediaService.editPath(ardVtdu);
        ardVtdu.setUpdateTime(DateUtils.getNowDate());
        return ardVtduMapper.updateArdVtdu(ardVtdu);
    }
@@ -98,7 +98,7 @@
        for (String name : names) {
            log.debug("流媒体【" + name + "】通道删除");
        }
        mediaService.removePath(names);
        ardMediaService.removePath(names);
        return ardVtduMapper.deleteArdVtduByNames(names);
    }
@@ -110,7 +110,7 @@
     */
    @Override
    public int deleteArdVtduByName(String name) {
        mediaService.removePath(name);
        ardMediaService.removePath(name);
        log.debug("流媒体【" + name + "】通道删除");
        return ardVtduMapper.deleteArdVtduByName(name);
    }
@@ -177,7 +177,7 @@
    public void asyncMediaMTX(List<ArdVtdu> vtdus, List<String> names) {
        //需要更新的数据,参数顺序注意
        sameList(vtdus, names).forEach(vtdu -> {
            Conf conf = mediaService.getPathConfig(vtdu.getName());
            Conf conf = ardMediaService.getPathConfig(vtdu.getName());
            if (conf == null || conf.getSource() == null) {
                return;
            }
@@ -188,16 +188,32 @@
            boolean isRtspSourceChanged = !Objects.equals(confRtspSource, currentRtspSource);
            // 如果 RTSP 源发生变化,则更新路径
            if (isRtspSourceChanged) {
                mediaService.editPath(vtdu);
                ardMediaService.editPath(vtdu);
            }
        });
        //需要删除的数据
        diffListToDel(vtdus, names).forEach(name -> {
            mediaService.removePath(name);
            ardMediaService.removePath(name);
        });
        //需要新增的数据
        diffListToAdd(vtdus, names).forEach(vtdu -> {
            mediaService.addPath(vtdu);
            ardMediaService.addPath(vtdu);
        });
    }
    /**
     * 同步mediamtx
     */
    @Scheduled(cron = "0/10 * * * * ?")
    public void syncMediamtx() {
        log.debug("定时同步MediaMTX任务");
        try {
            List<String> nameList = ardMediaService.getNameList();
            List<ArdVtdu> ardVtduList = this.selectArdVtduList(new ArdVtdu());
            asyncMediaMTX(ardVtduList, nameList);
        }
        catch (Exception e) {
            log.error("同步MediaMTX任务失败", e);
        }
    }
}
ard-work/src/main/java/com/ard/work/service/impl/ArdDroneInfoServiceImpl.java
@@ -307,6 +307,8 @@
     */
    @Scheduled(fixedRate = 5000)
    public void syncBoxInfo() {
        log.debug("定时执行同步盒子属性任务");
        try {
        ArdServerInfo ardServerInfo = new ArdServerInfo();
        ardServerInfo.setUseDataScope(false);
        List<ArdServerInfo> servers = ardServerInfoService.selectArdServerInfoList(ardServerInfo);
@@ -359,6 +361,9 @@
                }
            }
        }
        } catch (Exception e) {
            log.error("同步盒子属性任务异常", e);
        }
    }
ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskPartServiceImpl.java
@@ -48,6 +48,8 @@
     */
    @Scheduled(fixedRate = 1000)
    public void readTelemetryTask() {
       log.debug("定时任务:读取遥测数据");
        try {
        long now = System.currentTimeMillis();
        UavTelemetryDataCache.forEach((boxSn, telemetryData) -> {
            // 1️⃣ 从状态缓存里取当前状态
@@ -81,6 +83,10 @@
            }
        });
    }
        catch (Exception e) {
            log.error("定时任务:读取遥测数据异常", e);
        }
    }
    /**
     * 添加一条遥测数据到缓存
ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskServiceImpl.java
@@ -55,6 +55,7 @@
     */
    @Scheduled(fixedDelay = 5000)
    public void syncAllFlightHistory() {
        try {
        List<String> serverIds = ardServerInfoService.getServerIdsList();
        for (String serverId : serverIds) {
            // 获取上次同步的时间(即数据库中最大 startTime)
@@ -62,6 +63,9 @@
            // 根据上次同步时间同步飞行历史
            syncFlightHistory(serverId, lastSyncTime);
        }
        } catch (Exception e) {
            log.error("同步飞行历史失败", e);
        }
    }
    // 获取上次同步时间(获取最大 startTime)
ard-work/src/main/java/com/ard/work/service/task/MediaTask.java
File was renamed from ard-quartz/src/main/java/com/ard/quartz/task/MediaTask.java
@@ -1,4 +1,4 @@
package com.ard.quartz.task;
package com.ard.work.service.task;
import com.ard.common.utils.StringUtils;
import com.ard.common.utils.file.MimeTypeUtils;
@@ -39,7 +39,7 @@
 *
 * @author ard
 */
@Component("MediaTask")
@Component
@Slf4j
public class MediaTask {
    @Resource
@@ -55,7 +55,7 @@
    private final AtomicBoolean runningVideo = new AtomicBoolean(false);
    private final AtomicBoolean runningPic = new AtomicBoolean(false);
    @Scheduled(cron = "0/10 * * * * ?")
    public void syncVideoMediaUrl() {
        log.warn("开始同步视频媒体");
        if (!runningVideo.compareAndSet(false, true)) {
@@ -81,7 +81,7 @@
            runningVideo.set(false);
        }
    }
    @Scheduled(cron = "0/10 * * * * ?")
    public void syncPicMediaUrl() {
        log.warn("开始同步图片媒体");
        if (!runningPic.compareAndSet(false, true)) {