diff --git a/src/main/java/com/kamco/cd/kamcoback/mapsheet/MapSheetMngApiController.java b/src/main/java/com/kamco/cd/kamcoback/mapsheet/MapSheetMngApiController.java index 03f478b7..781c92d7 100644 --- a/src/main/java/com/kamco/cd/kamcoback/mapsheet/MapSheetMngApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/mapsheet/MapSheetMngApiController.java @@ -15,7 +15,9 @@ import jakarta.validation.Valid; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; +import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; @Tag(name = "영상 관리", description = "영상 관리 API") @RestController @@ -34,70 +36,85 @@ public class MapSheetMngApiController { */ @PostMapping("/error-list") public ApiResponseDto> findMapSheetErrorList( - @RequestBody @Valid MapSheetMngDto.searchReq searchReq) { + @RequestBody @Valid MapSheetMngDto.searchReq searchReq) { return ApiResponseDto.ok(mapSheetMngService.findMapSheetErrorList(searchReq)); } @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) - }) + 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("/mng-list") public ApiResponseDto> findMapSheetMngList( - @RequestBody @Valid MapSheetMngDto.searchReq searchReq) { + @RequestBody @Valid MapSheetMngDto.searchReq searchReq) { return ApiResponseDto.ok(mapSheetMngService.findMapSheetMngList(searchReq)); } @Operation(summary = "영상관리 > 데이터 등록", description = "영상관리 > 데이터 등록") @ApiResponses( - value = { - @ApiResponse( - responseCode = "201", - description = "데이터 등록 성공", - content = - @Content( - mediaType = "application/json", - schema = @Schema(implementation = Long.class))), - @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content), - @ApiResponse(responseCode = "404", description = "데이터를 찾을 수 없음", content = @Content), - @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - }) + value = { + @ApiResponse( + responseCode = "201", + description = "데이터 등록 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = Long.class))), + @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content), + @ApiResponse(responseCode = "404", description = "데이터를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) @PutMapping("/mng-data-save") public ApiResponseDto mngDataSave( - @RequestBody @Valid MapSheetMngDto.AddReq AddReq) { + @RequestBody @Valid MapSheetMngDto.AddReq AddReq) { return ApiResponseDto.ok(mapSheetMngService.mngDataSave(AddReq)); } + @Operation(summary = "파일 업로드", description = "파일 업로드") + @PostMapping(value = "/file-upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public ApiResponseDto uploadFile( + @RequestPart(value = "file") MultipartFile file, + @RequestParam(value = "hstUid") Long hstUid) { + return ApiResponseDto.ok(mapSheetMngService.uploadFile(file, hstUid)); + } + + @Operation(summary = "파일 삭제", description = "파일 삭제") + @PostMapping("/file-delete") + public ApiResponseDto deleteFile( + @RequestBody @Valid MapSheetMngDto.DeleteFileReq req) { + return ApiResponseDto.ok(mapSheetMngService.deleteFile(req)); + } + /** * @param hstUidList * @return */ @Operation(summary = "오류데이터 팝업 > 업로드 처리", description = "오류데이터 팝업 > 업로드 처리") @ApiResponses( - value = { - @ApiResponse( - responseCode = "201", - description = "공통코드 저장 성공", - content = - @Content( - mediaType = "application/json", - schema = @Schema(implementation = Long.class))), - @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content), - @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), - @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - }) + value = { + @ApiResponse( + responseCode = "201", + description = "공통코드 저장 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = Long.class))), + @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content), + @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) @PutMapping("/upload-process") public ApiResponseDto uploadProcess( - @RequestBody @Valid List hstUidList) { + @RequestBody @Valid List hstUidList) { return ApiResponseDto.ok(mapSheetMngService.uploadProcess(hstUidList)); } @@ -108,7 +125,7 @@ public class MapSheetMngApiController { @Operation(summary = "오류데이터 팝업 > 추론 제외", description = "오류데이터 팝업 > 추론 제외") @PutMapping("/except-inference") public ApiResponseDto updateExceptUseInference( - @RequestBody @Valid List hstUidList) { + @RequestBody @Valid List hstUidList) { return ApiResponseDto.ok(mapSheetMngService.updateExceptUseInference(hstUidList)); } } diff --git a/src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/MapSheetMngDto.java b/src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/MapSheetMngDto.java index aaf6594a..ad61bbec 100644 --- a/src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/MapSheetMngDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/MapSheetMngDto.java @@ -42,7 +42,7 @@ public class MapSheetMngDto { String[] sortParams = sort.split(","); String property = sortParams[0]; Sort.Direction direction = - sortParams.length > 1 ? Sort.Direction.fromString(sortParams[1]) : Sort.Direction.ASC; + sortParams.length > 1 ? Sort.Direction.fromString(sortParams[1]) : Sort.Direction.ASC; return PageRequest.of(page, size, Sort.by(direction, property)); } return PageRequest.of(page, size); @@ -77,6 +77,16 @@ public class MapSheetMngDto { private String mngPath; } + @Schema(name = "DeleteFileReq", description = "파일 삭제 요청") + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class DeleteFileReq { + @Schema(description = "파일 경로", example = "/app/original-images/2024/00000001.tif") + private String filePath; + } + @Schema(name = "MngDto", description = "영상관리 검색 리턴") @Getter @Setter diff --git a/src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java b/src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java index b898b607..34ec4ba0 100644 --- a/src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java +++ b/src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java @@ -29,6 +29,7 @@ import org.apache.commons.io.FilenameUtils; import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; @Service @RequiredArgsConstructor @@ -82,8 +83,8 @@ public class MapSheetMngService { String lastModified = dttmFormat.format(new Date(file.lastModified())); files.add( - new FileDto.Basic( - fileName, parentFolderNm, parentPath, fullPath, ext, fileSize, lastModified)); + new FileDto.Basic( + fileName, parentFolderNm, parentPath, fullPath, ext, fileSize, lastModified)); fileTotCnt = fileTotCnt + 1; fileTotSize = fileTotSize + fileSize; @@ -119,35 +120,35 @@ public class MapSheetMngService { try (Stream 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(); + 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(); + 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())); + 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()); + 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(); @@ -166,10 +167,10 @@ public class MapSheetMngService { // "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()); + .map(ext -> ext.trim()) + .filter(ext -> !ext.isEmpty()) + .map(ext -> "." + ext.toLowerCase()) + .collect(Collectors.toSet()); } public String extractExtension(Path path) { @@ -189,17 +190,17 @@ public class MapSheetMngService { // 파일 이름 비교 기본 Comparator (대소문자 무시) Comparator nameComparator = - Comparator.comparing(path -> path.getFileName().toString(), CASE_INSENSITIVE_ORDER); + Comparator.comparing(path -> path.getFileName().toString(), CASE_INSENSITIVE_ORDER); Comparator dateComparator = - Comparator.comparing( - path -> { - try { - return Files.getLastModifiedTime(path); - } catch (IOException e) { - return FileTime.fromMillis(0); - } - }); + Comparator.comparing( + path -> { + try { + return Files.getLastModifiedTime(path); + } catch (IOException e) { + return FileTime.fromMillis(0); + } + }); if ("name desc".equalsIgnoreCase(sortType)) { return nameComparator.reversed(); @@ -213,12 +214,12 @@ public class MapSheetMngService { } public Page findMapSheetErrorList( - MapSheetMngDto.@Valid searchReq searchReq) { + MapSheetMngDto.@Valid searchReq searchReq) { return mapSheetMngCoreService.findMapSheetErrorList(searchReq); } public Page findMapSheetMngList( - MapSheetMngDto.@Valid searchReq searchReq) { + MapSheetMngDto.@Valid searchReq searchReq) { return mapSheetMngCoreService.findMapSheetMngList(searchReq); } @@ -226,6 +227,14 @@ public class MapSheetMngService { return mapSheetMngCoreService.mngDataSave(AddReq); } + public MapSheetMngDto.DmlReturn uploadFile(MultipartFile file, Long hstUid) { + return mapSheetMngCoreService.uploadFile(file, hstUid); + } + + public MapSheetMngDto.DmlReturn deleteFile(MapSheetMngDto.DeleteFileReq req) { + return mapSheetMngCoreService.deleteFile(req); + } + public MapSheetMngDto.DmlReturn uploadProcess(@Valid List hstUidList) { return mapSheetMngCoreService.uploadProcess(hstUidList); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/MapSheetMngCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/MapSheetMngCoreService.java index c3d6c494..d258a1aa 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/MapSheetMngCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/MapSheetMngCoreService.java @@ -20,6 +20,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; @Service @RequiredArgsConstructor @@ -33,24 +34,68 @@ public class MapSheetMngCoreService { private String activeEnv; public Page findMapSheetErrorList( - MapSheetMngDto.@Valid searchReq searchReq) { + MapSheetMngDto.@Valid searchReq searchReq) { return mapSheetMngRepository.findMapSheetErrorList(searchReq); } public Page findMapSheetMngList( - MapSheetMngDto.@Valid searchReq searchReq) { + MapSheetMngDto.@Valid searchReq searchReq) { return mapSheetMngRepository.findMapSheetMngList(searchReq); } + public MapSheetMngDto.DmlReturn uploadFile(MultipartFile file, Long hstUid) { + MapSheetMngHstEntity entity = + mapSheetMngRepository + .findMapSheetMngHstInfo(hstUid) + .orElseThrow(() -> new EntityNotFoundException("해당 이력이 존재하지 않습니다.")); + + String localPath = ""; + String rootDir = ORIGINAL_IMAGES_PATH + "/" + entity.getMngYyyy(); + if ("local".equals(activeEnv)) { + rootDir = localPath + rootDir; + } + + try { + Path uploadPath = Paths.get(rootDir); + if (!Files.exists(uploadPath)) { + Files.createDirectories(uploadPath); + } + + String originalFilename = file.getOriginalFilename(); + if (originalFilename == null) { + throw new IllegalArgumentException("파일명이 없습니다."); + } + Path filePath = uploadPath.resolve(originalFilename); + file.transferTo(filePath); + + return new MapSheetMngDto.DmlReturn("success", "파일 업로드 성공"); + } catch (IOException e) { + throw new RuntimeException("파일 업로드 실패", e); + } + } + + public MapSheetMngDto.DmlReturn deleteFile(MapSheetMngDto.DeleteFileReq req) { + try { + Path filePath = Paths.get(req.getFilePath()); + if (Files.deleteIfExists(filePath)) { + return new MapSheetMngDto.DmlReturn("success", "파일 삭제 성공"); + } else { + return new MapSheetMngDto.DmlReturn("fail", "파일이 존재하지 않습니다."); + } + } catch (IOException e) { + throw new RuntimeException("파일 삭제 실패", e); + } + } + public MapSheetMngDto.DmlReturn uploadProcess(@Valid List hstUidList) { int count = 0; if (!Objects.isNull(hstUidList) && !hstUidList.isEmpty()) { for (Long hstUid : hstUidList) { Optional entity = - Optional.ofNullable( - mapSheetMngRepository - .findMapSheetMngHstInfo(hstUid) - .orElseThrow(EntityNotFoundException::new)); + Optional.ofNullable( + mapSheetMngRepository + .findMapSheetMngHstInfo(hstUid) + .orElseThrow(EntityNotFoundException::new)); // TODO: local TEST 시 각자 경로 수정하기 // TODO: application.yml 에 active profile : local 로 임시 변경하여 테스트 @@ -82,10 +127,10 @@ public class MapSheetMngCoreService { if (!Objects.isNull(hstUidList) && !hstUidList.isEmpty()) { for (Long hstUid : hstUidList) { Optional entity = - Optional.ofNullable( - mapSheetMngRepository - .findMapSheetMngHstInfo(hstUid) - .orElseThrow(EntityNotFoundException::new)); + Optional.ofNullable( + mapSheetMngRepository + .findMapSheetMngHstInfo(hstUid) + .orElseThrow(EntityNotFoundException::new)); // entity.get().updateUseInference(true); } @@ -106,10 +151,10 @@ public class MapSheetMngCoreService { // 모든 파일명을 Set으로 저장 Set fileNames = - paths - .filter(Files::isRegularFile) - .map(p -> p.getFileName().toString()) - .collect(Collectors.toSet()); + paths + .filter(Files::isRegularFile) + .map(p -> p.getFileName().toString()) + .collect(Collectors.toSet()); // 모든 확장자 파일 존재 여부 확인 for (String ext : extensions) {