From e7af0cdd75430765fcb880fa32391847eb6e615d Mon Sep 17 00:00:00 2001
From: liusuyi <1951119284@qq.com>
Date: Mon, 29 Dec 2025 14:40:59 +0800
Subject: [PATCH] 优化
---
ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskServiceImpl.java | 473 +++++------------------------------------------------------
1 files changed, 40 insertions(+), 433 deletions(-)
diff --git a/ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskServiceImpl.java b/ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskServiceImpl.java
index 4ab7d19..ff1016d 100644
--- a/ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskServiceImpl.java
+++ b/ard-work/src/main/java/com/ard/work/service/impl/ArdFlightTaskServiceImpl.java
@@ -4,47 +4,23 @@
import com.ard.common.core.domain.entity.SysUser;
import com.ard.common.core.redis.RedisCache;
import com.ard.common.utils.DateUtils;
-import com.ard.common.utils.file.MimeTypeUtils;
-import com.ard.common.utils.uuid.IdUtils;
-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.IArdMediaService;
import com.ard.work.service.IArdServerInfoService;
import com.ard.work.service.control.UavControlService;
-import com.ard.work.util.osSelect;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.net.URLConnection;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
import java.util.Date;
import java.util.List;
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Collectors;
@Slf4j
@Service
@@ -53,19 +29,16 @@
@Resource
private ArdFlightTaskMapper ardFlightTaskMapper;
@Resource
- private ArdMediaMapper ardMediaMapper;
- @Resource
private IArdServerInfoService ardServerInfoService;
@Resource
- private TyClient tyClient;
- @Resource
- private OssServiceContext ossServiceContext;
- @Resource
- private ThreadPoolTaskExecutor threadPoolTaskExecutor; // 使用线程池执行异步任务
- @Resource
private UavControlService uavControlService;
- @Autowired
+ @Resource
+ private IArdMediaService ardMediaService;
+ @Resource
private RedisCache redisCache;
+ @Resource
+ private TyClient tyClient;
+
/**
* 查询飞行架次列表
*
@@ -80,7 +53,7 @@
/**
* 同步所有服务的飞行历史
*/
- @Scheduled(fixedDelay = 10000)
+ @Scheduled(fixedDelay = 5000)
public void syncAllFlightHistory() {
List<String> serverIds = ardServerInfoService.getServerIdsList();
for (String serverId : serverIds) {
@@ -97,10 +70,18 @@
return maxStartTime != null ? maxStartTime : new Date(0); // 如果没有数据,返回 Unix 纪元时间作为起点
}
+ // 调用接口获取飞行历史数据
+ private List<BoxHistoryReceiver> getBoxHistory(String serverId, BoxHistoryDTO boxHistoryDTO) {
+ TyHttpCommonReceiver<List<BoxHistoryReceiver>> boxHistory = tyClient.getBoxHistory(serverId, boxHistoryDTO);
+ return boxHistory.getContent();
+ }
+
// 根据上次同步时间同步飞行历史
public void syncFlightHistory(String serverId, Date startTime) {
// 创建查询条件 BoxHistoryDTO,并设置 startTime 作为过滤条件
BoxHistoryDTO boxHistoryDTO = BoxHistoryDTO.builder()
+ .pageIndex(1)
+ .pageSize(20)
.startTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, startTime))
.build();
@@ -121,7 +102,11 @@
ArdFlightTask ardFlightTask = ardFlightTaskMapper.getArdFlightTaskById(boxHistoryReceiver.getTaskId());
if (ardFlightTask == null) {
// 如果不存在,则插入新记录
- log.debug("insert task {}", boxHistoryReceiver.getTaskId());
+ log.info("insert task {}", boxHistoryReceiver.getTaskId());
+ Date endTime = null;
+ if (boxHistoryReceiver.getEndTime() != null) {
+ endTime = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, boxHistoryReceiver.getEndTime());
+ }
// 创建FlightTask实体对象并填充数据
ArdFlightTask flightTask = ArdFlightTask.builder()
.taskId(boxHistoryReceiver.getTaskId())
@@ -134,7 +119,7 @@
.videoPath(boxHistoryReceiver.getVideoPath())
.serverId(serverId)
.startTime(DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, boxHistoryReceiver.getStartTime()))
- .endTime(DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, boxHistoryReceiver.getEndTime()))
+ .endTime(endTime)
.flightMileage(boxHistoryReceiver.getFlightMileage())
.flightDuration(boxHistoryReceiver.getFlightDuration())
.aveSpeed(boxHistoryReceiver.getAveSpeed())
@@ -152,35 +137,37 @@
// 插入新记录
int rows = ardFlightTaskMapper.insertArdFlightTask(flightTask);
if (rows > 0) {
- // 删除旧的媒体记录,防止重复插入
- ardMediaMapper.deleteArdMediaByTaskId(flightTask.getTaskId());
-
// 插入视频
- insertVideoToDatabase(flightTask, boxHistoryReceiver.getVideoPathList());
-
+ ardMediaService.insertVideoToDatabase(flightTask, serverId, boxHistoryReceiver.getBoxSn());
// 插入图片
- insertPhotoToDatabase(flightTask, serverId, boxHistoryReceiver.getBoxSn());
+ ardMediaService.insertPhotoToDatabase(flightTask, serverId, boxHistoryReceiver.getBoxSn());
}
} else {
// 如果存在,则更新记录
- log.debug("Updating task {}", boxHistoryReceiver.getTaskId());
+ log.debug("sync task {}", boxHistoryReceiver.getTaskId());
updateFlightTask(ardFlightTask, boxHistoryReceiver);
- // 增量更新
- updateVideoToDatabase(ardFlightTask, boxHistoryReceiver.getVideoPathList());
- // 增量更新图片
- updatePhotoToDatabase(ardFlightTask, serverId, boxHistoryReceiver.getBoxSn());
-
+ // 同步任务图片
+ ardMediaService.syncPicToDatabase(ardFlightTask, serverId, boxHistoryReceiver.getBoxSn());
+ // 同步任务视频
+ ardMediaService.syncVideoToDatabase(ardFlightTask, serverId, boxHistoryReceiver.getBoxSn());
}
}
+
private void updateFlightTask(ArdFlightTask local, BoxHistoryReceiver remote) {
boolean needUpdate = false;
// endTime 更新(重要!!!)
- Date newEnd = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, remote.getEndTime());
- if (newEnd != null && (local.getEndTime() == null || !local.getEndTime().equals(newEnd))) {
- local.setEndTime(newEnd);
- needUpdate = true;
+ if (remote.getEndTime() != null) {
+ Date newEnd = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, remote.getEndTime());
+ if (local.getEndTime() == null || !local.getEndTime().equals(newEnd)) {
+ local.setEndTime(newEnd);
+ local.setAveSpeed(remote.getAveSpeed());
+ local.setMaxSpeed(remote.getMaxSpeed());
+ local.setFlightDuration(remote.getFlightDuration());
+ local.setFlightMileage(remote.getFlightMileage());
+ needUpdate = true;
+ }
}
// photoCount 更新
@@ -199,386 +186,6 @@
if (needUpdate) {
ardFlightTaskMapper.updateArdFlightTask(local);
- }
- }
-
-
- // 调用接口获取飞行历史数据
- private List<BoxHistoryReceiver> getBoxHistory(String serverId, BoxHistoryDTO boxHistoryDTO) {
- TyHttpCommonReceiver<List<BoxHistoryReceiver>> boxHistory = tyClient.getBoxHistory(serverId, boxHistoryDTO);
- return boxHistory.getContent();
- }
-
- //调用接口获取架次图片
- private List<BoxPhotosReceiver> getBoxPhotos(String serverId, BoxPhotosDTO boxPhotosDTO) {
- TyHttpCommonReceiver<List<BoxPhotosReceiver>> boxPhotos = tyClient.getBoxPhotos(serverId, boxPhotosDTO);
- return boxPhotos.getContent();
- }
-
-
- // 插入视频记录
- private void insertVideoToDatabase(ArdFlightTask flightTask, List<String> videoPathList) {
- if (videoPathList == null || videoPathList.isEmpty()) {
- return;
- }
- String boxSn = flightTask.getBoxSn();
- for (String videoPath : videoPathList) {
- //videoPath = "https://192.168.1.3:9001/record/DBM250974065008/8212fd8e89814d66b6c32f48d05f5101.mp4";
- ArdMedia media = ArdMedia.builder()
- .id(IdUtils.simpleUUID())
- .taskId(flightTask.getTaskId())
- .mediaType(1)
- .sourceUrl(videoPath)
- .fileSize(getFileSizeByUrl(videoPath))
- .build();
-
- // ---- 1. 视频上传(失败不抛异常,返回 null) ----
-
- CompletableFuture<String> videoFuture = CompletableFuture.supplyAsync(() -> {
- try (InputStream inputStream = openUrlInputStream(videoPath, 5000, 10000)) {
- if (inputStream != null) {
- return ossServiceContext.upload(
- "record",
- boxSn + "/" + media.getId() + ".mp4",
- inputStream,
- MimeTypeUtils.VIDEO_MP4
- );
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }, threadPoolTaskExecutor);
- // ---- 2. 缩略图上传(失败不抛异常,返回 null) ----
-
- CompletableFuture<String> thumbFuture = CompletableFuture.supplyAsync(() -> {
- try {
- try (ByteArrayInputStream thumbStream = generateThumbnail(videoPath, 1, 200)) {
- if (thumbStream != null) {
- return ossServiceContext.upload(
- "record",
- boxSn + "/" + media.getId() + ".jpg",
- thumbStream,
- MimeTypeUtils.IMAGE_JPEG
- );
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }, threadPoolTaskExecutor);
-
- // 两个完成后写数据库(任意失败不阻断流程)
- videoFuture.thenCombine(thumbFuture, (vUrl, tUrl) -> {
- media.setMediaUrl(vUrl);
- media.setThumbnailUrl(tUrl);
- media.setCreateTime(new Date());
- return media;
- }).thenAcceptAsync(ardMediaMapper::insertArdMedia, threadPoolTaskExecutor);
- }
- }
-
- private void updateVideoToDatabase(ArdFlightTask flightTask, List<String> videoPathList) {
- if (videoPathList == null) {
- return;
- }
- // 需要插入新的视频
- List<ArdMedia> existingVideos = ardMediaMapper.selectArdMediaByTaskIdAndType(flightTask.getTaskId(), 1);
- Integer count = existingVideos.size();//获取本地库视频数量
- int size = videoPathList.size();//获取接口返回的视频数量
- if (count != null && size > count) {
- log.info("任务【{}】录像数量不一致,需要更新数据库", flightTask.getTaskId());
-
- // 提取现有的视频路径
- List<String> existingVideoPaths = existingVideos.stream()
- .map(ArdMedia::getSourceUrl) // 获取每个视频的 URL
- .collect(Collectors.toList());
-
- // 从接口返回的视频路径中找出新的视频
- List<String> newVideos = videoPathList.stream()
- .filter(videoPath -> !existingVideoPaths.contains(videoPath)) // 过滤出新的视频
- .collect(Collectors.toList());
- if (!newVideos.isEmpty()) {
- String boxSn = flightTask.getBoxSn();
- // 插入新的视频记录
- for (String videoPath : newVideos) {
- ArdMedia ardMedia = ArdMedia.builder()
- .id(IdUtils.simpleUUID())
- .taskId(flightTask.getTaskId())
- .mediaType(1) // 1表示视频
- .fileSize(getFileSizeByUrl(videoPath))
- .sourceUrl(videoPath)
- .build();
- // ---- 1. 视频上传(失败不抛异常,返回 null) ----
- CompletableFuture<String> videoFuture = CompletableFuture.supplyAsync(() -> {
- try (InputStream inputStream = openUrlInputStream(videoPath, 5000, 10000)) {
- if (inputStream != null) {
- return ossServiceContext.upload(
- "record",
- boxSn + "/" + ardMedia.getId() + ".mp4",
- inputStream,
- MimeTypeUtils.VIDEO_MP4
- );
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }, threadPoolTaskExecutor);
- // ---- 2. 缩略图上传(失败不抛异常,返回 null) ----
- CompletableFuture<String> thumbFuture = CompletableFuture.supplyAsync(() -> {
- try {
- try (ByteArrayInputStream thumbStream = generateThumbnail(videoPath, 1, 200)) {
- if (thumbStream != null) {
- return ossServiceContext.upload(
- "record",
- boxSn + "/" + ardMedia.getId() + ".jpg",
- thumbStream,
- MimeTypeUtils.IMAGE_JPEG
- );
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }, threadPoolTaskExecutor);
- // 两个完成后写数据库(任意失败不阻断流程)
- videoFuture.thenCombine(thumbFuture, (vUrl, tUrl) -> {
- ardMedia.setMediaUrl(vUrl);
- ardMedia.setThumbnailUrl(tUrl);
- ardMedia.setCreateTime(new Date());
- return ardMedia;
- }).thenAcceptAsync(ardMediaMapper::insertArdMedia, threadPoolTaskExecutor);
- }
- // 更新任务的视频数量
- flightTask.setVideoCount(flightTask.getVideoCount() + newVideos.size());
- ardFlightTaskMapper.updateArdFlightTask(flightTask);
- }
- }
- }
-
- // 插入图片记录
- private void insertPhotoToDatabase(ArdFlightTask flightTask, String serverId, String boxSn) {
- // 查询图片
- BoxPhotosDTO boxPhotosDTO = new BoxPhotosDTO();
- boxPhotosDTO.setTaskId(flightTask.getTaskId());
- boxPhotosDTO.setBoxSn(boxSn);
- boxPhotosDTO.setPageIndex(1);
- boxPhotosDTO.setPageSize(500);
- List<BoxPhotosReceiver> photoList = getBoxPhotos(serverId, boxPhotosDTO);
- if (photoList != null && !photoList.isEmpty()) {
- addPhotos(flightTask, photoList);
- }
- }
-
- private void updatePhotoToDatabase(ArdFlightTask flightTask, String serverId, String boxSn) {
-
- // 获取本地数据库中已存在的图片记录(类型为 0 表示图片)
- List<ArdMedia> existingPhotos = ardMediaMapper.selectArdMediaByTaskIdAndType(flightTask.getTaskId(), 0);
- int count = existingPhotos.size(); //获取本地库图片数量
- // 查询图片
- BoxPhotosDTO boxPhotosDTO = BoxPhotosDTO.builder()
- .taskId(flightTask.getTaskId())
- .boxSn(boxSn)
- .pageIndex(1)
- .pageSize(500)
- .build();
- TyHttpCommonReceiver<List<BoxPhotosReceiver>> boxPhotos = tyClient.getBoxPhotos(serverId, boxPhotosDTO);
- List<BoxPhotosReceiver> photoList = boxPhotos.getContent();
- int size = photoList.size();
-
- if (size > count) {
- log.info("任务【{}】图片数量不一致,需要更新数据库", flightTask.getTaskId());
- // 需要插入新的视频
- // 提取现有的图片路径(根据 imgUrl 来判断是否重复)
- List<String> existingPhotoUrls = existingPhotos.stream()
- .map(ArdMedia::getSourceUrl) // 提取 ArdMedia 中的图片 URL
- .collect(Collectors.toList());
-
- // 筛选出 photoList 中没有出现在 existingPhotos 中的新图片
- List<BoxPhotosReceiver> newPhotos = photoList.stream()
- .filter(photo -> !existingPhotoUrls.contains(photo.getImgUrl())) // 过滤出新图片
- .collect(Collectors.toList());
- if (!newPhotos.isEmpty()) {
- // 插入新的视频记录
- addPhotos(flightTask, newPhotos);
-
- // 更新任务的视频数量
- flightTask.setPhotoCount(flightTask.getPhotoCount() + newPhotos.size());
- ardFlightTaskMapper.updateArdFlightTask(flightTask);
- }
- }
- }
-
- private void addPhotos(ArdFlightTask flightTask, List<BoxPhotosReceiver> photoList) {
- String boxSn = flightTask.getBoxSn();
- for (BoxPhotosReceiver photo : photoList) {
- ArdMedia ardMedia = ArdMedia.builder()
- .id(IdUtils.simpleUUID())
- .taskId(flightTask.getTaskId())
- .mediaType(0) // 0表示图片
- .fileSize(photo.getFileSize())
- .fileMd5(photo.getFileMd5())
- .sourceUrl(photo.getImgUrl())
- .photoId(photo.getPhotoId())
- .longitude(photo.getLng())
- .latitude(photo.getLat())
- .height(photo.getHeight())
- .captureTime(DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, photo.getTimeStamp()))
- .build();
- // 异步上传文件到OSS,并在上传完成后插入数据库
- CompletableFuture.supplyAsync(() -> {
- try (InputStream inputStream = openUrlInputStream(photo.getImgUrl(), 5000, 10000)) {
- if (inputStream != null) {
- return ossServiceContext.upload(
- "pic",
- boxSn + "/" + ardMedia.getId() + ".jpg",
- inputStream,
- MimeTypeUtils.IMAGE_JPG
- );
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }, threadPoolTaskExecutor)
- .thenAccept(url -> {
- ardMedia.setMediaUrl(url);
- ardMedia.setCreateTime(new Date());
- ardMediaMapper.insertArdMedia(ardMedia);
- });
- }
- }
-
- // 获取文件大小
- private long getFileSizeByUrl(String fileUrl) {
- try {
- URL url = new URL(fileUrl);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setRequestMethod("HEAD");
- conn.connect();
- return conn.getContentLengthLong(); // 返回字节大小
- } catch (Exception e) {
- return -1;
- }
- }
-
- // 生成视频缩略图
- public ByteArrayInputStream generateThumbnail(
- String videoFile,
- int skipSeconds,
- int targetWidth) {
- String ffmpegPath = "";
- if (osSelect.isWindows()) {
- ffmpegPath = "ffmpeg";
- } else if (osSelect.isLinux()) {
- ffmpegPath = "/usr/local/ffmpeg/bin/ffmpeg";
- }
- try {
- List<String> command = new ArrayList<>();
- command.add(ffmpegPath);
-
- command.add("-timeout");
- command.add("3000000");
- command.add("-rw_timeout");
- command.add("3000000");
-
- command.add("-ss");
- command.add(String.format("00:00:%02d", skipSeconds));
- command.add("-i");
- command.add(videoFile);
- command.add("-vframes");
- command.add("1");
-
- // 等比缩放
- command.add("-vf");
- command.add("scale=" + targetWidth + ":-1");
-
- // **确保输出 JPEG**
- command.add("-f");
- command.add("mjpeg"); // 关键点:输出格式固定为 JPEG
- command.add("-vcodec");
- command.add("mjpeg");
-
- // 输出到管道
- command.add("pipe:1");
-
- // ⭐ 打印最终命令(可复制)
- log.info("ffmpeg command: {}", String.join(" ", command));
-
- ProcessBuilder pb = new ProcessBuilder(command);
- pb.redirectErrorStream(false);
- Process process = pb.start();
-
- // 读取 FFmpeg 输出(JPEG 数据)到内存
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try (InputStream is = process.getInputStream()) {
- byte[] buffer = new byte[8192];
- int len;
- while ((len = is.read(buffer)) != -1) {
- baos.write(buffer, 0, len);
- }
- }
-
- int exitCode = process.waitFor();
- if (exitCode != 0) {
- throw new RuntimeException("FFmpeg 执行失败,退出码: " + exitCode);
- }
-
- return new ByteArrayInputStream(baos.toByteArray());
-
- } catch (IOException | InterruptedException e) {
- throw new RuntimeException("FFmpeg 生成缩略图失败", e);
- }
- }
-
- /**
- * 将 URL 转成 InputStream
- *
- * @param fileUrl 文件 URL
- * @param connectTimeoutMillis 连接超时(毫秒)
- * @param readTimeoutMillis 读取超时(毫秒)
- * @return InputStream,如果失败返回 null
- */
- public InputStream openUrlInputStream(String fileUrl, int connectTimeoutMillis, int readTimeoutMillis) {
- try {
- URL url = new URL(fileUrl);
-
- // 支持 HTTPS 信任所有证书(如果需要访问自签名证书)
- if ("https".equalsIgnoreCase(url.getProtocol())) {
- TrustManager[] trustAllCerts = new TrustManager[]{
- new X509TrustManager() {
- @Override
- public void checkClientTrusted(X509Certificate[] chain, String authType) {
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] chain, String authType) {
- }
-
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- return null;
- }
- }
- };
- SSLContext sc = SSLContext.getInstance("SSL");
- sc.init(null, trustAllCerts, new java.security.SecureRandom());
- HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
- HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
- }
-
- URLConnection connection = url.openConnection();
- connection.setConnectTimeout(connectTimeoutMillis);
- connection.setReadTimeout(readTimeoutMillis);
-
- return connection.getInputStream();
-
- } catch (Exception e) {
- e.printStackTrace();
- return null;
}
}
--
Gitblit v1.9.3