파일 체크 수정 및 패키지 분리

This commit is contained in:
Harry M. You
2025-12-05 16:13:18 +09:00
parent 786b2f8cc8
commit fba9a14035
13 changed files with 680 additions and 241 deletions

View File

@@ -32,62 +32,6 @@ public class MapSheetMngApiController {
private final CommonCodeService commonCodeService;
private final MapSheetMngService mapSheetMngService;
@Operation(summary = "폴더 조회", description = "폴더 조회")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "조회 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = CommonCodeDto.Basic.class))),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PostMapping("/folder-list")
public ApiResponseDto<FoldersDto> getDir(@RequestBody SrchFoldersDto srchDto) {
return ApiResponseDto.createOK(mapSheetMngService.getFolderAll(srchDto));
}
@Operation(summary = "지정폴더내 파일목록 조회", description = "지정폴더내 파일목록 조회")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "조회 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = CommonCodeDto.Basic.class))),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PostMapping("/file-list")
public ApiResponseDto<FilesDto> getFiles(@RequestBody SrchFilesDto srchDto) {
return ApiResponseDto.createOK(mapSheetMngService.getFilesAll(srchDto));
}
@Operation(summary = "지정폴더(하위폴더포함) 파일목록 조회", description = "지정폴더(하위폴더포함) 파일목록 조회")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "조회 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = CommonCodeDto.Basic.class))),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PostMapping("/file-all-list")
public ApiResponseDto<FilesDto> getAllFiles(@RequestBody SrchFilesDepthDto srchDto) {
return ApiResponseDto.createOK(mapSheetMngService.getFilesDepthAll(srchDto));
}
/**
* 오류데이터 목록 조회
*
@@ -120,26 +64,6 @@ public class MapSheetMngApiController {
}
@Operation(summary = "영상데이터관리 > 영상파일 동기화", description = "영상파일 동기화")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "동기화 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = CommonCodeDto.Basic.class))),
@ApiResponse(responseCode = "404", description = "동기화 할수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PostMapping("/sync-process")
public ApiResponseDto<MapSheetMngDto.DmlReturn> uploadProcess(
@RequestBody @Valid ImageryDto.searchReq searchReq) {
return ApiResponseDto.ok(mapSheetMngService.syncProcess(searchReq));
}
/**
* @param hstUidList
* @return

View File

@@ -0,0 +1,118 @@
package com.kamco.cd.kamcoback.mapsheet;
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto;
import com.kamco.cd.kamcoback.code.service.CommonCodeService;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.FilesDto;
import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.FoldersDto;
import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.SrchFilesDepthDto;
import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.SrchFilesDto;
import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.SrchFoldersDto;
import com.kamco.cd.kamcoback.mapsheet.dto.ImageryDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto;
import com.kamco.cd.kamcoback.mapsheet.service.MapSheetMngFileCheckerService;
import com.kamco.cd.kamcoback.mapsheet.service.MapSheetMngService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Tag(name = "영상 관리", description = "영상 관리 API")
@RestController
@RequiredArgsConstructor
@RequestMapping({"/api/mapsheet"})
public class MapSheetMngFileCheckerApiController {
private final CommonCodeService commonCodeService;
private final MapSheetMngFileCheckerService mapSheetMngFileCheckerService;
@Operation(summary = "폴더 조회", description = "폴더 조회")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "조회 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = CommonCodeDto.Basic.class))),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PostMapping("/folder-list")
public ApiResponseDto<FoldersDto> getDir(@RequestBody SrchFoldersDto srchDto) {
return ApiResponseDto.createOK(mapSheetMngFileCheckerService.getFolderAll(srchDto));
}
@Operation(summary = "지정폴더내 파일목록 조회", description = "지정폴더내 파일목록 조회")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "조회 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = CommonCodeDto.Basic.class))),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PostMapping("/file-list")
public ApiResponseDto<FilesDto> getFiles(@RequestBody SrchFilesDto srchDto) {
return ApiResponseDto.createOK(mapSheetMngFileCheckerService.getFilesAll(srchDto));
}
@Operation(summary = "지정폴더(하위폴더포함) 파일목록 조회", description = "지정폴더(하위폴더포함) 파일목록 조회")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "조회 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = CommonCodeDto.Basic.class))),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PostMapping("/file-all-list")
public ApiResponseDto<FilesDto> getAllFiles(@RequestBody SrchFilesDepthDto srchDto) {
return ApiResponseDto.createOK(mapSheetMngFileCheckerService.getFilesDepthAll(srchDto));
}
@Operation(summary = "영상데이터관리 > 영상파일 동기화", description = "영상파일 동기화")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "동기화 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = CommonCodeDto.Basic.class))),
@ApiResponse(responseCode = "404", description = "동기화 할수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PostMapping("/sync-process")
public ApiResponseDto<MapSheetMngDto.DmlReturn> uploadProcess(
@RequestBody @Valid ImageryDto.searchReq searchReq) {
return ApiResponseDto.ok(mapSheetMngFileCheckerService.syncProcess(searchReq));
}
}

View File

@@ -15,7 +15,9 @@ public class FileDto {
@NoArgsConstructor
@AllArgsConstructor
public static class SrchFoldersDto {
@NotNull private String dirPath;
@Schema(description = "디렉토리경로", example = "D:\\kamco")
@NotNull
private String dirPath;
}
@Getter

View File

@@ -0,0 +1,310 @@
package com.kamco.cd.kamcoback.mapsheet.service;
import static java.lang.String.CASE_INSENSITIVE_ORDER;
import com.kamco.cd.kamcoback.common.utils.NameValidator;
import com.kamco.cd.kamcoback.mapsheet.dto.FileDto;
import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.FilesDto;
import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.FolderDto;
import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.FoldersDto;
import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.SrchFilesDepthDto;
import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.SrchFilesDto;
import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.SrchFoldersDto;
import com.kamco.cd.kamcoback.mapsheet.dto.ImageryDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto;
import com.kamco.cd.kamcoback.postgres.core.MapSheetMngFileCheckerCoreService;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileTime;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
import org.apache.commons.io.FilenameUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class MapSheetMngFileCheckerService {
private final MapSheetMngFileCheckerCoreService mapSheetMngFileCheckerCoreService;
public FoldersDto getFolderAll(SrchFoldersDto srchDto) {
System.out.println("getFolderAll === ");
Path startPath = Paths.get(srchDto.getDirPath());
String dirPath = srchDto.getDirPath();
int maxDepth = 1;
int folderTotCnt = 0;
int folderErrTotCnt = 0;
List<FolderDto> folderDtoList = List.of();
SimpleDateFormat dttmFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try (Stream<Path> stream = Files.walk(startPath, maxDepth)) {
folderDtoList =
stream
// 1. 디렉토리만 필터링
.filter(Files::isDirectory)
.filter(p -> !p.toString().equals(dirPath))
.map(
path -> {
int depth = path.getNameCount();
String folderNm = path.getFileName().toString();
String parentFolderNm = path.getParent().getFileName().toString();
String parentPath = path.getParent().toString();
String fullPath = path.toAbsolutePath().toString();
boolean isValid =
!NameValidator.containsKorean(folderNm)
&& !NameValidator.containsWhitespaceRegex(folderNm);
File directory = new File(fullPath);
File[] childFolders = directory.listFiles(File::isDirectory);
long childCnt = 0;
if (childFolders != null) {
childCnt = childFolders.length;
}
FileTime time = null;
String lastModified = "";
try {
time = Files.getLastModifiedTime(path);
lastModified = dttmFormat.format(new Date(time.toMillis()));
} catch (IOException e) {
throw new RuntimeException(e);
}
return new FolderDto(
folderNm,
parentFolderNm,
parentPath,
fullPath,
depth,
childCnt,
lastModified,
isValid);
})
.collect(Collectors.toList());
folderDtoList.sort(
Comparator.comparing(
FolderDto::getFolderNm, CASE_INSENSITIVE_ORDER // 대소문자 구분 없이
)
.reversed());
folderTotCnt = folderDtoList.size();
folderErrTotCnt =
(int)
folderDtoList.stream()
.filter(dto -> dto.getIsValid().toString().equals("false"))
.count();
} catch (IOException e) {
throw new RuntimeException(e);
}
// FoldersDto foldersDto = new FoldersDto(dirPath, folderTotCnt, folderErrTotCnt,
// folderDtoList);
return new FoldersDto(dirPath, folderTotCnt, folderErrTotCnt, folderDtoList);
}
public FilesDto getFilesAll(SrchFilesDto srchDto) {
String dirPath = srchDto.getDirPath();
String extension = srchDto.getExtension();
String sortType = srchDto.getSortType();
int startPos = srchDto.getStartPos();
int endPos = srchDto.getEndPos();
File dir = new File(dirPath);
File[] fileList = dir.listFiles();
List<FileDto.Basic> files = new ArrayList<>();
SimpleDateFormat dttmFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
int fileListPos = 0;
int fileTotCnt = 0;
long fileTotSize = 0;
if (fileList != null) {
if (sortType.equals("name")) {
Arrays.sort(fileList);
} else if (sortType.equals("date")) {
Arrays.sort(fileList, Comparator.comparingLong(File::lastModified));
}
for (File file : fileList) {
if (file.isFile()) { // 파일인 경우만
if (extension.equals("*") || file.getName().endsWith("." + extension)) {
fileListPos = fileListPos + 1;
if (startPos <= fileListPos && endPos >= fileListPos) {
// 생성자를 통해 객체를 만들고 리스트에 추가
String fileName = file.getName();
String parentPath = file.getParent();
String fullPath = file.getAbsolutePath();
String ext = FilenameUtils.getExtension(fileName);
Path path = Paths.get(parentPath);
String parentFolderNm = path.getFileName().toString();
long fileSize = file.length();
String lastModified = dttmFormat.format(new Date(file.lastModified()));
files.add(
new FileDto.Basic(
fileName, parentFolderNm, parentPath, fullPath, ext, fileSize, lastModified));
fileTotCnt = fileTotCnt + 1;
fileTotSize = fileTotSize + fileSize;
}
}
}
}
}
return new FilesDto(dirPath, fileTotCnt, fileTotSize, files);
}
public FilesDto getFilesDepthAll(SrchFilesDepthDto srchDto) {
Path startPath = Paths.get(srchDto.getDirPath());
int maxDepth = srchDto.getMaxDepth();
String dirPath = srchDto.getDirPath();
String extension = srchDto.getExtension();
String sortType = srchDto.getSortType();
int startPos = srchDto.getStartPos();
int endPos = srchDto.getEndPos();
int limit = endPos - startPos + 1;
Set<String> targetExtensions = createExtensionSet(extension);
List<FileDto.Basic> fileDtoList = new ArrayList<>();
SimpleDateFormat dttmFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
int fileTotCnt = 0;
long fileTotSize = 0;
try (Stream<Path> stream = Files.walk(startPath, maxDepth)) {
fileDtoList =
stream
.filter(Files::isRegularFile)
.filter(
p ->
extension == null
|| extension.equals("")
|| extension.equals("*")
|| targetExtensions.contains(extractExtension(p)))
.sorted(getFileComparator(sortType))
.skip(startPos)
.limit(limit)
.map(
path -> {
int depth = path.getNameCount();
String fileNm = path.getFileName().toString();
String ext = FilenameUtils.getExtension(fileNm);
String parentFolderNm = path.getParent().getFileName().toString();
String parentPath = path.getParent().toString();
String fullPath = path.toAbsolutePath().toString();
File file = new File(fullPath);
long fileSize = file.length();
String lastModified = dttmFormat.format(new Date(file.lastModified()));
return new FileDto.Basic(
fileNm, parentFolderNm, parentPath, fullPath, ext, fileSize, lastModified);
})
.collect(Collectors.toList());
fileTotCnt = fileDtoList.size();
fileTotSize = fileDtoList.stream().mapToLong(FileDto.Basic::getFileSize).sum();
} catch (IOException e) {
System.err.println("파일 I/O 오류 발생: " + e.getMessage());
}
return new FilesDto(dirPath, fileTotCnt, fileTotSize, fileDtoList);
}
public Set<String> createExtensionSet(String extensionString) {
if (extensionString == null || extensionString.isBlank()) {
return Set.of();
}
// "java, class" -> ["java", " class"] -> [".java", ".class"]
return Arrays.stream(extensionString.split(","))
.map(ext -> ext.trim())
.filter(ext -> !ext.isEmpty())
.map(ext -> "." + ext.toLowerCase())
.collect(Collectors.toSet());
}
public String extractExtension(Path path) {
String filename = path.getFileName().toString();
int lastDotIndex = filename.lastIndexOf('.');
// 확장자가 없거나 파일명이 .으로 끝나는 경우
if (lastDotIndex == -1 || lastDotIndex == filename.length() - 1) {
return ""; // 빈 문자열 반환
}
// 확장자 추출 및 소문자 변환
return filename.substring(lastDotIndex).toLowerCase();
}
public Comparator<Path> getFileComparator(String sortType) {
// 파일 이름 비교 기본 Comparator (대소문자 무시)
Comparator<Path> nameComparator =
Comparator.comparing(path -> path.getFileName().toString(), CASE_INSENSITIVE_ORDER);
Comparator<Path> dateComparator =
Comparator.comparing(
path -> {
try {
return Files.getLastModifiedTime(path);
} catch (IOException e) {
return FileTime.fromMillis(0);
}
});
if ("name desc".equalsIgnoreCase(sortType)) {
return nameComparator.reversed();
} else if ("date".equalsIgnoreCase(sortType)) {
return dateComparator;
} else if ("date desc".equalsIgnoreCase(sortType)) {
return dateComparator.reversed();
} else {
return nameComparator;
}
}
public MapSheetMngDto.DmlReturn syncProcess(ImageryDto.searchReq searchReq) {
return mapSheetMngFileCheckerCoreService.syncProcess(searchReq);
}
}

View File

@@ -42,90 +42,7 @@ public class MapSheetMngService {
private final MapSheetMngCoreService mapSheetMngCoreService;
public FoldersDto getFolderAll(SrchFoldersDto srchDto) {
Path startPath = Paths.get(srchDto.getDirPath());
String dirPath = srchDto.getDirPath();
int maxDepth = 1;
int folderTotCnt = 0;
int folderErrTotCnt = 0;
List<FolderDto> folderDtoList = List.of();
SimpleDateFormat dttmFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try (Stream<Path> stream = Files.walk(startPath, maxDepth)) {
folderDtoList =
stream
// 1. 디렉토리만 필터링
.filter(Files::isDirectory)
.filter(p -> !p.toString().equals(dirPath))
.map(
path -> {
int depth = path.getNameCount();
String folderNm = path.getFileName().toString();
String parentFolderNm = path.getParent().getFileName().toString();
String parentPath = path.getParent().toString();
String fullPath = path.toAbsolutePath().toString();
boolean isValid =
!NameValidator.containsKorean(folderNm)
&& !NameValidator.containsWhitespaceRegex(folderNm);
File directory = new File(fullPath);
File[] childFolders = directory.listFiles(File::isDirectory);
long childCnt = 0;
if (childFolders != null) {
childCnt = childFolders.length;
}
FileTime time = null;
String lastModified = "";
try {
time = Files.getLastModifiedTime(path);
lastModified = dttmFormat.format(new Date(time.toMillis()));
} catch (IOException e) {
throw new RuntimeException(e);
}
return new FolderDto(
folderNm,
parentFolderNm,
parentPath,
fullPath,
depth,
childCnt,
lastModified,
isValid);
})
.collect(Collectors.toList());
folderDtoList.sort(
Comparator.comparing(
FolderDto::getFolderNm, CASE_INSENSITIVE_ORDER // 대소문자 구분 없이
)
.reversed());
folderTotCnt = folderDtoList.size();
folderErrTotCnt =
(int)
folderDtoList.stream()
.filter(dto -> dto.getIsValid().toString().equals("false"))
.count();
} catch (IOException e) {
throw new RuntimeException(e);
}
// FoldersDto foldersDto = new FoldersDto(dirPath, folderTotCnt, folderErrTotCnt,
// folderDtoList);
return new FoldersDto(dirPath, folderTotCnt, folderErrTotCnt, folderDtoList);
}
public FilesDto getFilesAll(SrchFilesDto srchDto) {
@@ -320,8 +237,6 @@ public class MapSheetMngService {
return mapSheetMngCoreService.updateExceptUseInference(hstUidList);
}
public MapSheetMngDto.DmlReturn syncProcess(ImageryDto.searchReq searchReq) {
return mapSheetMngCoreService.syncProcess(searchReq);
}
}