From 79272137abfe601b1c8877bca3624968f49b4ba3 Mon Sep 17 00:00:00 2001 From: teddy Date: Tue, 24 Mar 2026 17:19:06 +0900 Subject: [PATCH] =?UTF-8?q?=EB=82=A9=ED=92=88=20=ED=8F=B4=EB=8D=94=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20api=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dataset/DatasetApiController.java | 21 +++ .../dataset/service/DatasetService.java | 99 +++++++++++ .../kamco/cd/training/model/dto/FileDto.java | 157 ++++++++++++++++++ 3 files changed, 277 insertions(+) create mode 100644 src/main/java/com/kamco/cd/training/model/dto/FileDto.java diff --git a/src/main/java/com/kamco/cd/training/dataset/DatasetApiController.java b/src/main/java/com/kamco/cd/training/dataset/DatasetApiController.java index 5d4441a..1b8459b 100644 --- a/src/main/java/com/kamco/cd/training/dataset/DatasetApiController.java +++ b/src/main/java/com/kamco/cd/training/dataset/DatasetApiController.java @@ -6,6 +6,8 @@ import com.kamco.cd.training.dataset.dto.DatasetObjDto; import com.kamco.cd.training.dataset.dto.DatasetObjDto.DatasetClass; import com.kamco.cd.training.dataset.dto.DatasetObjDto.DatasetStorage; import com.kamco.cd.training.dataset.service.DatasetService; +import com.kamco.cd.training.model.dto.FileDto.FoldersDto; +import com.kamco.cd.training.model.dto.FileDto.SrchFoldersDto; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; @@ -248,4 +250,23 @@ public class DatasetApiController { String path = datasetService.getFilePathByUUIDPathType(uuid, pathType); return datasetService.getFilePathByFile(path); } + + @Operation(summary = "납품 폴더 조회", description = "납품 폴더 조회 API") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "조회 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = Page.class))), + @ApiResponse(responseCode = "404", description = "조회 오류", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @PostMapping("/folder-list") + public ApiResponseDto getDir(@RequestBody SrchFoldersDto srchDto) throws IOException { + + return ApiResponseDto.createOK(datasetService.getFolderAll(srchDto)); + } } diff --git a/src/main/java/com/kamco/cd/training/dataset/service/DatasetService.java b/src/main/java/com/kamco/cd/training/dataset/service/DatasetService.java index 691dff1..230a337 100644 --- a/src/main/java/com/kamco/cd/training/dataset/service/DatasetService.java +++ b/src/main/java/com/kamco/cd/training/dataset/service/DatasetService.java @@ -18,8 +18,11 @@ import com.kamco.cd.training.dataset.dto.DatasetObjDto.DatasetClass; import com.kamco.cd.training.dataset.dto.DatasetObjDto.DatasetObjRegDto; import com.kamco.cd.training.dataset.dto.DatasetObjDto.DatasetStorage; import com.kamco.cd.training.dataset.dto.DatasetObjDto.SearchReq; +import com.kamco.cd.training.model.dto.FileDto.FoldersDto; +import com.kamco.cd.training.model.dto.FileDto.SrchFoldersDto; import com.kamco.cd.training.postgres.core.DatasetCoreService; import jakarta.validation.Valid; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; @@ -27,6 +30,8 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -506,4 +511,98 @@ public class DatasetService { } } } + + /** + * 폴더 조회 + * + * @param srchDto 폴더 경로 + * @return 폴더 리스트 + * @throws IOException + */ + public FoldersDto getFolderAll(SrchFoldersDto srchDto) throws IOException { + + File dir = new File(srchDto.getDirPath() == null ? "/" : srchDto.getDirPath()); + + // 존재 + 디렉토리 체크 + if (!dir.exists() || !dir.isDirectory()) { + throw new RuntimeException("Invalid path"); + } + + // 권한 없을때 + if (!dir.canRead()) { + throw new RuntimeException("Permission denied"); + } + + String canonicalPath = dir.getCanonicalPath(); + + File[] files = dir.listFiles(); + + if (files == null) { + return new FoldersDto(canonicalPath, 0, 0, Collections.emptyList()); + } + + List folders = new ArrayList<>(); + + int folderTotCnt = 0; + int folderErrTotCnt = 0; + + for (File f : files) { + + // 숨김 제외 + if (f.isHidden()) continue; + + if (f.isDirectory()) { + + // 폴더 개수 증가 + folderTotCnt++; + + // 폴더 유효성 여부 (기본 true, 이후 검증 로직으로 변경 가능) + boolean isValid = true; + + // 유효하지 않은 폴더 카운트 증가 + if (!isValid) folderErrTotCnt++; + + // 현재 폴더 이름 (ex: train, images 등) + String folderNm = f.getName(); + + // 부모 경로 (ex: /data/datasets) + String parentPath = f.getParent(); + + // 부모 폴더 이름 (ex: datasets) + String parentFolderNm = new File(parentPath).getName(); + + // 전체 절대 경로 (ex: /data/datasets/train) + String fullPath = f.getAbsolutePath(); + + // 폴더 깊이 (경로 기준 depth) + // ex: /a/b/c → depth = 3 + int depth = f.toPath().getNameCount(); + + // 하위 폴더 개수 + long childCnt = FIleChecker.getChildFolderCount(f); + + // 마지막 수정 시간 (문자열 포맷) + String lastModified = FIleChecker.getLastModified(f); + + // Folder DTO 생성 및 리스트에 추가 + folders.add( + new FIleChecker.Folder( + folderNm, // 폴더명 + parentFolderNm, // 부모 폴더명 + parentPath, // 부모 경로 + fullPath, // 전체 경로 + depth, // 깊이 + childCnt, // 하위 폴더 개수 + lastModified, // 수정일시 + isValid // 유효성 여부 + )); + } + } + + // 폴더 정렬 + folders.sort( + Comparator.comparing(FIleChecker.Folder::getFolderNm, String.CASE_INSENSITIVE_ORDER)); + + return new FoldersDto(canonicalPath, folderTotCnt, folderErrTotCnt, folders); + } } diff --git a/src/main/java/com/kamco/cd/training/model/dto/FileDto.java b/src/main/java/com/kamco/cd/training/model/dto/FileDto.java new file mode 100644 index 0000000..a7dff79 --- /dev/null +++ b/src/main/java/com/kamco/cd/training/model/dto/FileDto.java @@ -0,0 +1,157 @@ +package com.kamco.cd.training.model.dto; + +import com.kamco.cd.training.common.utils.FIleChecker; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +public class FileDto { + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class SrchFoldersDto { + @Schema(description = "디렉토리경로(ROOT:/)", example = "") + @NotNull + private String dirPath = "/"; + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class SrchFilesDto { + @Schema(description = "디렉토리경로", example = "D:\\kamco\\2022\\캠코_2021_2022_34602060_D1") + @NotNull + private String dirPath; + + @Schema(description = "전체(*), cpg,dbf,geojson등", example = "*") + @NotNull + private String extension; + + @Schema(description = "파일명(name), 최종수정일(date)", example = "name") + @NotNull + private String sortType; + + @Schema(description = "파일시작위치", example = "1") + @NotNull + private Integer startPos; + + @Schema(description = "파일종료위치", example = "100") + @NotNull + private Integer endPos; + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class SrchFilesDepthDto extends SrchFilesDto { + @Schema(description = "최대폴더Depth", example = "5") + @NotNull + private Integer maxDepth; + } + + @Schema(name = "FolderDto", description = "폴더 정보") + @Getter + public static class FolderDto { + private final String folderNm; + private final String parentFolderNm; + private final String parentPath; + private final String fullPath; + private final int depth; + private final long childCnt; + private final String lastModified; + private final Boolean isValid; + + public FolderDto( + String folderNm, + String parentFolderNm, + String parentPath, + String fullPath, + int depth, + long childCnt, + String lastModified, + Boolean isValid) { + this.folderNm = folderNm; + this.parentFolderNm = parentFolderNm; + this.parentPath = parentPath; + this.fullPath = fullPath; + this.depth = depth; + this.childCnt = childCnt; + this.lastModified = lastModified; + this.isValid = isValid; + } + } + + @Schema(name = "FoldersDto", description = "폴더목록 정보") + @Getter + public static class FoldersDto { + private final String dirPath; + private final int folderTotCnt; + private final int folderErrTotCnt; + private final List folders; + + public FoldersDto( + String dirPath, int folderTotCnt, int folderErrTotCnt, List folders) { + + this.dirPath = dirPath; + this.folderTotCnt = folderTotCnt; + this.folderErrTotCnt = folderErrTotCnt; + this.folders = folders; + } + } + + @Schema(name = "File Basic", description = "파일 기본 정보") + @Getter + public static class Basic { + + private final String fileNm; + private final String parentFolderNm; + private final String parentPath; + private final String fullPath; + private final String extension; + private final long fileSize; + private final String lastModified; + + public Basic( + String fileNm, + String parentFolderNm, + String parentPath, + String fullPath, + String extension, + long fileSize, + String lastModified) { + this.fileNm = fileNm; + this.parentFolderNm = parentFolderNm; + this.parentPath = parentPath; + this.fullPath = fullPath; + this.extension = extension; + this.fileSize = fileSize; + this.lastModified = lastModified; + } + } + + @Schema(name = "FilesDto", description = "파일 목록 정보") + @Getter + public static class FilesDto { + private final String dirPath; + private final int fileTotCnt; + private final long fileTotSize; + private final List files; + + public FilesDto( + String dirPath, int fileTotCnt, long fileTotSize, List files) { + + this.dirPath = dirPath; + this.fileTotCnt = fileTotCnt; + this.fileTotSize = fileTotSize; + this.files = files; + } + } +}