diff --git a/backend/src/main/java/com/yfd/platform/config/MyMetaObjectHandler.java b/backend/src/main/java/com/yfd/platform/config/MyMetaObjectHandler.java index 5510e43..2459da8 100644 --- a/backend/src/main/java/com/yfd/platform/config/MyMetaObjectHandler.java +++ b/backend/src/main/java/com/yfd/platform/config/MyMetaObjectHandler.java @@ -2,6 +2,7 @@ package com.yfd.platform.config; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import com.yfd.platform.utils.SecurityUtils; +import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; @@ -12,6 +13,7 @@ import java.util.Date; * 用于处理 @TableField(fill = FieldFill.INSERT/UPDATE) 注解 */ @Component +@Slf4j public class MyMetaObjectHandler implements MetaObjectHandler { @@ -35,7 +37,7 @@ public class MyMetaObjectHandler implements MetaObjectHandler { // 自动填充更新时间 this.strictInsertFill(metaObject, "updatedBy", String.class, userId); } catch (Exception e) { - e.printStackTrace(); + log.info("message{}",e.getMessage()); } } @@ -52,7 +54,7 @@ public class MyMetaObjectHandler implements MetaObjectHandler { // 自动填充更新人 this.strictInsertFill(metaObject, "updatedBy", String.class, userId); } catch (Exception e) { - e.printStackTrace(); + log.info("message{}",e.getMessage()); } } diff --git a/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java b/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java index 5a5d652..1e1a0d5 100644 --- a/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java +++ b/backend/src/main/java/com/yfd/platform/data/controller/FishDraftDataController.java @@ -33,6 +33,8 @@ import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; @@ -137,19 +139,15 @@ public class FishDraftDataController { ImportTask importTask = importTaskService.getById(taskId); String resultJson = importTask.getResultJson(); FishImportResult importResult = null; - log.info("==============批量保存草稿================: {}", taskId); + Map imageFiles = null; + Map videoFiles = null; if (resultJson != null && !resultJson.isEmpty()) { try { importResult = objectMapper.readValue(resultJson, FishImportResult.class); - ZipFileUtil.ZipContent content = new ZipFileUtil.ZipContent(); - content.images = importResult.getImageFiles(); - content.videos = importResult.getVideoFiles(); - log.info("==============processAttachments前================: {}", taskId); - fishImportService.processAttachments(importResult, content); - log.info("==============processAttachments后================: {}", taskId); + imageFiles = importResult.getImageFiles(); + videoFiles = importResult.getVideoFiles(); } catch (Exception e) { e.printStackTrace(); - // ignore parse error } } @@ -169,6 +167,7 @@ public class FishDraftDataController { fishDraftDataList.add(data); } boolean result = fishDraftDataService.saveBatch(fishDraftDataList); + fishImportService.processAttachmentsAsync(fishDraftDataList, imageFiles, videoFiles,importTask.getTempDir()); importTaskService.markSuccess(taskId); return result ? ResponseResult.success("保存成功") : ResponseResult.error("保存失败"); } @@ -392,9 +391,10 @@ public class FishDraftDataController { task.setTempDir(tempDirPath.toString()); importTaskService.save(task); log.info("导入任务已创建: {}", taskId); - + SecurityContext securityContext = SecurityContextHolder.getContext(); CompletableFuture.runAsync(() -> { try { + SecurityContextHolder.setContext(securityContext); log.info("异步开始解析ZIP文件, taskId: {}", taskId); FishImportResult result = fishImportService.parseAndMapZipFromFile( savedZipFile, tempDirPath.toString(), uploadUserId); @@ -413,6 +413,7 @@ public class FishDraftDataController { log.error("异步解析ZIP失败, taskId: {}", taskId, e); importTaskService.markFailed(taskId, "导入失败: " + e.getMessage()); } finally { + SecurityContextHolder.clearContext(); if (savedZipFile.exists()) { savedZipFile.delete(); } 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 bbfccc5..2531588 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 @@ -38,6 +38,10 @@ public class AttachmentUploadService { @Value("${attachment.video-url}") private String videoUrl; + @Value("${attachment.delete-url}") + private String deleteUrl; +// private static final String DELETE_URL = "https://211.99.26.225:12125/FileDelete"; + private static final ExecutorService UPLOAD_EXECUTOR = new ThreadPoolExecutor( 5, 10, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100), new ThreadPoolExecutor.CallerRunsPolicy() @@ -313,7 +317,55 @@ public class AttachmentUploadService { } } - private static final String DELETE_URL = "https://211.99.26.225:12125/FileDelete"; + + +// public boolean deleteFile(String attachmentId) { +// if (attachmentId == null || attachmentId.isEmpty()) { +// log.warn("附件ID为空"); +// return false; +// } +// +// try { +// TrustManager[] trustAllCerts = new TrustManager[]{ +// new X509TrustManager() { +// public void checkClientTrusted(X509Certificate[] chain, String authType) {} +// public void checkServerTrusted(X509Certificate[] chain, String authType) {} +// public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } +// } +// }; +// +// SSLContext sc = SSLContext.getInstance("TLS"); +// sc.init(null, trustAllCerts, new SecureRandom()); +// +// HttpClient secureClient = HttpClient.newBuilder() +// .sslContext(sc) +// .build(); +// +// String formData = "fileId=" + attachmentId; +// +// HttpRequest request = HttpRequest.newBuilder() +// .uri(URI.create(deleteUrl)) +// .header("Content-Type", "application/x-www-form-urlencoded") +// .header("token", token) +// .POST(HttpRequest.BodyPublishers.ofString(formData)) +// .build(); +// +// HttpResponse response = secureClient.send(request, HttpResponse.BodyHandlers.ofString()); +// +// if (response.statusCode() == 200) { +// String responseBody = response.body(); +// return parseDeleteResult(responseBody); +// } else { +// log.error("删除附件失败: {}, 状态码: {}", attachmentId, response.statusCode()); +// return false; +// } +// } catch (Exception e) { +// log.error("删除附件过程中发生异常: {}", attachmentId, e); +// return false; +// } +// } + + public boolean deleteFile(String attachmentId) { if (attachmentId == null || attachmentId.isEmpty()) { @@ -322,31 +374,16 @@ public class AttachmentUploadService { } try { - TrustManager[] trustAllCerts = new TrustManager[]{ - new X509TrustManager() { - public void checkClientTrusted(X509Certificate[] chain, String authType) {} - public void checkServerTrusted(X509Certificate[] chain, String authType) {} - public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } - } - }; - - SSLContext sc = SSLContext.getInstance("TLS"); - sc.init(null, trustAllCerts, new SecureRandom()); - - HttpClient secureClient = HttpClient.newBuilder() - .sslContext(sc) - .build(); - String formData = "fileId=" + attachmentId; HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(DELETE_URL)) + .uri(URI.create(deleteUrl)) .header("Content-Type", "application/x-www-form-urlencoded") .header("token", token) .POST(HttpRequest.BodyPublishers.ofString(formData)) .build(); - HttpResponse response = secureClient.send(request, HttpResponse.BodyHandlers.ofString()); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() == 200) { String responseBody = response.body(); @@ -361,6 +398,7 @@ public class AttachmentUploadService { } } + private boolean parseDeleteResult(String jsonResponse) { if (jsonResponse == null || jsonResponse.isEmpty()) { return false; diff --git a/backend/src/main/java/com/yfd/platform/data/service/IFishImportService.java b/backend/src/main/java/com/yfd/platform/data/service/IFishImportService.java index 339c21a..c78bdc5 100644 --- a/backend/src/main/java/com/yfd/platform/data/service/IFishImportService.java +++ b/backend/src/main/java/com/yfd/platform/data/service/IFishImportService.java @@ -51,4 +51,9 @@ public interface IFishImportService { boolean validateFpssBelongsToStation(String fpssCode, String stationCode); void processAttachments(FishImportResult result, ZipFileUtil.ZipContent zipContent); + + void processAttachmentsAsync(java.util.List dataList, + java.util.Map imageFiles, + java.util.Map videoFiles, + String tempDir); } \ 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 3f7b6c2..0228d07 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 @@ -1,5 +1,6 @@ package com.yfd.platform.data.service.impl; +import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.yfd.platform.data.domain.FishDraftData; @@ -8,6 +9,7 @@ import com.yfd.platform.data.domain.FishImportResult; import com.yfd.platform.data.domain.SysUserDataScope; import com.yfd.platform.data.mapper.SysUserDataScopeMapper; import com.yfd.platform.data.service.AttachmentUploadService; +import com.yfd.platform.data.service.IFishDraftDataService; import com.yfd.platform.data.service.IFishImportService; import com.yfd.platform.data.utils.ZipFileUtil; import com.yfd.platform.env.domain.*; @@ -19,6 +21,8 @@ import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; @@ -31,6 +35,7 @@ import java.math.BigDecimal; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; +import java.util.concurrent.CompletableFuture; @Service @Slf4j @@ -63,6 +68,9 @@ public class FishImportServiceImpl implements IFishImportService { @Resource private AttachmentUploadService attachmentUploadService; + @Resource + private IFishDraftDataService fishDraftDataService; + @Resource private SysUserDataScopeMapper userDataScopeMapper; @@ -131,12 +139,12 @@ public class FishImportServiceImpl implements IFishImportService { } @Override - public FishImportResult parseAndMapExcel(FishImportRequest request, InputStream inputStream,String userId) { + public FishImportResult parseAndMapExcel(FishImportRequest request, InputStream inputStream, String userId) { FishImportResult result = new FishImportResult(); try (Workbook workbook = new XSSFWorkbook(inputStream)) { Sheet sheet = workbook.getSheetAt(0); - return parseSheet(sheet, result,userId); + return parseSheet(sheet, result, userId); } catch (IOException e) { result.setSummary("Excel文件解析失败: " + e.getMessage()); return result; @@ -144,13 +152,13 @@ public class FishImportServiceImpl implements IFishImportService { } @Override - public FishImportResult parseAndMapExcelFromPath(FishImportRequest request,String userId) { + public FishImportResult parseAndMapExcelFromPath(FishImportRequest request, String userId) { FishImportResult result = new FishImportResult(); try (InputStream inputStream = request.getFilePath().startsWith("http") ? new java.net.URL(request.getFilePath()).openStream() : new java.io.FileInputStream(request.getFilePath())) { - return parseAndMapExcel(request, inputStream,userId); + return parseAndMapExcel(request, inputStream, userId); } catch (IOException e) { result.setSummary("读取文件失败: " + e.getMessage()); return result; @@ -175,7 +183,7 @@ public class FishImportServiceImpl implements IFishImportService { continue; } - FishImportResult.FishImportRow importRow = parseRow(result, row, columnIndexMap, i,uploadUserId); + FishImportResult.FishImportRow importRow = parseRow(result, row, columnIndexMap, i, uploadUserId); result.setTotalCount(result.getTotalCount() + 1); if (importRow.getData() != null && importRow.getWarnings().isEmpty()) { result.addSuccessRow(importRow); @@ -191,7 +199,7 @@ public class FishImportServiceImpl implements IFishImportService { return result; } - private FishImportResult.FishImportRow parseRow(FishImportResult result, Row row, Map columnIndexMap, int rowIndex,String userId) { + private FishImportResult.FishImportRow parseRow(FishImportResult result, Row row, Map columnIndexMap, int rowIndex, String userId) { FishImportResult.FishImportRow importRow = new FishImportResult.FishImportRow(rowIndex); FishDraftData data = new FishDraftData(); data.setId(UUID.randomUUID().toString()); @@ -496,10 +504,10 @@ public class FishImportServiceImpl implements IFishImportService { data.setStcd(cellValue.trim()); data.setStnm(cellValue.trim()); } else { - if(directBHSet.contains(stcd)){ + if (directBHSet.contains(stcd)) { data.setStnm(cellValue.trim()); data.setStcd(stcd); - }else { + } else { importRow.getWarnings().add("stcd"); data.setStcd(cellValue.trim()); data.setStnm(cellValue.trim()); @@ -1199,7 +1207,7 @@ public class FishImportServiceImpl implements IFishImportService { result.setVideoFiles(zipContent.videos); try (Workbook workbook = new XSSFWorkbook(new FileInputStream(zipContent.excelFilePath))) { Sheet sheet = workbook.getSheetAt(0); - result = parseSheet(sheet, result,uploadUserId); + result = parseSheet(sheet, result, uploadUserId); } result.setExcelFileName(zipContent.excelFileName); result.setExcelFilePath(zipContent.excelFilePath); @@ -1241,7 +1249,7 @@ public class FishImportServiceImpl implements IFishImportService { result.setVideoFiles(zipContent.videos); try (Workbook workbook = new XSSFWorkbook(new FileInputStream(zipContent.excelFilePath))) { Sheet sheet = workbook.getSheetAt(0); - result = parseSheet(sheet, result,uploadUserId); + result = parseSheet(sheet, result, uploadUserId); } result.setExcelFileName(zipContent.excelFileName); result.setExcelFilePath(zipContent.excelFilePath); @@ -1283,6 +1291,118 @@ public class FishImportServiceImpl implements IFishImportService { } } + @Override + public void processAttachmentsAsync(List dataList, + Map imageFiles, + Map videoFiles, + String tempDir) { + if (dataList == null || dataList.isEmpty()) { + return; + } + List> futures = new ArrayList<>(); + SecurityContext securityContext = SecurityContextHolder.getContext(); + for (FishDraftData data : dataList) { + CompletableFuture future = CompletableFuture.runAsync(() -> { + try { + SecurityContextHolder.setContext(securityContext); + String vdpth = data.getVdpth(); + String picpth = data.getPicpth(); + + if(StrUtil.isBlank(vdpth)||StrUtil.isBlank(picpth)){ + log.error("数据不完整, 忽略处理"); + return; + } + if (StringUtils.hasText(vdpth) && videoFiles != null && !videoFiles.isEmpty()) { + String uploadedVdpth = uploadVideoFilesAsync(vdpth, videoFiles); + if (uploadedVdpth != null) { + data.setVdpth(uploadedVdpth); + } + } + + if (StringUtils.hasText(picpth) && imageFiles != null && !imageFiles.isEmpty()) { + String uploadedPicpth = uploadImageFilesAsync(picpth, imageFiles); + if (uploadedPicpth != null) { + data.setPicpth(uploadedPicpth); + } + } + + fishDraftDataService.updateById(data); + log.info("异步上传附件完成, dataId: {},{},{}", data.getId(), data.getPicpth(), data.getVdpth()); + } catch (Exception e) { + log.error("异步上传附件失败, dataId: {}", data.getId(), e); + } finally { + SecurityContextHolder.clearContext(); + } + }); + futures.add(future); + } + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .thenRun(() -> { + + try { + // del 方法会递归删除目录及其所有内容 + FileUtil.del(tempDir); + } catch (Exception e) { + log.error("删除临时目录失败{}", e.getMessage()); + } + + }) + .exceptionally(ex -> { + log.error("等待异步任务完成时发生异常", ex); + return null; + }); + } + + private String uploadVideoFilesAsync(String videoNames, Map videoMap) { + 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); + } + } catch (Exception e) { + log.error("上传视频失败: {}", fileName, e); + } + } + } + + return attachmentIds.isEmpty() ? videoNames : String.join(",", attachmentIds); + } + + private String uploadImageFilesAsync(String imageNames, Map imageMap) { + 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); + } + } catch (Exception e) { + log.error("上传图片失败: {}", fileName, e); + } + } + } + + return attachmentIds.isEmpty() ? imageNames : String.join(",", attachmentIds); + } + private String processVideoAttachments(FishImportResult.FishImportRow importRow, String videoNames, Map videoMap) { if (videoNames == null || videoNames.isEmpty() || videoMap == null || videoMap.isEmpty()) { return videoNames; @@ -1301,9 +1421,9 @@ public class FishImportServiceImpl implements IFishImportService { fileMap.put("name", fileName); if (actualPath != null) { try { - log.info("开始上传视频文件: {}" ,actualPath); + log.info("开始上传视频文件: {}", actualPath); String attachmentId = attachmentUploadService.uploadFileAndGetId(actualPath); - log.info("开始上传视频文件后:{}attachmentId{} " ,actualPath,attachmentId); + log.info("开始上传视频文件后:{}attachmentId{} ", actualPath, attachmentId); if (attachmentId != null) { attachmentIds.add(attachmentId); fileMap.put("value", attachmentId); @@ -1343,9 +1463,9 @@ public class FishImportServiceImpl implements IFishImportService { String actualPath = findFilePath(fileName, imageMap); if (actualPath != null) { try { - log.info("开始上传图片文件: {}" ,actualPath); + log.info("开始上传图片文件: {}", actualPath); String attachmentId = attachmentUploadService.uploadFileAndGetId(actualPath); - log.info("开始上传图片文件后:{}attachmentId{} " ,actualPath,attachmentId); + log.info("开始上传图片文件后:{}attachmentId{} ", actualPath, attachmentId); if (attachmentId != null) { attachmentIds.add(attachmentId); fileMap.put("value", attachmentId); diff --git a/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java b/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java index 56b84d7..c8cb5f6 100644 --- a/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java +++ b/backend/src/main/java/com/yfd/platform/data/service/impl/ImportTaskServiceImpl.java @@ -140,19 +140,6 @@ public class ImportTaskServiceImpl extends ServiceImpl