From 09323e7895ae85319cd8afc51409be43cde90e3d Mon Sep 17 00:00:00 2001
From: zhaowenyu <35589726@qq.com>
Date: Tue, 18 Nov 2025 15:18:16 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev' into dev
---
ard-work/src/main/java/com/ard/work/mapper/ArdFlightTaskMapper.java | 26 +
ard-work/src/main/java/com/ard/work/mapper/ArdMediaMapper.java | 32 ++
ard-work/src/main/java/com/ard/work/domain/dto/BoxHistoryDTO.java | 3
ard-oss/src/main/java/com/ard/oss/service/impl/OssServiceContext.java | 16 +
ard-work/src/main/java/com/ard/work/domain/entity/ArdFlightTask.java | 23 +
ard-work/src/main/java/com/ard/work/domain/entity/ArdMedia.java | 16 +
ard-admin/src/main/java/com/ard/web/controller/work/UavBaseController.java | 26 +
ard-work/src/main/java/com/ard/work/service/impl/IArdMediaServiceImpl.java | 31 ++
ard-work/src/main/java/com/ard/work/mapper/ArdServerInfoMapper.java | 6
ard-work/src/main/java/com/ard/work/service/impl/GimbalSpeedServiceImpl.java | 2
ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskServiceServiceImpl.java | 273 +++++++++++++++++++
ard-common/src/main/java/com/ard/common/utils/file/MimeTypeUtils.java | 27 +
ard-work/src/main/resources/mapper/ArdFlightTaskMapper.xml | 117 ++++++++
ard-work/src/main/java/com/ard/work/domain/receiver/BoxHistoryReceiver.java | 7
ard-work/src/main/resources/mapper/ArdServerInfoMapper.xml | 6
ard-work/src/main/java/com/ard/work/service/impl/ArdServerInfoServiceImpl.java | 5
ard-work/src/main/java/com/ard/work/service/IArdMediaService.java | 20 +
ard-work/src/main/java/com/ard/work/service/IArdServerInfoService.java | 5
ard-work/src/main/java/com/ard/work/service/IArdFlightTaskService.java | 19 +
ard-work/src/main/resources/mapper/ArdMediaMapper.xml | 140 ++++++++++
20 files changed, 786 insertions(+), 14 deletions(-)
diff --git a/ard-admin/src/main/java/com/ard/web/controller/work/UavBaseController.java b/ard-admin/src/main/java/com/ard/web/controller/work/UavBaseController.java
index 243651c..2ca21ae 100644
--- a/ard-admin/src/main/java/com/ard/web/controller/work/UavBaseController.java
+++ b/ard-admin/src/main/java/com/ard/web/controller/work/UavBaseController.java
@@ -6,10 +6,15 @@
import com.ard.work.domain.dto.BoxHistoryDTO;
import com.ard.work.domain.dto.BoxPhotosDTO;
import com.ard.work.domain.dto.BoxSettingsDTO;
+import com.ard.work.domain.entity.ArdDroneInfo;
+import com.ard.work.domain.entity.ArdFlightTask;
+import com.ard.work.domain.entity.ArdMedia;
import com.ard.work.domain.receiver.BoxHistoryReceiver;
import com.ard.work.domain.receiver.BoxPhotosReceiver;
import com.ard.work.domain.receiver.BoxInfoReceiver;
import com.ard.work.domain.receiver.BoxStreamUrlReceiver;
+import com.ard.work.service.IArdFlightTaskService;
+import com.ard.work.service.IArdMediaService;
import com.ard.work.service.ITyService;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSort;
@@ -35,6 +40,10 @@
@Resource
private ITyService tyService;
+ @Resource
+ private IArdFlightTaskService ardFlightTaskService;
+ @Resource
+ private IArdMediaService ardMediaService;
@ApiOperation("获取边缘服务器token信息")
@ApiOperationSupport(order = 1)
@@ -61,6 +70,23 @@
List<BoxHistoryReceiver> boxHistory = tyService.getBoxHistory(boxHistoryDTO);
return AjaxResult.success(boxHistory);
}
+ @ApiOperation("获取飞行架次")
+ @ApiOperationSupport(order = 4)
+ @GetMapping("/getFlightTask")
+ public TableDataInfo getFlightTask(ArdFlightTask ardFlightTask) {
+ startPage();
+ List<ArdFlightTask> list = ardFlightTaskService.selectArdFlightTask(ardFlightTask);
+ return getDataTable(list);
+ }
+
+ @ApiOperation("获取媒体数据")
+ @ApiOperationSupport(order = 4)
+ @GetMapping("/getMediaList")
+ public TableDataInfo getMediaList(ArdMedia ardMedia) {
+ startPage();
+ List<ArdMedia> list = ardMediaService.selectArdMediaList(ardMedia);
+ return getDataTable(list);
+ }
@ApiOperation("获取任务照片")
@ApiOperationSupport(order = 5)
diff --git a/ard-common/src/main/java/com/ard/common/utils/file/MimeTypeUtils.java b/ard-common/src/main/java/com/ard/common/utils/file/MimeTypeUtils.java
index 9d85813..11c9625 100644
--- a/ard-common/src/main/java/com/ard/common/utils/file/MimeTypeUtils.java
+++ b/ard-common/src/main/java/com/ard/common/utils/file/MimeTypeUtils.java
@@ -2,11 +2,12 @@
/**
* 媒体类型工具类
- *
+ *
* @author ard
*/
-public class MimeTypeUtils
-{
+public class MimeTypeUtils {
+ public static final String VIDEO_MP4 = "video/mp4";
+
public static final String IMAGE_PNG = "image/png";
public static final String IMAGE_JPG = "image/jpg";
@@ -16,15 +17,15 @@
public static final String IMAGE_BMP = "image/bmp";
public static final String IMAGE_GIF = "image/gif";
-
- public static final String[] IMAGE_EXTENSION = { "bmp", "gif", "jpg", "jpeg", "png" };
- public static final String[] FLASH_EXTENSION = { "swf", "flv" };
+ public static final String[] IMAGE_EXTENSION = {"bmp", "gif", "jpg", "jpeg", "png"};
- public static final String[] MEDIA_EXTENSION = { "swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg",
- "asf", "rm", "rmvb" };
+ public static final String[] FLASH_EXTENSION = {"swf", "flv"};
- public static final String[] VIDEO_EXTENSION = { "mp4", "avi", "rmvb" };
+ public static final String[] MEDIA_EXTENSION = {"swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg",
+ "asf", "rm", "rmvb"};
+
+ public static final String[] VIDEO_EXTENSION = {"mp4", "avi", "rmvb"};
public static final String[] DEFAULT_ALLOWED_EXTENSION = {
// 图片
@@ -43,10 +44,10 @@
"glb"
};
- public static String getExtension(String prefix)
- {
- switch (prefix)
- {
+ public static String getExtension(String prefix) {
+ switch (prefix) {
+ case VIDEO_MP4:
+ return "mp4";
case IMAGE_PNG:
return "png";
case IMAGE_JPG:
diff --git a/ard-oss/src/main/java/com/ard/oss/service/impl/OssServiceContext.java b/ard-oss/src/main/java/com/ard/oss/service/impl/OssServiceContext.java
index cc61355..e78de05 100644
--- a/ard-oss/src/main/java/com/ard/oss/service/impl/OssServiceContext.java
+++ b/ard-oss/src/main/java/com/ard/oss/service/impl/OssServiceContext.java
@@ -12,6 +12,7 @@
import io.minio.PutObjectArgs;
import lombok.Cleanup;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
@@ -167,7 +168,22 @@
throw new RuntimeException("Upload failed: " + e.getMessage(), e);
}
}
+ @Async("threadPoolTaskExecutor")
+ public String upload(String bucket, String objectKey, InputStream input, String contentType) {
+ try {
+ // 上传文件时指定 Content-Type
+ this.ossService.putObject(bucket, objectKey, input, contentType);
+ // ✅ 构建永久访问 URL
+ String baseUrl = OssConfiguration.endpoint;
+ if (!baseUrl.endsWith("/")) {
+ baseUrl += "/";
+ }
+ return baseUrl + bucket + "/" + objectKey;
+ } catch (Exception e) {
+ throw new RuntimeException("Upload failed: " + e.getMessage(), e);
+ }
+ }
// 获取文件 MIME 类型
public String getMimeTypeByExtension(String fileName) {
// 获取文件扩展名
diff --git a/ard-work/src/main/java/com/ard/work/domain/dto/BoxHistoryDTO.java b/ard-work/src/main/java/com/ard/work/domain/dto/BoxHistoryDTO.java
index ecbd858..d58e025 100644
--- a/ard-work/src/main/java/com/ard/work/domain/dto/BoxHistoryDTO.java
+++ b/ard-work/src/main/java/com/ard/work/domain/dto/BoxHistoryDTO.java
@@ -1,11 +1,14 @@
package com.ard.work.domain.dto;
+import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
+import java.util.Date;
+
@Data
@Builder
@AllArgsConstructor
diff --git a/ard-work/src/main/java/com/ard/work/domain/entity/ArdFlightTask.java b/ard-work/src/main/java/com/ard/work/domain/entity/ArdFlightTask.java
new file mode 100644
index 0000000..8e4602b
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/work/domain/entity/ArdFlightTask.java
@@ -0,0 +1,23 @@
+package com.ard.work.domain.entity;
+
+import com.ard.common.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+@Data
+public class ArdFlightTask extends BaseEntity {
+
+ private Integer taskId; // 任务ID
+ private String boxSn; // 飞行器序列号
+ private String boxName; // 飞行器名称
+ private String taskName; // 任务名称
+ private Integer photoCount; // 图片数量
+ private Integer videoCount; // 录像数量
+ private String videoPath; // 视频路径
+ private Date startTime; // 任务开始时间
+ private Date endTime; // 任务结束时间
+ private String serverId; // 服务器ID
+ private List<ArdMedia> mediaList; // 媒体文件列表
+}
diff --git a/ard-work/src/main/java/com/ard/work/domain/entity/ArdMedia.java b/ard-work/src/main/java/com/ard/work/domain/entity/ArdMedia.java
new file mode 100644
index 0000000..a29e680
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/work/domain/entity/ArdMedia.java
@@ -0,0 +1,16 @@
+package com.ard.work.domain.entity;
+
+import com.ard.common.core.domain.BaseEntity;
+import lombok.Data;
+
+@Data
+public class ArdMedia extends BaseEntity {
+
+ private String id; // 媒体ID
+ private Integer taskId; // 任务ID(外键关联飞行任务)
+ private Integer mediaType; // 媒体类型(0"photo" 或 1"video")
+ private Long fileSize; // 文件大小
+ private String fileMd5; // 文件MD5值
+ private String mediaUrl; // 地址
+ private String sourceUrl; // 源地址
+}
diff --git a/ard-work/src/main/java/com/ard/work/domain/receiver/BoxHistoryReceiver.java b/ard-work/src/main/java/com/ard/work/domain/receiver/BoxHistoryReceiver.java
index de84960..5e03b4e 100644
--- a/ard-work/src/main/java/com/ard/work/domain/receiver/BoxHistoryReceiver.java
+++ b/ard-work/src/main/java/com/ard/work/domain/receiver/BoxHistoryReceiver.java
@@ -37,6 +37,13 @@
@JsonProperty("endTime")
private String endTime;
+
+ private Integer flightDuration;
+ private Integer flightMileage;
+ private Float aveSpeed;
+ private Float maxSpeed;
+
+
@JsonProperty("videoPathList")
private List<String> videoPathList;
diff --git a/ard-work/src/main/java/com/ard/work/mapper/ArdFlightTaskMapper.java b/ard-work/src/main/java/com/ard/work/mapper/ArdFlightTaskMapper.java
new file mode 100644
index 0000000..9235bc4
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/work/mapper/ArdFlightTaskMapper.java
@@ -0,0 +1,26 @@
+package com.ard.work.mapper;
+
+import com.ard.work.domain.entity.ArdFlightTask;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
+
+public interface ArdFlightTaskMapper {
+ // 插入飞行任务
+ int insertArdFlightTask(ArdFlightTask task);
+
+ // 根据任务ID获取飞行任务
+ ArdFlightTask getArdFlightTaskById(@Param("taskId") Integer taskId);
+
+ // 获取所有飞行任务
+ List<ArdFlightTask> selectArdFlightTask(ArdFlightTask ardFlightTask);
+
+ // 获取某个时间戳后的任务
+ List<ArdFlightTask> getTasksAfter(@Param("lastSyncTime") String lastSyncTime);
+
+
+ // 获取最大 startTime
+ Date findMaxStartTimeByServerId(String serverId);
+}
+
diff --git a/ard-work/src/main/java/com/ard/work/mapper/ArdMediaMapper.java b/ard-work/src/main/java/com/ard/work/mapper/ArdMediaMapper.java
new file mode 100644
index 0000000..ebd0e76
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/work/mapper/ArdMediaMapper.java
@@ -0,0 +1,32 @@
+package com.ard.work.mapper;
+
+import com.ard.work.domain.entity.ArdMedia;
+import org.apache.ibatis.annotations.Mapper;
+import java.util.List;
+
+
+public interface ArdMediaMapper {
+
+ /**
+ * 查询媒体数据列表
+ *
+ * @param ardMedia 媒体数据
+ * @return 媒体数据集合
+ */
+ List<ArdMedia> selectArdMedia(ArdMedia ardMedia); // 动态查询
+ List<ArdMedia> selectArdMediaByTaskId(Integer taskId); // 根据任务ID查询
+
+ /**
+ * 插入媒体数据记录
+ *
+ * @param ardMedia 媒体数据
+ */
+ void insertArdMedia(ArdMedia ardMedia); // 插入单个记录
+
+ void insertArdMediaList(List<ArdMedia> ardMediaList); // 插入批量记录
+
+ void updateArdMedia(ArdMedia ardMedia); // 更新记录
+ void deleteArdMediaById(Integer id); // 根据ID删除记录
+ void deleteArdMediaByIds(List<Integer> mediaIds); // 批量删除记录
+ void deleteArdMediaByTaskId(Integer taskId); // 批量删除记录
+}
diff --git a/ard-work/src/main/java/com/ard/work/mapper/ArdServerInfoMapper.java b/ard-work/src/main/java/com/ard/work/mapper/ArdServerInfoMapper.java
index f28c31b..b99214d 100644
--- a/ard-work/src/main/java/com/ard/work/mapper/ArdServerInfoMapper.java
+++ b/ard-work/src/main/java/com/ard/work/mapper/ArdServerInfoMapper.java
@@ -70,4 +70,10 @@
*/
public int updateServerStatus(@Param("id") String id, @Param("status") String status);
+ /**
+ * 获取服务器ids
+ *
+ * @return 结果
+ */
+ List<String> getServerIdsList();
}
diff --git a/ard-work/src/main/java/com/ard/work/service/IArdFlightTaskService.java b/ard-work/src/main/java/com/ard/work/service/IArdFlightTaskService.java
new file mode 100644
index 0000000..ca8d500
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/work/service/IArdFlightTaskService.java
@@ -0,0 +1,19 @@
+package com.ard.work.service;
+
+import com.ard.work.domain.entity.ArdFlightTask;
+import java.util.List;
+
+/**
+ * Description:
+ * Author: lsy
+ * Date: 2025年11月18日12:31
+ **/
+public interface IArdFlightTaskService {
+ /**
+ * 查询飞行架次列表
+ *
+ * @param ardFlightTask 飞行架次
+ * @return 无人机飞行架次合
+ */
+ public List<ArdFlightTask> selectArdFlightTask(ArdFlightTask ardFlightTask);
+}
diff --git a/ard-work/src/main/java/com/ard/work/service/IArdMediaService.java b/ard-work/src/main/java/com/ard/work/service/IArdMediaService.java
new file mode 100644
index 0000000..356ed7a
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/work/service/IArdMediaService.java
@@ -0,0 +1,20 @@
+package com.ard.work.service;
+
+import com.ard.work.domain.entity.ArdMedia;
+
+import java.util.List;
+
+/**
+ * Description:
+ * Author: lsy
+ * Date: 2025年11月18日13:15
+ **/
+public interface IArdMediaService {
+ /**
+ * 查询媒体数据列表
+ *
+ * @param ardMedia 媒体数据
+ * @return 媒体数据集合
+ */
+ public List<ArdMedia> selectArdMediaList(ArdMedia ardMedia);
+}
diff --git a/ard-work/src/main/java/com/ard/work/service/IArdServerInfoService.java b/ard-work/src/main/java/com/ard/work/service/IArdServerInfoService.java
index f6ab3d7..78b1125 100644
--- a/ard-work/src/main/java/com/ard/work/service/IArdServerInfoService.java
+++ b/ard-work/src/main/java/com/ard/work/service/IArdServerInfoService.java
@@ -70,4 +70,9 @@
*/
public int updateServerStatus(String id,String status);
+ /**
+ * 获取服务器ID列表
+ */
+ public List<String> getServerIdsList();
+
}
diff --git a/ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskServiceServiceImpl.java b/ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskServiceServiceImpl.java
new file mode 100644
index 0000000..87b1be2
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskServiceServiceImpl.java
@@ -0,0 +1,273 @@
+package com.ard.work.service.impl;
+
+import com.ard.common.utils.DateUtils;
+import com.ard.common.utils.StringUtils;
+import com.ard.common.utils.file.MimeTypeUtils;
+import com.ard.common.utils.uuid.IdUtils;
+import com.ard.oss.service.IOssService;
+import com.ard.oss.service.impl.OssServiceContext;
+import com.ard.work.component.forest.TyClient;
+import com.ard.work.domain.dto.BoxHistoryDTO;
+import com.ard.work.domain.dto.BoxPhotosDTO;
+import com.ard.work.domain.entity.ArdFlightTask;
+import com.ard.work.domain.entity.ArdMedia;
+import com.ard.work.domain.receiver.BoxHistoryReceiver;
+import com.ard.work.domain.receiver.BoxPhotosReceiver;
+import com.ard.work.domain.receiver.TyHttpCommonReceiver;
+import com.ard.work.mapper.ArdFlightTaskMapper;
+import com.ard.work.mapper.ArdMediaMapper;
+import com.ard.work.service.IArdFlightTaskService;
+import com.ard.work.service.IArdServerInfoService;
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import javax.net.ssl.*;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+
+@Service
+public class ArdFlightTaskServiceServiceImpl implements IArdFlightTaskService {
+
+ @Resource
+ private ArdFlightTaskMapper ardFlightTaskMapper;
+ @Resource
+ private ArdMediaMapper ardMediaMapper;
+ @Resource
+ private IArdServerInfoService ardServerInfoService;
+ @Resource
+ private TyClient tyClient;
+ @Resource
+ private OssServiceContext ossServiceContext;
+
+ @Resource
+ private ThreadPoolTaskExecutor threadPoolTaskExecutor; // 使用线程池执行异步任务
+
+ @Override
+ public List<ArdFlightTask> selectArdFlightTask(ArdFlightTask ardFlightTask) {
+ return ardFlightTaskMapper.selectArdFlightTask(ardFlightTask);
+ }
+
+ // 同步所有服务的飞行历史
+ @Scheduled(fixedDelay = 10000)
+ public void syncAllFlightHistory() {
+ List<String> serverIds = ardServerInfoService.getServerIdsList();
+ for (String serverId : serverIds) {
+ // 获取上次同步的时间(即数据库中最大 startTime)
+ Date lastSyncTime = getLastSyncTimeForServer(serverId);
+ // 根据上次同步时间同步飞行历史
+ syncFlightHistory(serverId, lastSyncTime);
+ }
+ }
+
+ // 获取上次同步时间(获取最大 startTime)
+ private Date getLastSyncTimeForServer(String serverId) {
+ Date maxStartTime = ardFlightTaskMapper.findMaxStartTimeByServerId(serverId);
+ return maxStartTime != null ? maxStartTime : new Date(0); // 如果没有数据,返回 Unix 纪元时间作为起点
+ }
+
+ // 调用接口获取飞行历史数据
+ // 根据上次同步时间同步飞行历史
+ public void syncFlightHistory(String serverId, Date lastSyncTime) {
+ // 创建查询条件 BoxHistoryDTO,并设置 startTime 作为过滤条件
+ BoxHistoryDTO boxHistoryDTO = new BoxHistoryDTO();
+ boxHistoryDTO.setStartTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, lastSyncTime)); // 传递 lastSyncTime 参数
+
+ // 获取飞行历史
+ List<BoxHistoryReceiver> historyList = getBoxHistory(serverId, boxHistoryDTO);
+
+ // 如果获取到数据,处理并同步到本地数据库
+ if (historyList != null && !historyList.isEmpty()) {
+ for (BoxHistoryReceiver boxHistory : historyList) {
+ syncToLocalDatabase(serverId, boxHistory);
+ }
+ }
+ }
+
+ // 调用接口获取飞行历史数据
+ private List<BoxHistoryReceiver> getBoxHistory(String serverId, BoxHistoryDTO boxHistoryDTO) {
+ TyHttpCommonReceiver<List<BoxHistoryReceiver>> boxHistory = tyClient.getBoxHistory(serverId, boxHistoryDTO);
+ return boxHistory.getContent();
+ }
+
+ // 将数据同步到本地数据库
+ private void syncToLocalDatabase(String serverId, BoxHistoryReceiver boxHistoryReceiver) {
+ // 创建FlightTask实体对象并填充数据
+ ArdFlightTask flightTask = new ArdFlightTask();
+ flightTask.setTaskId(boxHistoryReceiver.getTaskId());
+ flightTask.setBoxSn(boxHistoryReceiver.getBoxSn());
+ flightTask.setBoxName(boxHistoryReceiver.getBoxName());
+ flightTask.setTaskName(boxHistoryReceiver.getTaskName());
+
+ Integer photoCount = Integer.parseInt(boxHistoryReceiver.getPhotoCount());
+ flightTask.setPhotoCount(photoCount);
+
+ Integer videoCount = (boxHistoryReceiver.getVideoPathList() != null) ?
+ boxHistoryReceiver.getVideoPathList().size() : 0;
+ flightTask.setVideoCount(videoCount);
+
+ flightTask.setVideoPath(boxHistoryReceiver.getVideoPath());
+ flightTask.setServerId(serverId);
+
+ Date startTime = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, boxHistoryReceiver.getStartTime());
+ flightTask.setStartTime(startTime);
+
+ Date endTime = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, boxHistoryReceiver.getEndTime());
+ flightTask.setEndTime(endTime);
+
+ flightTask.setCreateTime(DateUtils.getNowDate());
+
+ // 检查是否已经存在相同任务ID的记录
+ ArdFlightTask ardFlightTaskById = ardFlightTaskMapper.getArdFlightTaskById(flightTask.getTaskId());
+ if (ardFlightTaskById != null) {
+ return;
+ }
+
+ System.out.println("Syncing task " + boxHistoryReceiver.getTaskId());
+
+ // 插入新记录
+ int rows = ardFlightTaskMapper.insertArdFlightTask(flightTask);
+ if (rows > 0) {
+ // 删除旧的媒体记录,防止重复插入
+ ardMediaMapper.deleteArdMediaByTaskId(flightTask.getTaskId());
+
+ // 插入视频
+ syncVideoToDatabase(flightTask, boxHistoryReceiver.getVideoPathList());
+
+ // 插入图片
+ syncPhotoToDatabase(flightTask, serverId, boxHistoryReceiver.getBoxSn());
+ }
+ }
+
+ // 插入视频记录
+ private void syncVideoToDatabase(ArdFlightTask flightTask, List<String> videoPathList) {
+ if (videoPathList != null && !videoPathList.isEmpty()) {
+ for (String videoPath : videoPathList) {
+
+ ArdMedia ardMedia = new ArdMedia();
+ ardMedia.setId(IdUtils.simpleUUID());
+ ardMedia.setTaskId(flightTask.getTaskId());
+ ardMedia.setMediaType(1); // 1表示视频
+ ardMedia.setSourceUrl(videoPath);
+ // 异步上传文件到OSS,并在上传完成后插入数据库
+ CompletableFuture.supplyAsync(() -> uploadFileToOss(flightTask.getBoxSn(), videoPath, "record",
+ MimeTypeUtils.VIDEO_MP4), threadPoolTaskExecutor)
+ .thenAccept(url -> {
+ ardMedia.setMediaUrl(url); // 获取上传后的文件 URL
+ ardMedia.setCreateTime(new Date());
+ ardMediaMapper.insertArdMedia(ardMedia); // 插入数据库
+ });
+ }
+ }
+ }
+
+ // 插入图片记录
+ private void syncPhotoToDatabase(ArdFlightTask flightTask, String serverId, String boxSn) {
+ // 查询图片
+ BoxPhotosDTO boxPhotosDTO = new BoxPhotosDTO();
+ boxPhotosDTO.setTaskId(flightTask.getTaskId());
+ boxPhotosDTO.setBoxSn(boxSn);
+ boxPhotosDTO.setPageIndex(1);
+ boxPhotosDTO.setPageSize(1000);
+
+ TyHttpCommonReceiver<List<BoxPhotosReceiver>> boxPhotos = tyClient.getBoxPhotos(serverId, boxPhotosDTO);
+ List<BoxPhotosReceiver> photoList = boxPhotos.getContent();
+
+ if (photoList != null && !photoList.isEmpty()) {
+ for (BoxPhotosReceiver photo : photoList) {
+ ArdMedia ardMedia = new ArdMedia();
+ ardMedia.setId(IdUtils.simpleUUID());
+ ardMedia.setTaskId(flightTask.getTaskId());
+ ardMedia.setMediaType(0); // 0表示图片
+ ardMedia.setFileSize(photo.getFileSize());
+ ardMedia.setFileMd5(photo.getFileMd5());
+ ardMedia.setSourceUrl(photo.getImgUrl());
+ // 异步上传文件到OSS,并在上传完成后插入数据库
+ CompletableFuture.supplyAsync(() -> uploadFileToOss(flightTask.getBoxSn(), photo.getImgUrl(), "pic",
+ MimeTypeUtils.IMAGE_JPG), threadPoolTaskExecutor)
+ .thenAccept(url -> {
+ ardMedia.setMediaUrl(url); // 获取上传后的文件 URL
+ ardMedia.setCreateTime(new Date());
+ ardMediaMapper.insertArdMedia(ardMedia); // 插入数据库
+ });
+ }
+ }
+ }
+
+ // 通用的上传方法,支持视频和图片等文件上传
+ public String uploadFileToOss(String boxSn, String fileUrl, String bucket, String contentType) {
+ InputStream fileInputStream = null;
+ String fileOssUrl = "";
+ try {
+ // 创建信任所有证书的SSLContext
+ TrustManager[] trustAllCerts = new TrustManager[]{
+ new X509TrustManager() {
+ @Override
+ public java.security.cert.X509Certificate[] getAcceptedIssuers() {
+ return null;
+ }
+
+ @Override
+ public void checkClientTrusted(
+ java.security.cert.X509Certificate[] certs, String authType) {
+ }
+
+ @Override
+ public void checkServerTrusted(
+ java.security.cert.X509Certificate[] certs, String authType) {
+ }
+ }
+ };
+
+ SSLContext sc = SSLContext.getInstance("SSL");
+ sc.init(null, trustAllCerts, new java.security.SecureRandom());
+ HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+
+ // 创建所有主机名都信任的HostnameVerifier
+ HostnameVerifier allHostsValid = new HostnameVerifier() {
+ @Override
+ public boolean verify(String hostname, SSLSession session) {
+ return true;
+ }
+ };
+ HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
+
+ // 现在可以正常访问
+
+ // 从URL创建InputStream
+ URL url = new URL(fileUrl);
+ fileInputStream = url.openStream();
+
+ // 文件名
+ String fileName = boxSn + "/" + IdUtils.fastSimpleUUID() + "." + MimeTypeUtils.getExtension(contentType);
+
+ // 调用OSS服务上下文进行文件上传
+ fileOssUrl = ossServiceContext.upload(bucket, fileName, fileInputStream, contentType);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ // 异常处理,可以选择记录日志或者抛出业务异常
+ } finally {
+ // 关闭InputStream
+ if (fileInputStream != null) {
+ try {
+ fileInputStream.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ return fileOssUrl; // 返回上传后的文件OSS URL
+ }
+
+}
diff --git a/ard-work/src/main/java/com/ard/work/service/impl/ArdServerInfoServiceImpl.java b/ard-work/src/main/java/com/ard/work/service/impl/ArdServerInfoServiceImpl.java
index bc42e90..351b7ab 100644
--- a/ard-work/src/main/java/com/ard/work/service/impl/ArdServerInfoServiceImpl.java
+++ b/ard-work/src/main/java/com/ard/work/service/impl/ArdServerInfoServiceImpl.java
@@ -150,6 +150,11 @@
return ardServerInfoMapper.updateServerStatus(id,status);
}
+ @Override
+ public List<String> getServerIdsList() {
+ return ardServerInfoMapper.getServerIdsList();
+ }
+
private String getEncryptStr(ArdServerInfo serverInfo, long timeStamp) {
String sb = serverInfo.getAccessKeyId() + serverInfo.getAccessKeySecret() + timeStamp;
return DigestUtils.md5DigestAsHex(sb.getBytes());
diff --git a/ard-work/src/main/java/com/ard/work/service/impl/GimbalSpeedService.java b/ard-work/src/main/java/com/ard/work/service/impl/GimbalSpeedServiceImpl.java
similarity index 97%
rename from ard-work/src/main/java/com/ard/work/service/impl/GimbalSpeedService.java
rename to ard-work/src/main/java/com/ard/work/service/impl/GimbalSpeedServiceImpl.java
index dc5956f..be56386 100644
--- a/ard-work/src/main/java/com/ard/work/service/impl/GimbalSpeedService.java
+++ b/ard-work/src/main/java/com/ard/work/service/impl/GimbalSpeedServiceImpl.java
@@ -25,7 +25,7 @@
*/
@Service
@Slf4j
-public class GimbalSpeedService implements IGimbalSpeedService {
+public class GimbalSpeedServiceImpl implements IGimbalSpeedService {
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
private final Map<String, ScheduledFuture<?>> tasks = new ConcurrentHashMap<>();
diff --git a/ard-work/src/main/java/com/ard/work/service/impl/IArdMediaServiceImpl.java b/ard-work/src/main/java/com/ard/work/service/impl/IArdMediaServiceImpl.java
new file mode 100644
index 0000000..26a7e85
--- /dev/null
+++ b/ard-work/src/main/java/com/ard/work/service/impl/IArdMediaServiceImpl.java
@@ -0,0 +1,31 @@
+package com.ard.work.service.impl;
+
+import com.ard.work.domain.entity.ArdMedia;
+import com.ard.work.mapper.ArdMediaMapper;
+import com.ard.work.service.IArdMediaService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * Description:
+ * Author: lsy
+ * Date: 2025年11月18日13:17
+ **/
+@Service
+public class IArdMediaServiceImpl implements IArdMediaService {
+ @Resource
+ private ArdMediaMapper ardMediaMapper;
+
+ /**
+ * 查询媒体数据列表
+ *
+ * @param ardMedia 媒体数据
+ * @return 媒体数据集合
+ */
+ @Override
+ public List<ArdMedia> selectArdMediaList(ArdMedia ardMedia) {
+ return ardMediaMapper.selectArdMedia(ardMedia);
+ }
+}
diff --git a/ard-work/src/main/resources/mapper/ArdFlightTaskMapper.xml b/ard-work/src/main/resources/mapper/ArdFlightTaskMapper.xml
new file mode 100644
index 0000000..cdd7d25
--- /dev/null
+++ b/ard-work/src/main/resources/mapper/ArdFlightTaskMapper.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ard.work.mapper.ArdFlightTaskMapper">
+ <!-- 结果映射 -->
+ <resultMap id="ArdFlightTaskResult" type="ArdFlightTask">
+ <result property="taskId" column="task_id"/>
+ <result property="boxSn" column="box_sn"/>
+ <result property="boxName" column="box_name"/>
+ <result property="taskName" column="task_name"/>
+ <result property="videoCount" column="video_count"/>
+ <result property="photoCount" column="photo_count"/>
+ <result property="videoPath" column="video_path"/>
+ <result property="startTime" column="start_time"/>
+ <result property="endTime" column="end_time"/>
+ <result property="serverId" column="server_id"/>
+ <result property="createBy" column="create_by"/>
+ <result property="createTime" column="create_time"/>
+ <result property="updateBy" column="update_by"/>
+ <result property="updateTime" column="update_time"/>
+ <result property="remark" column="remark"/>
+ </resultMap>
+ <!-- 查询任务记录并联接图片和视频 -->
+ <select id="selectArdFlightTask" resultMap="ArdFlightTaskResult">
+ SELECT
+ aft.task_id,
+ aft.box_sn,
+ aft.box_name,
+ aft.task_name,
+ aft.video_count,
+ aft.photo_count,
+ aft.video_path,
+ aft.start_time,
+ aft.end_time,
+ aft.server_id,
+ aft.create_by,
+ aft.create_time,
+ aft.update_by,
+ aft.update_time,
+ aft.remark
+ FROM ard_flight_task aft
+ <where>
+ <trim prefix="" suffix="" suffixOverrides="AND,OR">
+ <if test="taskId != null">AND aft.task_id = #{taskId}</if>
+ <if test="boxSn != null">AND aft.box_sn = #{boxSn}</if>
+ <if test="boxName != null">AND aft.box_name LIKE CONCAT('%', #{boxName}, '%')</if>
+ <if test="taskName != null">AND aft.task_name LIKE CONCAT('%', #{taskName}, '%')</if>
+ <if test="startTime != null">AND aft.start_time >= #{startTime}</if>
+ <if test="endTime != null">AND aft.end_time <= #{endTime}</if>
+ <if test="serverId != null">AND aft.server_id = #{serverId}</if>
+ </trim>
+ </where>
+ ORDER BY aft.task_id DESC
+ </select>
+
+ <!-- 插入飞行任务 -->
+ <insert id="insertArdFlightTask" parameterType="com.ard.work.domain.entity.ArdFlightTask">
+ insert into ard_flight_task
+ <trim prefix="(" suffix=")" suffixOverrides=",">
+ <if test="taskId != null">task_id,</if>
+ <if test="boxSn != null">box_sn,</if>
+ <if test="boxName != null">box_name,</if>
+ <if test="taskName != null">task_name,</if>
+ <if test="videoCount != null">video_count,</if>
+ <if test="photoCount != null">photo_count,</if>
+ <if test="videoPath != null">video_path,</if>
+ <if test="startTime != null">start_time,</if>
+ <if test="endTime != null">end_time,</if>
+ <if test="serverId != null">server_id,</if>
+ <if test="createBy != null">create_by,</if>
+ <if test="createTime != null">create_time,</if>
+ <if test="updateBy != null">update_by,</if>
+ <if test="updateTime != null">update_time,</if>
+ <if test="remark != null">remark,</if>
+ </trim>
+ <trim prefix="values (" suffix=")" suffixOverrides=",">
+ <if test="taskId != null">#{taskId},</if>
+ <if test="boxSn != null">#{boxSn},</if>
+ <if test="boxName != null">#{boxName},</if>
+ <if test="taskName != null">#{taskName},</if>
+ <if test="videoCount != null">#{videoCount},</if>
+ <if test="photoCount != null">#{photoCount},</if>
+ <if test="videoPath != null">#{videoPath},</if>
+ <if test="startTime != null">#{startTime},</if>
+ <if test="endTime != null">#{endTime},</if>
+ <if test="serverId != null">#{serverId},</if>
+ <if test="createBy != null">#{createBy},</if>
+ <if test="createTime != null">#{createTime},</if>
+ <if test="updateBy != null">#{updateBy},</if>
+ <if test="updateTime != null">#{updateTime},</if>
+ <if test="remark != null">#{remark},</if>
+ </trim>
+ </insert>
+
+
+ <!-- 根据任务ID获取飞行任务 -->
+ <select id="getArdFlightTaskById" resultType="ArdFlightTask">
+ SELECT *
+ FROM ard_flight_task
+ WHERE task_id = #{taskId}
+ </select>
+
+
+ <!-- 获取某个时间戳后的任务 -->
+ <select id="getTasksAfter" resultType="ArdFlightTask">
+ SELECT *
+ FROM ard_flight_task
+ WHERE end_time > #{lastSyncTime}
+ </select>
+ <select id="findMaxStartTimeByServerId" resultType="java.util.Date">
+ SELECT MAX(start_time)
+ FROM ard_flight_task
+ WHERE server_id = #{serverId}
+ </select>
+</mapper>
+
diff --git a/ard-work/src/main/resources/mapper/ArdMediaMapper.xml b/ard-work/src/main/resources/mapper/ArdMediaMapper.xml
new file mode 100644
index 0000000..2c8db02
--- /dev/null
+++ b/ard-work/src/main/resources/mapper/ArdMediaMapper.xml
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ard.work.mapper.ArdMediaMapper">
+
+ <!-- 结果映射 -->
+ <resultMap id="ArdMediaResult" type="com.ard.work.domain.entity.ArdMedia">
+ <result property="id" column="id"/>
+ <result property="taskId" column="task_id"/>
+ <result property="mediaType" column="media_type"/>
+ <result property="fileSize" column="file_size"/>
+ <result property="fileMd5" column="file_md5"/>
+ <result property="mediaUrl" column="media_url"/>
+ <result property="sourceUrl" column="source_url"/>
+ <result property="createTime" column="create_time"/>
+ </resultMap>
+
+ <!-- 查询媒体列表:根据条件动态生成SQL -->
+ <select id="selectArdMedia" resultMap="ArdMediaResult">
+ SELECT id, task_id, media_type, file_size, file_md5, media_url, source_url,create_time
+ FROM ard_media
+ <where>
+ <!-- 动态查询条件:任务ID -->
+ <if test="taskId != null">AND task_id = #{taskId}</if>
+
+ <!-- 动态查询条件:媒体类型 -->
+ <if test="mediaType != null">AND media_type = #{mediaType}</if>
+
+ <!-- 动态查询条件:文件大小 -->
+ <if test="fileSize != null">AND file_size = #{fileSize}</if>
+
+ <!-- 动态查询条件:文件MD5 -->
+ <if test="fileMd5 != null">AND file_md5 = #{fileMd5}</if>
+
+ <!-- 动态查询条件:媒体URL -->
+ <if test="mediaUrl != null">AND media_url = #{mediaUrl}</if>
+
+ <!-- 动态查询条件:时间戳 -->
+ <if test="createTime != null">AND create_time = #{createTime}</if>
+ </where>
+ </select>
+
+ <!-- 根据任务ID查询媒体 -->
+ <select id="selectArdMediaByTaskId" resultMap="ArdMediaResult">
+ SELECT id, task_id, media_type, file_size, file_md5, media_url, create_time
+ FROM ard_media
+ WHERE task_id = #{taskId}
+ </select>
+
+ <!-- 插入媒体记录 -->
+ <insert id="insertArdMedia" parameterType="com.ard.work.domain.entity.ArdMedia">
+ INSERT INTO ard_media
+ <trim prefix="(" suffix=")" suffixOverrides=",">
+ <if test="id != null">id,</if>
+ <if test="taskId != null">task_id,</if>
+ <if test="mediaType != null">media_type,</if>
+ <if test="fileSize != null">file_size,</if>
+ <if test="fileMd5 != null">file_md5,</if>
+ <if test="mediaUrl != null">media_url,</if>
+ <if test="sourceUrl != null">source_url,</if>
+ <if test="createTime != null">create_time,</if>
+ </trim>
+ <trim prefix="values (" suffix=")" suffixOverrides=",">
+ <if test="id != null">#{id},</if>
+ <if test="taskId != null">#{taskId},</if>
+ <if test="mediaType != null">#{mediaType},</if>
+ <if test="fileSize != null">#{fileSize},</if>
+ <if test="fileMd5 != null">#{fileMd5},</if>
+ <if test="mediaUrl != null">#{mediaUrl},</if>
+ <if test="sourceUrl != null">#{sourceUrl},</if>
+ <if test="createTime != null">#{createTime},</if>
+ </trim>
+ </insert>
+
+
+ <!-- 批量插入媒体记录 -->
+ <insert id="insertArdMediaList" parameterType="java.util.List">
+ INSERT INTO ard_media
+ <trim prefix="(" suffix=")" suffixOverrides=",">
+ <if test="list != null and !list.isEmpty()">
+ <foreach item="item" collection="list" separator=",">
+ <trim prefix="(" suffix=")" suffixOverrides=",">
+ <if test="item.taskId != null">task_id,</if>
+ <if test="item.mediaType != null">media_type,</if>
+ <if test="item.fileSize != null">file_size,</if>
+ <if test="item.fileMd5 != null">file_md5,</if>
+ <if test="item.mediaUrl != null">media_url,</if>
+ <if test="item.sourceUrl != null">source_url,</if>
+ <if test="item.createTime != null">create_time,</if>
+ </trim>
+ </foreach>
+ </if>
+ </trim>
+
+ <trim prefix="values " suffix=")" suffixOverrides=",">
+ <foreach item="item" collection="list" separator=",">
+ <trim prefix="(" suffix=")" suffixOverrides=",">
+ <if test="item.taskId != null">#{item.taskId},</if>
+ <if test="item.mediaType != null">#{item.mediaType},</if>
+ <if test="item.fileSize != null">#{item.fileSize},</if>
+ <if test="item.fileMd5 != null">#{item.fileMd5},</if>
+ <if test="item.mediaUrl != null">#{item.mediaUrl},</if>
+ <if test="item.sourceUrl != null">#{item.sourceUrl},</if>
+ <if test="item.createTime != null">#{item.createTime},</if>
+ </trim>
+ </foreach>
+ </trim>
+ </insert>
+
+
+ <!-- 更新媒体记录 -->
+ <update id="updateArdMedia" parameterType="com.ard.work.domain.entity.ArdMedia">
+ UPDATE ard_media
+ <set>
+ <if test="mediaType != null">media_type = #{mediaType},</if>
+ <if test="fileSize != null">file_size = #{fileSize},</if>
+ <if test="fileMd5 != null">file_md5 = #{fileMd5},</if>
+ <if test="mediaUrl != null">media_url = #{mediaUrl},</if>
+ <if test="createTime != null">create_time = #{createTime},</if>
+ </set>
+ WHERE id = #{id}
+ </update>
+
+ <!-- 删除媒体记录 -->
+ <delete id="deleteArdMediaById" parameterType="Integer">
+ DELETE FROM ard_media WHERE id = #{id}
+ </delete>
+
+ <!-- 批量删除媒体记录 -->
+ <delete id="deleteArdMediaByIds" parameterType="java.util.List">
+ DELETE FROM ard_media WHERE id IN
+ <foreach item="id" collection="list" open="(" separator="," close=")">
+ #{id}
+ </foreach>
+ </delete>
+
+ <delete id="deleteArdMediaByTaskId" parameterType="java.lang.Integer">
+ DELETE FROM ard_media WHERE task_id = #{taskId}
+ </delete>
+
+</mapper>
diff --git a/ard-work/src/main/resources/mapper/ArdServerInfoMapper.xml b/ard-work/src/main/resources/mapper/ArdServerInfoMapper.xml
index 5f5a58a..ae58db9 100644
--- a/ard-work/src/main/resources/mapper/ArdServerInfoMapper.xml
+++ b/ard-work/src/main/resources/mapper/ArdServerInfoMapper.xml
@@ -148,4 +148,10 @@
#{id}
</foreach>
</delete>
+
+ <select id="getServerIdsList" resultType="String">
+ SELECT id
+ FROM ard_server
+ where server_status = "1"
+ </select>
</mapper>
\ No newline at end of file
--
Gitblit v1.9.3