diff --git a/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java b/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java index 3dc70417..ec24bfad 100644 --- a/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java +++ b/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java @@ -63,7 +63,8 @@ public class AuthenticationFilter extends OncePerRequestFilter { //GlobalAwardController "/api/global-award/uploads/pdf/init", "/api/global-award/uploads/pdf/chunk", "/api/global-award/uploads/pdf/complete", "/api/global-award/uploads/pdf/status", "/api/global-award/uploads/video/init", "/api/global-award/uploads/video/chunk", "/api/global-award/uploads/video/complete", "/api/global-award/uploads/video/status", - "/api/global-award/contestants/save", "/api/global-award/contestants/by-email", "/api/global-award/checkEmail", "/api/global-award/checkCode","/api/global-award/contestants/export" + "/api/global-award/contestants/save", "/api/global-award/contestants/by-email", "/api/global-award/checkEmail", "/api/global-award/checkCode","/api/global-award/contestants/export", + "/api/global-award/contestants/export/files" ); @Override diff --git a/src/main/java/com/ai/da/controller/GlobalAwardController.java b/src/main/java/com/ai/da/controller/GlobalAwardController.java index 2206dc4d..e36a7b77 100644 --- a/src/main/java/com/ai/da/controller/GlobalAwardController.java +++ b/src/main/java/com/ai/da/controller/GlobalAwardController.java @@ -175,6 +175,13 @@ public class GlobalAwardController { response.getOutputStream().flush(); } + @PostMapping("/contestants/export/files") + @ApiOperation(value = "导出参赛者文件到本地", notes = "根据参赛者编号范围导出PDF和视频文件到本地temp/uploads/contestants目录") + public Response exportContestantFiles(@ApiParam(value = "参赛者文件导出请求", required = true) @RequestBody ContestantExportRequest request) throws Exception { + int exportedCount = globalAwardService.exportContestantFiles(request.getMinContestantNumber(), request.getMaxContestantNumber()); + return Response.success(exportedCount); + } + } diff --git a/src/main/java/com/ai/da/service/GlobalAwardService.java b/src/main/java/com/ai/da/service/GlobalAwardService.java index b21cfc36..5dcde74f 100644 --- a/src/main/java/com/ai/da/service/GlobalAwardService.java +++ b/src/main/java/com/ai/da/service/GlobalAwardService.java @@ -31,6 +31,14 @@ public interface GlobalAwardService { * 将参赛者列表导出并保存到服务端本地目录(使用服务配置的 uploadDir/exports) */ void saveContestantsToLocal() throws Exception; + + /** + * 根据参赛者编号范围导出参赛者文件到本地目录 + * @param minContestantNumber 最小参赛者编号 + * @param maxContestantNumber 最大参赛者编号 + * @return 导出的参赛者数量 + */ + int exportContestantFiles(Integer minContestantNumber, Integer maxContestantNumber) throws Exception; } diff --git a/src/main/java/com/ai/da/service/impl/GlobalAwardServiceImpl.java b/src/main/java/com/ai/da/service/impl/GlobalAwardServiceImpl.java index ce0631e5..feff5cc3 100644 --- a/src/main/java/com/ai/da/service/impl/GlobalAwardServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/GlobalAwardServiceImpl.java @@ -479,6 +479,109 @@ public class GlobalAwardServiceImpl implements GlobalAwardService { // 这里推送消息是在接受到视频生成结束后发生的,所以UserContext中没有用户信息 messageCenterService.pushMessage("system", userId); } + + @Override + public int exportContestantFiles(Integer minContestantNumber, Integer maxContestantNumber) throws Exception { + if (minContestantNumber == null || maxContestantNumber == null) { + throw new BusinessException("minContestantNumber and maxContestantNumber are required."); + } + if (minContestantNumber > maxContestantNumber) { + throw new BusinessException("minContestantNumber cannot be greater than maxContestantNumber."); + } + + // 1. 根据contestantNumber范围查询参赛者 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.lambda() + .ge(Contestant::getContestantNumber, minContestantNumber) + .le(Contestant::getContestantNumber, maxContestantNumber) + .orderByAsc(Contestant::getContestantNumber); + List contestants = contestantMapper.selectList(queryWrapper); + + if (contestants.isEmpty()) { + log.info("No contestants found in range [{}, {}]", minContestantNumber, maxContestantNumber); + return 0; + } + + // 2. 创建基础目录 + String baseDir = uploadDir + "/contestants"; + Path basePath = Paths.get(baseDir).toAbsolutePath(); + Files.createDirectories(basePath); + log.info("Base directory created: {}", basePath); + + int exportedCount = 0; + + // 3. 遍历每个参赛者,下载文件 + for (Contestant contestant : contestants) { + Integer contestantNumber = contestant.getContestantNumber(); + if (contestantNumber == null) { + log.warn("Contestant {} has no contestantNumber, skipping", contestant.getId()); + continue; + } + + // 创建参赛者文件夹 + String contestantDir = baseDir + "/" + contestantNumber; + Path contestantPath = Paths.get(contestantDir); + Files.createDirectories(contestantPath); + + // 下载PDF文件 + String pdfPath = contestant.getPdfPath(); + if (StringUtils.isNotBlank(pdfPath)) { + try { + downloadFileFromMinio(pdfPath, contestantPath.toString(), "design.pdf"); + log.info("Downloaded PDF for contestant {}", contestantNumber); + } catch (Exception e) { + log.error("Failed to download PDF for contestant {}: {}", contestantNumber, e.getMessage()); + } + } + + // 下载视频文件 + String videoPath = contestant.getVideoPath(); + if (StringUtils.isNotBlank(videoPath)) { + try { + // 根据路径判断视频格式 + String fileName = videoPath.contains("/") ? + videoPath.substring(videoPath.lastIndexOf("/") + 1) : "video.mp4"; + downloadFileFromMinio(videoPath, contestantPath.toString(), fileName); + log.info("Downloaded video for contestant {}", contestantNumber); + } catch (Exception e) { + log.error("Failed to download video for contestant {}: {}", contestantNumber, e.getMessage()); + } + } + + exportedCount++; + } + + log.info("Exported {} contestants' files to {}", exportedCount, basePath); + return exportedCount; + } + + /** + * 从MinIO下载文件到本地 + * @param minioPath MinIO路径 (格式: bucketName/objectPath) + * @param localDir 本地目录 + * @param fileName 本地文件名 + */ + private void downloadFileFromMinio(String minioPath, String localDir, String fileName) { + if (StringUtils.isBlank(minioPath)) { + return; + } + + // 从路径中提取bucket名称和对象名称 + int index = minioPath.indexOf("/"); + if (index == -1) { + log.warn("Invalid MinIO path: {}", minioPath); + return; + } + + String bucketName = minioPath.substring(0, index); + String objectName = minioPath.substring(index + 1); + + // 构建本地文件完整路径 + Path localFilePath = Paths.get(localDir, fileName); + + // 下载文件 + minioUtil.downloadMinioObjectToLocal(bucketName, objectName, localFilePath.toString()); + } }