From 26db274aaf2e3a2b629afd42dea180133a22ff30 Mon Sep 17 00:00:00 2001 From: tangwei Date: Mon, 27 Apr 2026 19:02:00 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=A2=9E=E5=8A=A0=E6=89=B9=E9=87=8F?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/service/AttachmentUploadService.java | 76 ++++++++++++++++++- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/backend/src/main/java/com/yfd/platform/data/service/AttachmentUploadService.java b/backend/src/main/java/com/yfd/platform/data/service/AttachmentUploadService.java index e34f6b6..146d18a 100644 --- a/backend/src/main/java/com/yfd/platform/data/service/AttachmentUploadService.java +++ b/backend/src/main/java/com/yfd/platform/data/service/AttachmentUploadService.java @@ -3,6 +3,7 @@ package com.yfd.platform.data.service; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; @@ -16,13 +17,21 @@ import java.net.http.HttpResponse; import java.nio.file.Files; import java.security.SecureRandom; import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.*; +import java.util.stream.Collectors; @Slf4j @Service public class AttachmentUploadService { - + // 定义一个固定的线程池用于文件上传(建议根据服务器性能调整核心线程数) + private static final ExecutorService UPLOAD_EXECUTOR = new ThreadPoolExecutor( + 5, 10, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100), + new ThreadPoolExecutor.CallerRunsPolicy() + ); private static final String UPLOAD_URL = "https://211.99.26.225:12125/upload"; private static final String VIDEO_URL = "https://211.99.26.225:12125/upload"; @@ -93,6 +102,69 @@ public class AttachmentUploadService { return null; } } + + + /** + * 多线程批量上传文件 + * @param files 文件列表 + * @return 返回所有上传成功的附件ID列表 + */ + public List uploadFilesConcurrently(List files) { + if (files == null || files.isEmpty()) { + return Collections.emptyList(); + } + + List> futures = files.stream() + .map(file -> CompletableFuture.supplyAsync(() -> { + try { + // 复用单文件上传逻辑 + return uploadFile(file); + } catch (Exception e) { + log.error("线程上传文件失败: {}", file.getName(), e); + return null; + } + }, UPLOAD_EXECUTOR)) + .toList(); + + // 等待所有任务完成并收集结果 + return futures.stream() + .map(CompletableFuture::join) + .filter(id -> id != null) + .collect(Collectors.toList()); + } + + /** + * 批量上传 MultipartFile (调用多线程版本) + */ + public List uploadMultipartFiles(List files) { + if (files == null || files.isEmpty()) { + return Collections.emptyList(); + } + + List tempFiles = new ArrayList<>(); + try { + for (MultipartFile file : files) { + if (!file.isEmpty()) { + File tempFile = File.createTempFile("upload_", file.getOriginalFilename()); + file.transferTo(tempFile); + tempFiles.add(tempFile); + } + } + + if (!tempFiles.isEmpty()) { + return uploadFilesConcurrently(tempFiles); + } + } catch (Exception e) { + log.error("批量处理 MultipartFile 失败", e); + } finally { + for (File tempFile : tempFiles) { + if (tempFile.exists()) tempFile.delete(); + } + } + return Collections.emptyList(); + } + + public String uploadVideo(File file) throws IOException, InterruptedException { return uploadFile(file); }