From 65e669f9d9b970cbe49eb5793044b95cb3ff3927 Mon Sep 17 00:00:00 2001 From: tangwei Date: Mon, 27 Apr 2026 08:22:09 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=A2=9E=E5=8A=A0zip?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=9B=BE=E7=89=87=E7=BB=91=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/service/AttachmentUploadService.java | 176 ++++++++++++++++++ .../service/impl/FishImportServiceImpl.java | 127 ++++++++++++- 2 files changed, 300 insertions(+), 3 deletions(-) create mode 100644 backend/src/main/java/com/yfd/platform/data/service/AttachmentUploadService.java 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 new file mode 100644 index 0000000..5cb5e08 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/data/service/AttachmentUploadService.java @@ -0,0 +1,176 @@ +package com.yfd.platform.data.service; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.file.Files; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Slf4j +@Service +public class AttachmentUploadService { + + 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"; + + private final HttpClient httpClient; + + public AttachmentUploadService() { + this.httpClient = HttpClient.newBuilder() + .build(); + } + + public String uploadFile(File file) throws IOException, InterruptedException { + if (file == null || !file.exists()) { + log.warn("文件不存在或为空: {}", file); + return null; + } + + String boundary = "----FormBoundary" + System.currentTimeMillis(); + byte[] fileContent = Files.readAllBytes(file.toPath()); + String fileName = file.getName(); + + String header = "--" + boundary + "\r\n" + + "Content-Disposition: form-data; name=\"file\"; filename=\"" + fileName + "\"\r\n" + + "Content-Type: application/octet-stream\r\n\r\n"; + String footer = "\r\n--" + boundary + "--\r\n"; + + byte[] body; + if (fileName.toLowerCase().endsWith(".mp4") || fileName.toLowerCase().endsWith(".avi") || + fileName.toLowerCase().endsWith(".mov") || fileName.toLowerCase().endsWith(".wmv")) { + body = new byte[header.getBytes().length + fileContent.length + footer.getBytes().length]; + System.arraycopy(header.getBytes(), 0, body, 0, header.getBytes().length); + System.arraycopy(fileContent, 0, body, header.getBytes().length, fileContent.length); + System.arraycopy(footer.getBytes(), 0, body, header.getBytes().length + fileContent.length, footer.getBytes().length); + } else { + body = new byte[header.getBytes().length + fileContent.length + footer.getBytes().length]; + System.arraycopy(header.getBytes(), 0, body, 0, header.getBytes().length); + System.arraycopy(fileContent, 0, body, header.getBytes().length, fileContent.length); + System.arraycopy(footer.getBytes(), 0, body, header.getBytes().length + fileContent.length, footer.getBytes().length); + } + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(UPLOAD_URL)) + .header("Content-Type", "multipart/form-data; boundary=" + boundary) + .POST(HttpRequest.BodyPublishers.ofByteArray(body)) + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + if (response.statusCode() == 200) { + String responseBody = response.body(); + return parseAttachmentId(responseBody); + } else { + log.error("上传文件失败: {}, 状态码: {}", fileName, response.statusCode()); + return null; + } + } + + public String uploadVideo(File file) throws IOException, InterruptedException { + return uploadFile(file); + } + + public String uploadImage(File file) throws IOException, InterruptedException { + return uploadFile(file); + } + + public Map uploadImages(Map imageMap) { + Map result = new ConcurrentHashMap<>(); + for (Map.Entry entry : imageMap.entrySet()) { + String fileName = entry.getKey(); + String filePath = entry.getValue(); + try { + File file = new File(filePath); + if (file.exists()) { + String attachmentId = uploadFile(file); + if (attachmentId != null) { + result.put(fileName, attachmentId); + log.info("图片上传成功: {} -> {}", fileName, attachmentId); + } else { + log.warn("图片上传返回空ID: {}", fileName); + } + } else { + log.warn("图片文件不存在: {}", filePath); + } + } catch (Exception e) { + log.error("上传图片失败: {}", fileName, e); + } + } + return result; + } + + public Map uploadVideos(Map videoMap) { + Map result = new ConcurrentHashMap<>(); + for (Map.Entry entry : videoMap.entrySet()) { + String fileName = entry.getKey(); + String filePath = entry.getValue(); + try { + File file = new File(filePath); + if (file.exists()) { + String attachmentId = uploadFile(file); + if (attachmentId != null) { + result.put(fileName, attachmentId); + log.info("视频上传成功: {} -> {}", fileName, attachmentId); + } else { + log.warn("视频上传返回空ID: {}", fileName); + } + } else { + log.warn("视频文件不存在: {}", filePath); + } + } catch (Exception e) { + log.error("上传视频失败: {}", fileName, e); + } + } + return result; + } + + private String parseAttachmentId(String jsonResponse) { + if (jsonResponse == null || jsonResponse.isEmpty()) { + return null; + } + + try { + if (jsonResponse.contains("\"message\":")) { + int start = jsonResponse.indexOf("\"message\":\"") + 11; + int end = jsonResponse.indexOf("\"", start); + if (start > 10 && end > start) { + return jsonResponse.substring(start, end); + } + } + if (jsonResponse.contains("\"message\":\"")) { + int start = jsonResponse.indexOf("\"message\":\"") + 11; + int end = jsonResponse.indexOf("\"", start); + if (start > 10 && end > start) { + return jsonResponse.substring(start, end); + } + } + } catch (Exception e) { + log.error("解析附件ID失败: {}", jsonResponse, e); + } + return null; + } + + public String uploadFileAndGetId(String filePath) { + if (filePath == null || filePath.isEmpty()) { + return null; + } + File file = new File(filePath); + if (!file.exists()) { + log.warn("文件不存在: {}", filePath); + return null; + } + try { + return uploadFile(file); + } catch (Exception e) { + log.error("上传文件失败: {}", filePath, e); + return null; + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/data/service/impl/FishImportServiceImpl.java b/backend/src/main/java/com/yfd/platform/data/service/impl/FishImportServiceImpl.java index fb6b136..2d40178 100644 --- a/backend/src/main/java/com/yfd/platform/data/service/impl/FishImportServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/data/service/impl/FishImportServiceImpl.java @@ -3,6 +3,7 @@ package com.yfd.platform.data.service.impl; import com.yfd.platform.data.domain.FishDraftData; import com.yfd.platform.data.domain.FishImportRequest; import com.yfd.platform.data.domain.FishImportResult; +import com.yfd.platform.data.service.AttachmentUploadService; import com.yfd.platform.data.service.IFishImportService; import com.yfd.platform.data.utils.ZipFileUtil; import com.yfd.platform.env.domain.*; @@ -50,6 +51,9 @@ public class FishImportServiceImpl implements IFishImportService { @Resource private ISysDictionaryItemsService sysDictionaryItemsService; + @Resource + private AttachmentUploadService attachmentUploadService; + private static final Map EXCEL_COLUMN_MAPPING = new LinkedHashMap<>(); private static final Map EXCEL_COLUMN_INDEX_MAPPING = new LinkedHashMap<>(); @@ -160,9 +164,8 @@ public class FishImportServiceImpl implements IFishImportService { result.setFailedCount(result.getFailedCount() + 1); } } - - result.setSummary(String.format("共解析%d条数据,成功%d条,失败%d条,未识别字段:%s", - result.getTotalCount(), result.getSuccessCount(), result.getFailedCount(), + result.setSummary(String.format("共解析%d条数据,失败%d条,未识别字段:%s", + result.getSuccessCount(), result.getFailedCount(), unrecognizedHeaders.isEmpty() ? "无" : String.join(", ", unrecognizedHeaders))); return result; @@ -714,6 +717,8 @@ public class FishImportServiceImpl implements IFishImportService { result.setExcelFileName(zipContent.excelFileName); result.setExcelFilePath(zipContent.excelFilePath); + processAttachments(result, zipContent); + result.setSummary(result.getSummary() + String.format("\nZIP内容: 发现%d张图片, %d个视频, 临时目录: %s", zipContent.images.size(), zipContent.videos.size(), zipContent.tempDir)); @@ -726,4 +731,120 @@ public class FishImportServiceImpl implements IFishImportService { return result; } } + + private void processAttachments(FishImportResult result, ZipFileUtil.ZipContent zipContent) { + if (result.getSuccessRows() == null || result.getSuccessRows().isEmpty()) { + return; + } + + for (FishImportResult.FishImportRow importRow : result.getSuccessRows()) { + FishDraftData data = importRow.getData(); + if (data == null) { + continue; + } + + String vdpth = data.getVdpth(); + String picpth = data.getPicpth(); + + if (StringUtils.hasText(vdpth)) { + String uploadedVdpth = processVideoAttachments(vdpth, zipContent.videos); + data.setVdpth(uploadedVdpth); + } + + if (StringUtils.hasText(picpth)) { + String uploadedPicpth = processImageAttachments(picpth, zipContent.images); + data.setPicpth(uploadedPicpth); + } + } + } + + private String processVideoAttachments(String videoNames, Map videoMap) { + if (videoNames == null || videoNames.isEmpty() || videoMap == null || videoMap.isEmpty()) { + return videoNames; + } + + String[] fileNames = videoNames.split(";"); + List attachmentIds = new ArrayList<>(); + + for (String fileName : fileNames) { + fileName = fileName.trim(); + if (fileName.isEmpty()) { + continue; + } + + String actualPath = findFilePath(fileName, videoMap); + if (actualPath != null) { + try { + String attachmentId = attachmentUploadService.uploadFileAndGetId(actualPath); + if (attachmentId != null) { + attachmentIds.add(attachmentId); + } else { + attachmentIds.add(fileName); + } + } catch (Exception e) { + attachmentIds.add(fileName); + } + } else { + attachmentIds.add(fileName); + } + } + + return String.join(",", attachmentIds); + } + + private String processImageAttachments(String imageNames, Map imageMap) { + if (imageNames == null || imageNames.isEmpty() || imageMap == null || imageMap.isEmpty()) { + return imageNames; + } + + String[] fileNames = imageNames.split(";"); + List attachmentIds = new ArrayList<>(); + + for (String fileName : fileNames) { + fileName = fileName.trim(); + if (fileName.isEmpty()) { + continue; + } + + String actualPath = findFilePath(fileName, imageMap); + if (actualPath != null) { + try { + String attachmentId = attachmentUploadService.uploadFileAndGetId(actualPath); + if (attachmentId != null) { + attachmentIds.add(attachmentId); + } else { + attachmentIds.add(fileName); + } + } catch (Exception e) { + attachmentIds.add(fileName); + } + } else { + attachmentIds.add(fileName); + } + } + + return String.join(",", attachmentIds); + } + + private String findFilePath(String fileName, Map fileMap) { + if (fileName == null || fileMap == null || fileMap.isEmpty()) { + return null; + } + + for (Map.Entry entry : fileMap.entrySet()) { + String entryName = entry.getKey(); + if (entryName.equals(fileName) || entryName.endsWith("/" + fileName) || entryName.endsWith("\\" + fileName)) { + return entry.getValue(); + } + String entryFileName = entryName; + int lastSep = Math.max(entryName.lastIndexOf('/'), entryName.lastIndexOf('\\')); + if (lastSep >= 0) { + entryFileName = entryName.substring(lastSep + 1); + } + if (entryFileName.equals(fileName)) { + return entry.getValue(); + } + } + return null; + } } \ No newline at end of file