diff --git a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/DatasetFileApplicationService.java b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/DatasetFileApplicationService.java index 9c9844ca..27712f3f 100644 --- a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/DatasetFileApplicationService.java +++ b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/DatasetFileApplicationService.java @@ -7,6 +7,7 @@ import com.datamate.common.domain.service.FileService; import com.datamate.common.domain.utils.AnalyzerUtils; import com.datamate.common.domain.utils.ArchiveAnalyzer; +import com.datamate.common.domain.utils.CommonUtils; import com.datamate.common.infrastructure.exception.BusinessAssert; import com.datamate.common.infrastructure.exception.BusinessException; import com.datamate.common.infrastructure.exception.CommonErrorCode; @@ -189,7 +190,7 @@ private DatasetFile getDatasetFile(Path path, Map datasetFi } else { DatasetFile exist = datasetFilesMap.get(path.toString()); if (exist == null) { - datasetFile.setId("file-" + datasetFile.getFileName()); + datasetFile.setId(datasetFile.getFileName()); datasetFile.setFileSize(path.toFile().length()); } else { datasetFile = exist; @@ -202,12 +203,21 @@ private DatasetFile getDatasetFile(Path path, Map datasetFi * 获取文件详情 */ @Transactional(readOnly = true) - public DatasetFile getDatasetFile(String datasetId, String fileId) { + public DatasetFile getDatasetFile(Dataset dataset, String fileId) { + if (dataset != null && !CommonUtils.isUUID(fileId) && !fileId.startsWith(".")) { + DatasetFile file = new DatasetFile(); + file.setId(fileId); + file.setFileName(fileId); + file.setDatasetId(dataset.getId()); + file.setFileSize(0L); + file.setFilePath(dataset.getPath() + File.separator + fileId); + return file; + } DatasetFile file = datasetFileRepository.getById(fileId); - if (file == null) { + if (file == null || dataset == null) { throw new IllegalArgumentException("File not found: " + fileId); } - if (!file.getDatasetId().equals(datasetId)) { + if (!file.getDatasetId().equals(dataset.getId())) { throw new IllegalArgumentException("File does not belong to the specified dataset"); } return file; @@ -218,11 +228,13 @@ public DatasetFile getDatasetFile(String datasetId, String fileId) { */ @Transactional public void deleteDatasetFile(String datasetId, String fileId) { - DatasetFile file = getDatasetFile(datasetId, fileId); Dataset dataset = datasetRepository.getById(datasetId); + DatasetFile file = getDatasetFile(dataset, fileId); dataset.setFiles(new ArrayList<>(Collections.singleton(file))); datasetFileRepository.removeById(fileId); - dataset.removeFile(file); + if (CommonUtils.isUUID(fileId)) { + dataset.removeFile(file); + } datasetRepository.updateById(dataset); // 删除文件时,上传到数据集中的文件会同时删除数据库中的记录和文件系统中的文件,归集过来的文件仅删除数据库中的记录 if (file.getFilePath().startsWith(dataset.getPath())) { @@ -239,10 +251,10 @@ public void deleteDatasetFile(String datasetId, String fileId) { * 下载文件 */ @Transactional(readOnly = true) - public Resource downloadFile(String datasetId, String fileId) { - DatasetFile file = getDatasetFile(datasetId, fileId); + public Resource downloadFile(DatasetFile file) { try { Path filePath = Paths.get(file.getFilePath()).normalize(); + log.info("start download file {}", file.getFilePath()); Resource resource = new UrlResource(filePath.toUri()); if (resource.exists()) { return resource; @@ -638,12 +650,12 @@ public void deleteDirectory(String datasetId, String prefix) { */ @Transactional public void renameFile(String datasetId, String fileId, RenameFileRequest request) { - DatasetFile file = getDatasetFile(datasetId, fileId); Dataset dataset = datasetRepository.getById(datasetId); if (dataset == null) { throw BusinessException.of(DataManagementErrorCode.DATASET_NOT_FOUND); } + DatasetFile file = getDatasetFile(dataset, fileId); String newName = Optional.ofNullable(request.getNewName()).orElse("").trim(); if (newName.isEmpty()) { throw BusinessException.of(CommonErrorCode.PARAM_ERROR); diff --git a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/domain/model/dataset/DatasetFile.java b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/domain/model/dataset/DatasetFile.java index f164ee16..704b0ad4 100644 --- a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/domain/model/dataset/DatasetFile.java +++ b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/domain/model/dataset/DatasetFile.java @@ -3,6 +3,7 @@ import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; +import com.datamate.common.infrastructure.config.PgJsonTypeHandler; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.*; @@ -32,7 +33,7 @@ public class DatasetFile { private Long fileSize; // bytes private String checkSum; private String tags; - private LocalDateTime tagsUpdatedAt; + @TableField(typeHandler = PgJsonTypeHandler.class) private String metadata; private String status; // UPLOADED, PROCESSING, COMPLETED, ERROR private LocalDateTime uploadTime; diff --git a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/interfaces/rest/DatasetFileController.java b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/interfaces/rest/DatasetFileController.java index 4b5c1ba8..136ccbab 100644 --- a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/interfaces/rest/DatasetFileController.java +++ b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/interfaces/rest/DatasetFileController.java @@ -5,7 +5,9 @@ import com.datamate.common.infrastructure.exception.SystemErrorCode; import com.datamate.common.interfaces.PagedResponse; import com.datamate.common.interfaces.PagingQuery; +import com.datamate.datamanagement.application.DatasetApplicationService; import com.datamate.datamanagement.application.DatasetFileApplicationService; +import com.datamate.datamanagement.domain.model.dataset.Dataset; import com.datamate.datamanagement.domain.model.dataset.DatasetFile; import com.datamate.datamanagement.interfaces.converter.DatasetConverter; import com.datamate.datamanagement.interfaces.dto.AddFilesRequest; @@ -18,6 +20,7 @@ import com.datamate.datamanagement.interfaces.dto.RenameDirectoryRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.Resource; @@ -34,15 +37,13 @@ */ @Slf4j @RestController +@RequiredArgsConstructor @RequestMapping("/data-management/datasets/{datasetId}/files") public class DatasetFileController { private final DatasetFileApplicationService datasetFileApplicationService; - @Autowired - public DatasetFileController(DatasetFileApplicationService datasetFileApplicationService) { - this.datasetFileApplicationService = datasetFileApplicationService; - } + private final DatasetApplicationService datasetApplicationService; @GetMapping public Response> getDatasetFiles( @@ -66,7 +67,8 @@ public ResponseEntity> getDatasetFileById( @PathVariable("datasetId") String datasetId, @PathVariable("fileId") String fileId) { try { - DatasetFile datasetFile = datasetFileApplicationService.getDatasetFile(datasetId, fileId); + Dataset dataset = datasetApplicationService.getDataset(datasetId); + DatasetFile datasetFile = datasetFileApplicationService.getDatasetFile(dataset, fileId); return ResponseEntity.ok(Response.ok(DatasetConverter.INSTANCE.convertToResponse(datasetFile))); } catch (IllegalArgumentException e) { return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Response.error(SystemErrorCode.UNKNOWN_ERROR, null)); @@ -90,8 +92,9 @@ public ResponseEntity> deleteDatasetFile( public ResponseEntity downloadDatasetFileById(@PathVariable("datasetId") String datasetId, @PathVariable("fileId") String fileId) { try { - DatasetFile datasetFile = datasetFileApplicationService.getDatasetFile(datasetId, fileId); - Resource resource = datasetFileApplicationService.downloadFile(datasetId, fileId); + Dataset dataset = datasetApplicationService.getDataset(datasetId); + DatasetFile datasetFile = datasetFileApplicationService.getDatasetFile(dataset, fileId); + Resource resource = datasetFileApplicationService.downloadFile(datasetFile); return ResponseEntity.ok() .contentType(MediaType.APPLICATION_OCTET_STREAM) @@ -99,8 +102,10 @@ public ResponseEntity downloadDatasetFileById(@PathVariable("datasetId "attachment; filename=\"" + datasetFile.getFileName() + "\"") .body(resource); } catch (IllegalArgumentException e) { + log.error("downloadDatasetFileById error: {}", e.getMessage(), e); return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); } catch (Exception e) { + log.error("downloadDatasetFileById error: {}", e.getMessage(), e); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } } diff --git a/backend/shared/domain-common/src/main/java/com/datamate/common/domain/utils/CommonUtils.java b/backend/shared/domain-common/src/main/java/com/datamate/common/domain/utils/CommonUtils.java index 4a1fe477..acffe76b 100644 --- a/backend/shared/domain-common/src/main/java/com/datamate/common/domain/utils/CommonUtils.java +++ b/backend/shared/domain-common/src/main/java/com/datamate/common/domain/utils/CommonUtils.java @@ -1,6 +1,7 @@ package com.datamate.common.domain.utils; import java.io.File; +import java.util.UUID; /** * 通用工具类 @@ -21,4 +22,20 @@ public static String trimFilePath(String filePath) { } return filename; } + + /** + * 判断字符串是否是uuid + * + * @param str 要判断的字符串 + * @return 判断结果 + */ + public static boolean isUUID(String str) { + if (str == null) return false; + try { + UUID.fromString(str); + return true; + } catch (IllegalArgumentException e) { + return false; + } + } } diff --git a/frontend/src/pages/DataCollection/collection.apis.ts b/frontend/src/pages/DataCollection/collection.apis.ts index 3e6bb9ee..4f07f889 100644 --- a/frontend/src/pages/DataCollection/collection.apis.ts +++ b/frontend/src/pages/DataCollection/collection.apis.ts @@ -1,4 +1,4 @@ -import { get, post, put, del } from "@/utils/request"; +import {get, post, put, del, download} from "@/utils/request"; // 数据源任务相关接口 export function queryTasksUsingGet(params?: any) { @@ -9,21 +9,6 @@ export function createTaskUsingPost(data: any) { return post("/api/data-collection/tasks", data); } -export function queryTaskByIdUsingGet(id: string | number) { - return get(`/api/data-collection/tasks/${id}`); -} - -export function updateTaskByIdUsingPut( - id: string | number, - data: any -) { - return put(`/api/data-collection/tasks/${id}`, data); -} - -export function queryTaskDetailsByIdUsingGet(id: string | number) { - return get(`/api/data-collection/tasks/${id}`); -} - export function queryDataXTemplatesUsingGet(params?: any) { return get("/api/data-collection/templates", params); } @@ -50,45 +35,6 @@ export function queryExecutionLogUsingPost(params?: any) { return get("/api/data-collection/executions", params); } -export function queryExecutionLogByIdUsingGet(id: string | number) { - return get(`/api/data-collection/executions/${id}`); -} - -export function queryExecutionLogContentByIdUsingGet(id: string | number) { - return get(`/api/data-collection/executions/${id}/log`); -} - export async function queryExecutionLogFileByIdUsingGet(id: string | number) { - const token = localStorage.getItem("token") || sessionStorage.getItem("token"); - const resp = await fetch(`/api/data-collection/executions/${id}/log`, { - method: "GET", - headers: { - ...(token ? { Authorization: `Bearer ${token}` } : {}), - }, - credentials: "include", - }); - - if (!resp.ok) { - let detail = ""; - try { - detail = await resp.text(); - } catch { - detail = resp.statusText; - } - const err: any = new Error(detail || `HTTP error ${resp.status}`); - err.status = resp.status; - err.data = detail; - throw err; - } - - const contentDisposition = resp.headers.get("content-disposition") || ""; - const filenameMatch = contentDisposition.match(/filename\*?=(?:UTF-8''|\")?([^;\"\n]+)/i); - const filename = filenameMatch?.[1] ? decodeURIComponent(filenameMatch[1].replace(/\"/g, "").trim()) : `execution_${id}.log`; - const blob = await resp.blob(); - return { blob, filename }; -} - -// 监控统计相关接口 -export function queryCollectionStatisticsUsingGet(params?: any) { - return get("/api/data-collection/monitor/statistics", params); + return await download(`/api/data-collection/executions/${id}/log`, null, undefined, "preview"); } diff --git a/runtime/datamate-python/app/module/collection/interface/execution.py b/runtime/datamate-python/app/module/collection/interface/execution.py index b012642b..29e879d3 100644 --- a/runtime/datamate-python/app/module/collection/interface/execution.py +++ b/runtime/datamate-python/app/module/collection/interface/execution.py @@ -104,7 +104,7 @@ async def get_execution_log( filename = path.name headers = { - "Content-Disposition": f'inline; filename="{filename}"' + "Content-Disposition": f'inline; filename={filename}' } return FileResponse( path=str(path),