From eaa246201cc8991032b2c6541e00acb3a8be6e72 Mon Sep 17 00:00:00 2001 From: taking Date: Wed, 11 Oct 2023 11:43:32 +0000 Subject: [PATCH 1/7] =?UTF-8?q?Chore:=20=ED=8C=8C=EC=9D=BC=20FileUrl=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nw/build.gradle | 2 +- nw/src/main/java/lab/cherry/nw/model/FileEntity.java | 7 ++++++- nw/src/main/java/lab/cherry/nw/model/QsheetEntity.java | 1 + .../java/lab/cherry/nw/service/Impl/FileServiceImpl.java | 8 +++++++- nw/src/main/java/lab/cherry/nw/util/Common.java | 9 ++++----- 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/nw/build.gradle b/nw/build.gradle index 708c692..8cc8aff 100644 --- a/nw/build.gradle +++ b/nw/build.gradle @@ -14,7 +14,7 @@ dependencies { runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5' implementation 'org.springframework:spring-context:6.0.7' implementation 'org.springframework:spring-context-support:6.0.7' - implementation 'com.sun.mail:jakarta.mail:2.0.1' + implementation 'jakarta.mail:jakarta.mail-api:2.1.2' implementation 'org.springframework.boot:spring-boot-starter-mail:3.0.2' implementation 'org.springframework.boot:spring-boot-starter-data-redis:3.0.2' implementation 'io.lettuce:lettuce-core' diff --git a/nw/src/main/java/lab/cherry/nw/model/FileEntity.java b/nw/src/main/java/lab/cherry/nw/model/FileEntity.java index 18f6029..f409517 100644 --- a/nw/src/main/java/lab/cherry/nw/model/FileEntity.java +++ b/nw/src/main/java/lab/cherry/nw/model/FileEntity.java @@ -27,7 +27,7 @@ @Builder @NoArgsConstructor @AllArgsConstructor @Document(collection = "files") -@JsonPropertyOrder({ "fileSeq", "fileName", "fileType", "fileExt", "filePath", "fileSize", "userId", "orgId", "created_at" }) +@JsonPropertyOrder({ "fileSeq", "fileName", "fileType", "fileExt", "filePath", "fileUrl", "fileSize", "userId", "orgId", "created_at" }) public class FileEntity implements Serializable { @Id @@ -50,6 +50,11 @@ public class FileEntity implements Serializable { @Schema(title = "파일 경로", example = "관리/더 글로리/IMG_61E29A079818-1.jpeg") private String path; + @NotNull + @JsonProperty("fileUrl") + @Schema(title = "파일 URL", example = "https://{IP_ADDR}:{PORT}/api/v1/file/download/6506ebb61b6deb1602d85c35?path=/관리/더 글로리/IMG_61E29A079818-1.jpeg") + private String url; + @NotNull @JsonProperty("fileSize") @Schema(title = "파일 사이즈", example = "20MB") diff --git a/nw/src/main/java/lab/cherry/nw/model/QsheetEntity.java b/nw/src/main/java/lab/cherry/nw/model/QsheetEntity.java index 009dcf8..a750c40 100644 --- a/nw/src/main/java/lab/cherry/nw/model/QsheetEntity.java +++ b/nw/src/main/java/lab/cherry/nw/model/QsheetEntity.java @@ -74,6 +74,7 @@ public class QsheetEntity implements Serializable { @Getter @Builder + @NoArgsConstructor @AllArgsConstructor public static class ItemData { @Schema(title = "큐시트 순서", example = "1") private int orderIndex; diff --git a/nw/src/main/java/lab/cherry/nw/service/Impl/FileServiceImpl.java b/nw/src/main/java/lab/cherry/nw/service/Impl/FileServiceImpl.java index f6b0904..8bde2c9 100644 --- a/nw/src/main/java/lab/cherry/nw/service/Impl/FileServiceImpl.java +++ b/nw/src/main/java/lab/cherry/nw/service/Impl/FileServiceImpl.java @@ -8,6 +8,7 @@ import lab.cherry.nw.util.FormatConverter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @@ -31,6 +32,9 @@ public class FileServiceImpl implements FileService { private final MinioService minioService; private final FileRepository fileRepository; + @Value("${server.port}") + private String server_port; + public Page getFiles(Pageable pageable) { return fileRepository.findAll(pageable); } @@ -67,14 +71,16 @@ public List uploadFiles(Map info, List fi throw new RuntimeException(e); } + String fileUrl = "/api/v1/file/download/" + orgId + "?path=" + filePath; // 파일 객체 ID 저장 - fileObjectIds.add(filePath); + fileObjectIds.add(fileUrl); FileEntity fileEntity = FileEntity.builder() .name(file.getOriginalFilename()) .size(FormatConverter.convertInputBytes(file.getSize())) .type(file.getContentType()) .path(filePath) + .url(fileUrl) .userid(userName) .orgid(orgId) .created_at(Instant.now()) diff --git a/nw/src/main/java/lab/cherry/nw/util/Common.java b/nw/src/main/java/lab/cherry/nw/util/Common.java index 895294c..abe34b7 100644 --- a/nw/src/main/java/lab/cherry/nw/util/Common.java +++ b/nw/src/main/java/lab/cherry/nw/util/Common.java @@ -1,13 +1,12 @@ package lab.cherry.nw.util; -import jakarta.servlet.http.HttpServletRequest; -import lombok.extern.slf4j.Slf4j; +import java.util.ArrayList; +import java.util.List; import org.springframework.data.domain.Sort; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; - -import java.util.ArrayList; -import java.util.List; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; @Slf4j public class Common { From c5ce99d9043c848ccca9626f46d1e17b1776814e Mon Sep 17 00:00:00 2001 From: taking Date: Thu, 12 Oct 2023 11:37:55 +0000 Subject: [PATCH 2/7] Feat: Qsheet Download, Fix: Minor Updated --- .../cherry/nw/configuration/Initalizer.java | 18 ++- .../WebSecurityConfiguration.java | 3 +- .../cherry/nw/controller/FileController.java | 141 ++++++++++++------ .../nw/controller/QsheetController.java | 22 +++ .../nw/controller/WeddinghallController.java | 34 +++-- .../lab/cherry/nw/error/enums/ErrorCode.java | 3 +- .../lab/cherry/nw/model/QsheetEntity.java | 7 + .../cherry/nw/repository/BoardRepository.java | 2 +- .../nw/repository/BookmarkRepository.java | 2 +- .../nw/repository/FinalTemplRepository.java | 10 +- .../nw/repository/FinaldocsRepository.java | 15 +- .../nw/repository/QsheetRepository.java | 2 +- .../nw/repository/ScheduleRepository.java | 11 +- .../cherry/nw/repository/TagRepository.java | 2 +- .../nw/repository/UserCardRepository.java | 12 +- .../lab/cherry/nw/service/FileService.java | 7 +- .../nw/service/Impl/FileServiceImpl.java | 79 +++++++--- .../nw/service/Impl/MinioServiceImpl.java | 51 ++++--- .../nw/service/Impl/QsheetServiceImpl.java | 60 +++++++- .../nw/service/Impl/UserServiceImpl.java | 10 ++ .../lab/cherry/nw/service/QsheetService.java | 2 + .../lab/cherry/nw/service/UserService.java | 1 + .../java/lab/cherry/nw/util/HttpUtils.java | 50 +++++++ 23 files changed, 407 insertions(+), 137 deletions(-) create mode 100644 nw/src/main/java/lab/cherry/nw/util/HttpUtils.java diff --git a/nw/src/main/java/lab/cherry/nw/configuration/Initalizer.java b/nw/src/main/java/lab/cherry/nw/configuration/Initalizer.java index 0be2f3e..77772e9 100644 --- a/nw/src/main/java/lab/cherry/nw/configuration/Initalizer.java +++ b/nw/src/main/java/lab/cherry/nw/configuration/Initalizer.java @@ -7,12 +7,15 @@ import lab.cherry.nw.repository.OrgRepository; import lab.cherry.nw.repository.RoleRepository; import lab.cherry.nw.repository.UserRepository; +import lab.cherry.nw.service.MinioService; import lombok.RequiredArgsConstructor; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Component; - +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; import java.time.Instant; @RequiredArgsConstructor @@ -23,6 +26,7 @@ public class Initalizer implements ApplicationRunner { private final RoleRepository roleRepository; private final OrgRepository orgRepository; private final PasswordEncoder passwordEncoder; + private final MinioService minioService; @Override public void run(ApplicationArguments args) { @@ -69,7 +73,7 @@ public void run(ApplicationArguments args) { .userid("admin") .username("관리자") .password(passwordEncoder.encode("admin")) - .email("admin@test.com") + .email("admin@localhost.com") .type("org") .role(roleEntity) .enabled(true) @@ -91,5 +95,15 @@ public void run(ApplicationArguments args) { .enabled(true) .build()); } + + // 'user' Bucket 생성 + try { + minioService.createBucketIfNotExists("user"); + minioService.createGlobalPolicy("user"); + minioService.setBucketPolicy("user"); + } catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) { + // log.error("{}, e"); + // e.printStackTrace(); + } } } \ No newline at end of file diff --git a/nw/src/main/java/lab/cherry/nw/configuration/WebSecurityConfiguration.java b/nw/src/main/java/lab/cherry/nw/configuration/WebSecurityConfiguration.java index c5cc5b7..85b1ab6 100644 --- a/nw/src/main/java/lab/cherry/nw/configuration/WebSecurityConfiguration.java +++ b/nw/src/main/java/lab/cherry/nw/configuration/WebSecurityConfiguration.java @@ -60,7 +60,8 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti "/swagger-resources/**", "/swagger-ui/**", "/swagger-ui.html", - "/api/v1/file/download/**" // TODO: download/{orgId} 에 대해 각 orgId 소속만 접근 가능하는 기능 추가 필요 + "/api/v1/file/download/**", // TODO: download/{orgId} 에 대해 각 orgId 소속만 접근 가능하는 기능 추가 필요 + "/api/v1/file/test" ) .permitAll() .requestMatchers("/api/v1/**").hasAnyRole("ADMIN", "USER") // spring boot 에서 ROLE_ 은 자동으로 붙음 diff --git a/nw/src/main/java/lab/cherry/nw/controller/FileController.java b/nw/src/main/java/lab/cherry/nw/controller/FileController.java index 5879e2b..3b1a93e 100644 --- a/nw/src/main/java/lab/cherry/nw/controller/FileController.java +++ b/nw/src/main/java/lab/cherry/nw/controller/FileController.java @@ -1,14 +1,11 @@ package lab.cherry.nw.controller; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import lab.cherry.nw.error.ResultResponse; -import lab.cherry.nw.error.enums.SuccessCode; -import lab.cherry.nw.model.FileEntity; -import lab.cherry.nw.service.FileService; -import lab.cherry.nw.util.Common; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.zip.ZipOutputStream; +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.springframework.core.io.InputStreamResource; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -18,9 +15,22 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.io.InputStream; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lab.cherry.nw.error.ResultResponse; +import lab.cherry.nw.error.enums.SuccessCode; +import lab.cherry.nw.model.FileEntity; +import lab.cherry.nw.service.FileService; +import lab.cherry.nw.util.Common; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; /** *
@@ -64,17 +74,6 @@ public ResponseEntity findAllFiles(
 		Pageable pageable = PageRequest.of(page, size, Sort.by(Common.getOrder(sort)));
 
 		Page fileEntity = fileService.getFiles(pageable);
-//		if(userid == null && orgid == null) {
-//			fileEntity = fileService.getFiles(pageable);
-//		}
-//		else {
-//			fileEntity = fileService.findPageByUserId(userid, pageable);
-//		}
-//		} else {
-//			fileEntity = fileService.getFiles(pageable);
-//		}
-
-		//        final ResultResponse response = ResultResponse.of(SuccessCode.OK, userService.getUsers());
 		return new ResponseEntity<>(fileEntity, new HttpHeaders(), HttpStatus.OK);
 	}
 
@@ -121,7 +120,6 @@ public ResponseEntity findByFilePath(@RequestParam(required = true) String pa
 		return new ResponseEntity<>(response, new HttpHeaders(), HttpStatus.OK);
 	}
 
-
 	/**
      * [FileController] 특정 파일 다운로드 함수
      *
@@ -129,31 +127,80 @@ public ResponseEntity findByFilePath(@RequestParam(required = true) String pa
      *
      * Author : taking(taking@duck.com)
      */
-	@GetMapping("/download/{orgId}")
-    @Operation(summary = "특정 파일 다운로드", description = "특정 파일을 다운로드합니다.")
-    public ResponseEntity downloadFile(
-			@RequestParam(required = false) String path,
+     @GetMapping("/download/{orgId}")
+     @Operation(summary = "특정 파일 다운로드", description = "특정 파일을 다운로드합니다.")
+     public ResponseEntity downloadFile(
+               @RequestParam(required = false) Boolean qsheet,
+			@RequestParam(required = false) List path,
 			@PathVariable String orgId) {
 
-		// MinioService를 사용하여 MinIO 서버로부터 파일을 가져옵니다.
-		InputStream fileInputStream = fileService.downloadFile(orgId, path);
+          if(path.size() > 1) {
+
+               ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+               try (ZipOutputStream zipOut = new ZipOutputStream(byteArrayOutputStream)) {
+                    for (String data : path) {
+
+                         String[] parts = data.split("/");
+                         String fileName = parts[parts.length - 1];
+
+                         byte[] objectData = fileService.downloadZip(orgId, data);
+
+                         // Zip 아카이브에 객체 추가
+                         ZipArchiveEntry zipEntry = new ZipArchiveEntry(fileName + ".zip");
+                         zipOut.putNextEntry(zipEntry);
+                         zipOut.write(objectData);
+                         zipOut.closeEntry();
+
+                    }
+               } catch (IOException e) {
+                    log.error("{}", e);
+               }
+          
+               byte[] zipBytes = byteArrayOutputStream.toByteArray();
+               
+               HttpHeaders headers = new HttpHeaders();
+               headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + "download.zip");
+
+               return new ResponseEntity<>(zipBytes, headers, HttpStatus.OK);
+
+          } else {
+
+               String objectName = path.get(0);
 
-		// 문자열을 '/'로 분할
-		String[] parts = path.split("/");
+               if(chkExtension(path.get(0))) {
 
-		// 마지막 요소 확인
-		String fileName = parts[parts.length - 1];
+                    // MinioService를 사용하여 MinIO 서버로부터 파일을 가져옵니다.
+                    InputStream fileInputStream = fileService.downloadFile(orgId, objectName);
 
-		// 파일 다운로드를 위한 헤더 설정
-		HttpHeaders headers = new HttpHeaders();
-		headers.setContentDispositionFormData("attachment", fileName); // 다운로드할 때 파일 이름 지정
-		headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
+                    // 문자열을 '/'로 분할
+                    String[] parts = objectName.split("/");
 
-		// 파일 스트림을 InputStreamResource로 래핑하여 응답합니다.
-		InputStreamResource resource = new InputStreamResource(fileInputStream);
+                    // 마지막 요소 확인
+                    String fileName = parts[parts.length - 1];
+
+                    // 파일 다운로드를 위한 헤더 설정
+                    HttpHeaders headers = new HttpHeaders();
+                    headers.setContentDispositionFormData("attachment", fileName); // 다운로드할 때 파일 이름 지정
+                    headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
+
+                    // 파일 스트림을 InputStreamResource로 래핑하여 응답합니다.
+                    InputStreamResource resource = new InputStreamResource(fileInputStream);
+
+                    return new ResponseEntity<>(resource, headers, HttpStatus.OK);
+
+               } else {
+
+                    // 파일 다운로드를 위한 헤더 설정
+                    HttpHeaders headers = new HttpHeaders();
+                    headers.setContentDispositionFormData("attachment", "download.zip"); // 다운로드할 때 파일 이름 지정
+                    headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
+
+                    return new ResponseEntity<>(fileService.downloadZip(orgId, objectName), headers, HttpStatus.OK);
+
+               }
+
+          }
 
-		//        final ResultResponse response = ResultResponse.of(SuccessCode.OK, userService.getUsers());
-		return new ResponseEntity<>(resource, headers, HttpStatus.OK);
 	}
 
 
@@ -180,4 +227,14 @@ public ResponseEntity deleteFile(@PathVariable("id") String id) {
 		final ResultResponse response = ResultResponse.of(SuccessCode.OK);
 		return new ResponseEntity<>(response, new HttpHeaders(), HttpStatus.OK);
 	}
+
+     public Boolean chkExtension(String path) {
+          String extension = StringUtils.getFilenameExtension(path);
+
+          if (extension == null) {
+               return false;
+          } else {
+               return true;
+          }
+     }
 }
diff --git a/nw/src/main/java/lab/cherry/nw/controller/QsheetController.java b/nw/src/main/java/lab/cherry/nw/controller/QsheetController.java
index fc3c413..646c8de 100644
--- a/nw/src/main/java/lab/cherry/nw/controller/QsheetController.java
+++ b/nw/src/main/java/lab/cherry/nw/controller/QsheetController.java
@@ -15,6 +15,7 @@
 import lab.cherry.nw.util.Common;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import java.util.List;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageRequest;
 import org.springframework.data.domain.Pageable;
@@ -171,5 +172,26 @@ public ResponseEntity findByQsheetId(@PathVariable("id") String id) {
         //        final ResultResponse response = ResultResponse.of(SuccessCode.OK, userService.findById(id));
         return new ResponseEntity<>(qsheetService.findById(id), new HttpHeaders(), HttpStatus.OK);
     }
+    
+	/**
+     * [QsheetController] 큐시트 사용자 파일 다운로드 함수
+     *
+     * @return 큐시트 사용자 파일을 반환합니다.
+     *
+     * Author : taking(taking@duck.com)
+     */
+    @PostMapping("/download")
+    @Operation(summary = "큐시트 사용자 파일 다운로드", description = "큐시트 사용자 파일을 다운로드합니다.")
+    public ResponseEntity downloadQsheetBySeq(@RequestBody QsheetEntity.QsheetDownloadDto qsheetDownloadDto) {
+
+        log.info("[QsheetController] downloadQsheetBySeq...!");
+
+
+        HttpHeaders headers = new HttpHeaders();
+        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + "download.zip");
+
+        return new ResponseEntity<>(qsheetService.download(qsheetDownloadDto.getUser()), new HttpHeaders(), HttpStatus.OK);
+
+   }
 
 }
diff --git a/nw/src/main/java/lab/cherry/nw/controller/WeddinghallController.java b/nw/src/main/java/lab/cherry/nw/controller/WeddinghallController.java
index be9dc4e..2f4ced5 100644
--- a/nw/src/main/java/lab/cherry/nw/controller/WeddinghallController.java
+++ b/nw/src/main/java/lab/cherry/nw/controller/WeddinghallController.java
@@ -1,5 +1,23 @@
 package lab.cherry.nw.controller;
 
+import java.util.List;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.media.Content;
 import io.swagger.v3.oas.annotations.media.Schema;
@@ -10,27 +28,11 @@
 import lab.cherry.nw.error.ErrorResponse;
 import lab.cherry.nw.error.ResultResponse;
 import lab.cherry.nw.error.enums.SuccessCode;
-import lab.cherry.nw.model.UserEntity;
 import lab.cherry.nw.model.WeddinghallEntity;
-import lab.cherry.nw.service.MinioService;
-import lab.cherry.nw.service.UserService;
 import lab.cherry.nw.service.WeddinghallService;
 import lab.cherry.nw.util.Common;
 import lombok.RequiredArgsConstructor;
-import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Sort;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.util.List;
 
 /**
  * 
diff --git a/nw/src/main/java/lab/cherry/nw/error/enums/ErrorCode.java b/nw/src/main/java/lab/cherry/nw/error/enums/ErrorCode.java
index 17b36f7..24bf4f3 100644
--- a/nw/src/main/java/lab/cherry/nw/error/enums/ErrorCode.java
+++ b/nw/src/main/java/lab/cherry/nw/error/enums/ErrorCode.java
@@ -29,7 +29,8 @@ public enum ErrorCode {
     FORBIDDEN(403, "접근 권한이 없어 거부되었습니다."),
     ACCESS_DENIED_EXCEPTION(401, "인증 정보가 유효하지 않습니다."),
     DUPLICATE(409, "중복된 데이터가 있습니다."),
-    NO_BODY(400, "파라미터 값이 입력되지 않았습니다.");
+    NO_BODY(400, "파라미터 값이 입력되지 않았습니다."),
+    URL_NOTFOUND(400, "Minio URL을 다시 확인해주세요.");
 
     private final int status;
     private final String message;
diff --git a/nw/src/main/java/lab/cherry/nw/model/QsheetEntity.java b/nw/src/main/java/lab/cherry/nw/model/QsheetEntity.java
index 7c28fea..7ab109b 100644
--- a/nw/src/main/java/lab/cherry/nw/model/QsheetEntity.java
+++ b/nw/src/main/java/lab/cherry/nw/model/QsheetEntity.java
@@ -154,5 +154,12 @@ public void updateFromDto(QsheetUpdateDto updateDto) {
         }
     }
 
+    @Getter
+    @Builder
+    @NoArgsConstructor @AllArgsConstructor
+    public static class QsheetDownloadDto {
+		@Schema(title = "사용자 리스트")
+		private List user;
+    }
 
 }
diff --git a/nw/src/main/java/lab/cherry/nw/repository/BoardRepository.java b/nw/src/main/java/lab/cherry/nw/repository/BoardRepository.java
index 0696b11..048c2f9 100644
--- a/nw/src/main/java/lab/cherry/nw/repository/BoardRepository.java
+++ b/nw/src/main/java/lab/cherry/nw/repository/BoardRepository.java
@@ -16,7 +16,7 @@
  * Related : BoardServiceImpl, BoardService
  * 
*/ -public interface BoardRepository extends MongoRepository { +public interface BoardRepository extends MongoRepository { Page findAll(Pageable pageable); Page findPageByUserid(String userid, Pageable pageable); diff --git a/nw/src/main/java/lab/cherry/nw/repository/BookmarkRepository.java b/nw/src/main/java/lab/cherry/nw/repository/BookmarkRepository.java index 020eee5..7655f2a 100644 --- a/nw/src/main/java/lab/cherry/nw/repository/BookmarkRepository.java +++ b/nw/src/main/java/lab/cherry/nw/repository/BookmarkRepository.java @@ -19,7 +19,7 @@ * Related : BookmarkServiceImpl, BookmarkService *
*/ -public interface BookmarkRepository extends MongoRepository { +public interface BookmarkRepository extends MongoRepository { Page findAll(Pageable pageable); diff --git a/nw/src/main/java/lab/cherry/nw/repository/FinalTemplRepository.java b/nw/src/main/java/lab/cherry/nw/repository/FinalTemplRepository.java index 9a632e1..da47db9 100644 --- a/nw/src/main/java/lab/cherry/nw/repository/FinalTemplRepository.java +++ b/nw/src/main/java/lab/cherry/nw/repository/FinalTemplRepository.java @@ -1,13 +1,11 @@ package lab.cherry.nw.repository; -import lab.cherry.nw.model.FinalTemplEntity; +import java.util.List; +import java.util.Optional; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.mongodb.repository.MongoRepository; - -import java.util.List; -import java.util.Optional; -import java.util.UUID; +import lab.cherry.nw.model.FinalTemplEntity; /** @@ -19,7 +17,7 @@ * */ //@Repository -public interface FinalTemplRepository extends MongoRepository { +public interface FinalTemplRepository extends MongoRepository { Page findAll(Pageable pageable); diff --git a/nw/src/main/java/lab/cherry/nw/repository/FinaldocsRepository.java b/nw/src/main/java/lab/cherry/nw/repository/FinaldocsRepository.java index e0e3df7..1d1fa15 100644 --- a/nw/src/main/java/lab/cherry/nw/repository/FinaldocsRepository.java +++ b/nw/src/main/java/lab/cherry/nw/repository/FinaldocsRepository.java @@ -1,17 +1,12 @@ package lab.cherry.nw.repository; -import lab.cherry.nw.model.FinaldocsEntity; -import lab.cherry.nw.model.OrgEntity; -import lab.cherry.nw.model.ScheduleEntity; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.mongodb.repository.MongoRepository; - import java.time.Instant; -import java.time.LocalDateTime; import java.util.List; import java.util.Optional; -import java.util.UUID; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.mongodb.repository.MongoRepository; +import lab.cherry.nw.model.FinaldocsEntity; /** @@ -23,7 +18,7 @@ * */ //@Repository -public interface FinaldocsRepository extends MongoRepository { +public interface FinaldocsRepository extends MongoRepository { Page findAll(Pageable pageable); diff --git a/nw/src/main/java/lab/cherry/nw/repository/QsheetRepository.java b/nw/src/main/java/lab/cherry/nw/repository/QsheetRepository.java index 9aaff75..555954b 100644 --- a/nw/src/main/java/lab/cherry/nw/repository/QsheetRepository.java +++ b/nw/src/main/java/lab/cherry/nw/repository/QsheetRepository.java @@ -16,7 +16,7 @@ * Related : QsheetServiceImpl, QsheetService * */ -public interface QsheetRepository extends MongoRepository { +public interface QsheetRepository extends MongoRepository { Page findAll(Pageable pageable); Page findPageByUserid(String userid, Pageable pageable); diff --git a/nw/src/main/java/lab/cherry/nw/repository/ScheduleRepository.java b/nw/src/main/java/lab/cherry/nw/repository/ScheduleRepository.java index 8691c1c..69a63c5 100644 --- a/nw/src/main/java/lab/cherry/nw/repository/ScheduleRepository.java +++ b/nw/src/main/java/lab/cherry/nw/repository/ScheduleRepository.java @@ -1,14 +1,11 @@ package lab.cherry.nw.repository; -import lab.cherry.nw.model.ScheduleEntity; +import java.util.List; +import java.util.Optional; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.mongodb.repository.MongoRepository; - -import java.time.LocalDateTime; -import java.util.List; -import java.util.Optional; -import java.util.UUID; +import lab.cherry.nw.model.ScheduleEntity; /** @@ -20,7 +17,7 @@ * */ //@Repository -public interface ScheduleRepository extends MongoRepository { +public interface ScheduleRepository extends MongoRepository { Page findAll(Pageable pageable); diff --git a/nw/src/main/java/lab/cherry/nw/repository/TagRepository.java b/nw/src/main/java/lab/cherry/nw/repository/TagRepository.java index 17de5ae..4678294 100644 --- a/nw/src/main/java/lab/cherry/nw/repository/TagRepository.java +++ b/nw/src/main/java/lab/cherry/nw/repository/TagRepository.java @@ -16,7 +16,7 @@ * Related : TagServiceImpl, TagService * */ -public interface TagRepository extends MongoRepository { +public interface TagRepository extends MongoRepository { Page findAll(Pageable pageable); Optional findByName(String name); diff --git a/nw/src/main/java/lab/cherry/nw/repository/UserCardRepository.java b/nw/src/main/java/lab/cherry/nw/repository/UserCardRepository.java index 8293cad..199dd19 100644 --- a/nw/src/main/java/lab/cherry/nw/repository/UserCardRepository.java +++ b/nw/src/main/java/lab/cherry/nw/repository/UserCardRepository.java @@ -1,15 +1,11 @@ package lab.cherry.nw.repository; -import lab.cherry.nw.model.OrgEntity; -import lab.cherry.nw.model.UserCardEntity; -import org.apache.catalina.User; +import java.util.List; +import java.util.Optional; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.mongodb.repository.MongoRepository; - -import java.util.List; -import java.util.Optional; -import java.util.UUID; +import lab.cherry.nw.model.UserCardEntity; /** @@ -21,7 +17,7 @@ * */ //@Repository -public interface UserCardRepository extends MongoRepository { +public interface UserCardRepository extends MongoRepository { Page findAll(Pageable pageable); diff --git a/nw/src/main/java/lab/cherry/nw/service/FileService.java b/nw/src/main/java/lab/cherry/nw/service/FileService.java index 2f06eff..3835f71 100644 --- a/nw/src/main/java/lab/cherry/nw/service/FileService.java +++ b/nw/src/main/java/lab/cherry/nw/service/FileService.java @@ -1,12 +1,16 @@ package lab.cherry.nw.service; import lab.cherry.nw.model.FileEntity; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.InputStreamResource; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; - +import java.io.IOException; import java.io.InputStream; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; import java.util.List; import java.util.Map; @@ -29,5 +33,6 @@ public interface FileService { void deleteById(String id); InputStream downloadFile(String orgId, String path); + byte[] downloadZip(String bucketName, String objectName); void deleteFiles(String orgId, List images); } \ No newline at end of file diff --git a/nw/src/main/java/lab/cherry/nw/service/Impl/FileServiceImpl.java b/nw/src/main/java/lab/cherry/nw/service/Impl/FileServiceImpl.java index 8bde2c9..c88472d 100644 --- a/nw/src/main/java/lab/cherry/nw/service/Impl/FileServiceImpl.java +++ b/nw/src/main/java/lab/cherry/nw/service/Impl/FileServiceImpl.java @@ -1,28 +1,36 @@ package lab.cherry.nw.service.Impl; -import lab.cherry.nw.error.exception.EntityNotFoundException; -import lab.cherry.nw.model.FileEntity; -import lab.cherry.nw.repository.FileRepository; -import lab.cherry.nw.service.FileService; -import lab.cherry.nw.service.MinioService; -import lab.cherry.nw.util.FormatConverter; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.multipart.MultipartFile; - import java.io.IOException; import java.io.InputStream; +import java.net.URI; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.time.Instant; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.tomcat.util.codec.binary.Base64; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.InputStreamResource; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.util.UriComponentsBuilder; +import lab.cherry.nw.error.enums.ErrorCode; +import lab.cherry.nw.error.exception.CustomException; +import lab.cherry.nw.error.exception.EntityNotFoundException; +import lab.cherry.nw.model.FileEntity; +import lab.cherry.nw.repository.FileRepository; +import lab.cherry.nw.service.FileService; +import lab.cherry.nw.service.MinioService; +import lab.cherry.nw.util.FormatConverter; +import lab.cherry.nw.util.HttpUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; @Slf4j @Service @@ -32,8 +40,15 @@ public class FileServiceImpl implements FileService { private final MinioService minioService; private final FileRepository fileRepository; - @Value("${server.port}") - private String server_port; + + @Value("${minio.url}") + private String minioUrl; + + @Value("${minio.access-key}") + private String accessKey; + + @Value("${minio.secret-key}") + private String secretKey; public Page getFiles(Pageable pageable) { return fileRepository.findAll(pageable); @@ -118,7 +133,35 @@ public InputStream downloadFile(String orgId, String path) { return null; } - public void deleteById(String id) { + @Override + public byte[] downloadZip(String bucketName, String objectName) { + + objectName = Base64.encodeBase64String(objectName.getBytes()); + String addr = minioUrl.substring(0, minioUrl.length()-5) + ":9001"; + + try { + URI uri = UriComponentsBuilder + .fromUriString(addr) + .path("/api/v1/buckets/{bucketName}/objects/download") + // .encode() + .queryParam("prefix", objectName) + .build() + .expand(bucketName, objectName) + .toUri(); + + log.error("uri {}", uri); + return HttpUtils.getForObject(uri); + + } catch (Exception ex) { + log.error("error {}", ex); + log.error("error.msg {}", ex.getMessage()); + // throw new CustomException(ErrorCode.URL_NOTFOUND); + } + + return null; + } + + public void deleteById(String id) { FileEntity fileEntity = findById(id); try { diff --git a/nw/src/main/java/lab/cherry/nw/service/Impl/MinioServiceImpl.java b/nw/src/main/java/lab/cherry/nw/service/Impl/MinioServiceImpl.java index 34ce5a0..0265774 100644 --- a/nw/src/main/java/lab/cherry/nw/service/Impl/MinioServiceImpl.java +++ b/nw/src/main/java/lab/cherry/nw/service/Impl/MinioServiceImpl.java @@ -1,34 +1,41 @@ package lab.cherry.nw.service.Impl; -import io.minio.*; +import java.io.IOException; +import java.io.InputStream; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.bouncycastle.crypto.InvalidCipherTextException; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import io.minio.BucketExistsArgs; +import io.minio.GetBucketPolicyArgs; +import io.minio.GetObjectArgs; +import io.minio.GetPresignedObjectUrlArgs; +import io.minio.ListObjectsArgs; +import io.minio.MakeBucketArgs; +import io.minio.MinioClient; +import io.minio.PutObjectArgs; +import io.minio.RemoveBucketArgs; +import io.minio.RemoveObjectArgs; +import io.minio.RemoveObjectsArgs; +import io.minio.Result; +import io.minio.SetBucketPolicyArgs; import io.minio.admin.MinioAdminClient; import io.minio.admin.UserInfo; -import io.minio.errors.*; +import io.minio.errors.MinioException; import io.minio.http.Method; import io.minio.messages.DeleteError; import io.minio.messages.DeleteObject; import io.minio.messages.Item; import lab.cherry.nw.model.UserEntity; import lab.cherry.nw.service.MinioService; -import lab.cherry.nw.service.UserService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; -import org.springframework.web.multipart.MultipartFile; - -import java.io.IOException; -import java.io.InputStream; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import org.springframework.beans.factory.annotation.Value; @Slf4j @Service @@ -153,7 +160,7 @@ public InputStream getObject(String bucketName, String objectName) throws IOExce log.error("Minio Connect Check : {}", isMinioConnected()); - log.error("bucketName is {}, objectName is {}", bucketName, objectName); + log.error("\nbucketName is {}\nobjectName is {}\n", bucketName, objectName); // bucketName에 있는 objectName을 조회합니다. InputStream stream = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build()); @@ -341,6 +348,9 @@ public String getPresignedURL(String bucketName, String objectName) throws IOExc Map reqParams = new HashMap(); reqParams.put("response-content-type", "application/json"); + log.error("bucketName {}", bucketName); + log.error("objectName {}", objectName); + // Presigned URL 생성 return minioClient.getPresignedObjectUrl( GetPresignedObjectUrlArgs.builder() @@ -350,6 +360,7 @@ public String getPresignedURL(String bucketName, String objectName) throws IOExc .expiry(1, TimeUnit.HOURS) // 시간 .extraQueryParams(reqParams) .build()); + } catch (MinioException e) { log.error("Error occurred: " + e); } diff --git a/nw/src/main/java/lab/cherry/nw/service/Impl/QsheetServiceImpl.java b/nw/src/main/java/lab/cherry/nw/service/Impl/QsheetServiceImpl.java index 861c2d9..4f96cd0 100644 --- a/nw/src/main/java/lab/cherry/nw/service/Impl/QsheetServiceImpl.java +++ b/nw/src/main/java/lab/cherry/nw/service/Impl/QsheetServiceImpl.java @@ -7,17 +7,25 @@ import lab.cherry.nw.model.QsheetEntity; import lab.cherry.nw.model.UserEntity; import lab.cherry.nw.repository.QsheetRepository; +import lab.cherry.nw.service.FileService; import lab.cherry.nw.service.OrgService; import lab.cherry.nw.service.QsheetService; import lab.cherry.nw.service.UserService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; - +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.zip.ZipOutputStream; /** *
@@ -36,6 +44,7 @@ public class QsheetServiceImpl implements QsheetService {
     private final QsheetRepository qsheetRepository;
     private final UserService userService;
     private final OrgService orgService;
+    private final FileService fileService;
     /**
      * [QsheetServiceImpl] 전체 큐시트 조회 함수
      *
@@ -207,4 +216,53 @@ public Page findPageByOrgId(String orgid, Pageable pageable) {
         return qsheetRepository.findPageByOrgid(orgid, pageable);
     }
     
+    public byte[] download(List users) {
+        
+        List userList = new ArrayList<>();
+        List userData = new ArrayList<>();
+
+        for(String user : users) {
+            if (userService.checkId(user)) {
+                UserEntity _user = userService.findById(user);
+                userList.add(_user);
+
+                String objectName = _user.getId() +"/";
+                userData.add(fileService.downloadZip("user", objectName)); 
+            }
+        }
+
+        if(userList.size() > 1) {
+
+            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+            try (ZipOutputStream zipOut = new ZipOutputStream(byteArrayOutputStream)) {
+                for (UserEntity user : userList) {
+
+                        String objectName = user.getId() +"/";
+
+                        byte[] objectData = fileService.downloadZip("user", objectName);
+
+                        // Zip 아카이브에 객체 추가
+                        ZipArchiveEntry zipEntry = new ZipArchiveEntry(user.getUsername() + ".zip");
+                        zipOut.putNextEntry(zipEntry);
+                        zipOut.write(objectData);
+                        zipOut.closeEntry();
+
+                }
+            } catch (IOException e) {
+                log.error("{}", e);
+            }
+        
+            byte[] zipBytes = byteArrayOutputStream.toByteArray();
+            
+            return zipBytes;
+
+        } else {
+
+            UserEntity user = userService.findById(users.get(0));
+
+            String objectName = "사용자/" + user.getId();
+
+            return fileService.downloadZip(user.getOrg().getId(), objectName);
+        }
+    }
 }
diff --git a/nw/src/main/java/lab/cherry/nw/service/Impl/UserServiceImpl.java b/nw/src/main/java/lab/cherry/nw/service/Impl/UserServiceImpl.java
index fdc87b7..8d47443 100644
--- a/nw/src/main/java/lab/cherry/nw/service/Impl/UserServiceImpl.java
+++ b/nw/src/main/java/lab/cherry/nw/service/Impl/UserServiceImpl.java
@@ -179,4 +179,14 @@ public UserEntity findById(String id) {
     public Page findPageByUserId(String userid, Pageable pageable) {
         return userRepository.findPageByUserid(userid, pageable);
     }
+
+    public Boolean checkId(String id) {
+
+        // userSeq가 DB에 존재할 시, true
+        if(userRepository.findById(id).isPresent()) {
+            return true;
+        } else {
+            return false;
+        }
+    }
 }
diff --git a/nw/src/main/java/lab/cherry/nw/service/QsheetService.java b/nw/src/main/java/lab/cherry/nw/service/QsheetService.java
index c19bbf7..61ced63 100644
--- a/nw/src/main/java/lab/cherry/nw/service/QsheetService.java
+++ b/nw/src/main/java/lab/cherry/nw/service/QsheetService.java
@@ -1,6 +1,7 @@
 package lab.cherry.nw.service;
 
 import lab.cherry.nw.model.QsheetEntity;
+import java.util.List;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 import org.springframework.stereotype.Component;
@@ -25,4 +26,5 @@ public interface QsheetService {
  Page findPageByUserId(String userid, Pageable pageable);
  Page findPageByOrgId(String orgid, Pageable pageable);
 // void updateOrgById(String id, List orgIds);
+byte[] download(List users);
 }
\ No newline at end of file
diff --git a/nw/src/main/java/lab/cherry/nw/service/UserService.java b/nw/src/main/java/lab/cherry/nw/service/UserService.java
index 775e127..07e5011 100644
--- a/nw/src/main/java/lab/cherry/nw/service/UserService.java
+++ b/nw/src/main/java/lab/cherry/nw/service/UserService.java
@@ -17,6 +17,7 @@
 public interface UserService {
     Page getUsers(Pageable pageable);
     UserEntity findById(String id);
+    Boolean checkId(String id);
 	UserEntity findByUserId(String userid);
     void updateById(String id, UserEntity.UserUpdateDto user);
     void deleteById(String id);
diff --git a/nw/src/main/java/lab/cherry/nw/util/HttpUtils.java b/nw/src/main/java/lab/cherry/nw/util/HttpUtils.java
new file mode 100644
index 0000000..c33523e
--- /dev/null
+++ b/nw/src/main/java/lab/cherry/nw/util/HttpUtils.java
@@ -0,0 +1,50 @@
+package lab.cherry.nw.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.ObjectInputStream;
+import java.net.URI;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.client.RestTemplate;
+import lombok.extern.slf4j.Slf4j;
+
+
+@Slf4j
+public class HttpUtils {
+
+	public static byte[] httpRequest(URI uri, String Method, HttpHeaders headers){
+
+		HttpMethod _method;
+
+		switch (Method) {
+			case "GET":
+				_method = HttpMethod.GET;
+			case "POST":
+				_method = HttpMethod.POST;
+			case "DELETE":
+				_method = HttpMethod.DELETE;
+			default:
+				_method = HttpMethod.GET;
+		}
+
+		RestTemplate restTemplate = new RestTemplate();
+		ResponseEntity result = restTemplate.exchange(uri, _method, new HttpEntity<>(headers), byte[].class);
+
+		return result.getBody();
+
+		// log.error("result {}", result);
+
+		// return result.getBody();
+
+	}
+
+
+	public static byte[] getForObject(URI uri){
+
+		RestTemplate restTemplate = new RestTemplate();
+		return restTemplate.getForObject(uri, byte[].class);
+
+	}	
+}
\ No newline at end of file

From adaa85f3312e537a72ca36b6a80d1aeaa3e3cb04 Mon Sep 17 00:00:00 2001
From: taking 
Date: Thu, 12 Oct 2023 11:44:42 +0000
Subject: [PATCH 3/7] Refactor: Organize Imports

---
 .../nw/configuration/email/EmailConfig.java   |  7 -----
 .../nw/controller/BookmarkController.java     | 25 +++++++++++-------
 .../cherry/nw/controller/EmailController.java |  7 ++---
 .../nw/controller/FinalTemplController.java   | 25 +++++++++++-------
 .../nw/controller/FinaldocsController.java    | 25 +++++++++++-------
 .../nw/controller/QsheetController.java       | 25 +++++++++++-------
 .../cherry/nw/controller/TagController.java   | 23 +++++++++-------
 .../nw/controller/UserCardController.java     | 26 ++++++++++++-------
 .../lab/cherry/nw/error/ErrorResponse.java    |  1 -
 .../java/lab/cherry/nw/model/BoardEntity.java | 14 +++++-----
 .../lab/cherry/nw/model/BookmarkEntity.java   | 18 +++++--------
 .../lab/cherry/nw/model/ScheduleEntity.java   | 22 ++++++++--------
 .../java/lab/cherry/nw/model/TagEntity.java   | 14 ++--------
 .../lab/cherry/nw/model/UserCardEntity.java   | 16 +++++-------
 .../cherry/nw/repository/OrgRepository.java   |  8 +++---
 15 files changed, 132 insertions(+), 124 deletions(-)

diff --git a/nw/src/main/java/lab/cherry/nw/configuration/email/EmailConfig.java b/nw/src/main/java/lab/cherry/nw/configuration/email/EmailConfig.java
index 8524e57..87a3594 100644
--- a/nw/src/main/java/lab/cherry/nw/configuration/email/EmailConfig.java
+++ b/nw/src/main/java/lab/cherry/nw/configuration/email/EmailConfig.java
@@ -1,7 +1,6 @@
 package lab.cherry.nw.configuration.email;
 
 import java.util.Properties;
-
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -9,12 +8,6 @@
 import org.springframework.mail.javamail.JavaMailSender;
 import org.springframework.mail.javamail.JavaMailSenderImpl;
 
-import org.springframework.boot.context.properties.ConfigurationProperties;
-
-import lombok.Getter;
-import lombok.Setter;
-import lombok.ToString;
-
 
 //@ConfigurationProperties(prefix = "mail")
 @Configuration
diff --git a/nw/src/main/java/lab/cherry/nw/controller/BookmarkController.java b/nw/src/main/java/lab/cherry/nw/controller/BookmarkController.java
index 8c3aaed..910872a 100644
--- a/nw/src/main/java/lab/cherry/nw/controller/BookmarkController.java
+++ b/nw/src/main/java/lab/cherry/nw/controller/BookmarkController.java
@@ -1,5 +1,21 @@
 package lab.cherry.nw.controller;
 
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PatchMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.media.Content;
 import io.swagger.v3.oas.annotations.media.Schema;
@@ -15,15 +31,6 @@
 import lab.cherry.nw.util.Common;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.bson.types.ObjectId;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Sort;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.*;
 
 /**
  * 
diff --git a/nw/src/main/java/lab/cherry/nw/controller/EmailController.java b/nw/src/main/java/lab/cherry/nw/controller/EmailController.java
index e1c5a7d..87631d5 100644
--- a/nw/src/main/java/lab/cherry/nw/controller/EmailController.java
+++ b/nw/src/main/java/lab/cherry/nw/controller/EmailController.java
@@ -1,10 +1,11 @@
 package lab.cherry.nw.controller;
 
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 import lab.cherry.nw.service.EmailService;
 import lombok.RequiredArgsConstructor;
-import org.springframework.data.crossstore.ChangeSetPersister;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.*;
 
 @RestController
 @RequiredArgsConstructor
diff --git a/nw/src/main/java/lab/cherry/nw/controller/FinalTemplController.java b/nw/src/main/java/lab/cherry/nw/controller/FinalTemplController.java
index 907d70d..f30e5cf 100644
--- a/nw/src/main/java/lab/cherry/nw/controller/FinalTemplController.java
+++ b/nw/src/main/java/lab/cherry/nw/controller/FinalTemplController.java
@@ -1,5 +1,21 @@
 package lab.cherry.nw.controller;
 
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PatchMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.media.Content;
 import io.swagger.v3.oas.annotations.media.Schema;
@@ -11,19 +27,10 @@
 import lab.cherry.nw.error.ResultResponse;
 import lab.cherry.nw.error.enums.SuccessCode;
 import lab.cherry.nw.model.FinalTemplEntity;
-import lab.cherry.nw.model.OrgEntity;
 import lab.cherry.nw.service.FinalTemplService;
 import lab.cherry.nw.util.Common;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Sort;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.*;
 
 /**
  * 
diff --git a/nw/src/main/java/lab/cherry/nw/controller/FinaldocsController.java b/nw/src/main/java/lab/cherry/nw/controller/FinaldocsController.java
index dfb23b0..5f8cfb3 100644
--- a/nw/src/main/java/lab/cherry/nw/controller/FinaldocsController.java
+++ b/nw/src/main/java/lab/cherry/nw/controller/FinaldocsController.java
@@ -1,5 +1,21 @@
 package lab.cherry.nw.controller;
 
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PatchMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.media.Content;
 import io.swagger.v3.oas.annotations.media.Schema;
@@ -11,19 +27,10 @@
 import lab.cherry.nw.error.ResultResponse;
 import lab.cherry.nw.error.enums.SuccessCode;
 import lab.cherry.nw.model.FinaldocsEntity;
-import lab.cherry.nw.model.OrgEntity;
 import lab.cherry.nw.service.FinaldocsService;
 import lab.cherry.nw.util.Common;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Sort;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.*;
 
 /**
  * 
diff --git a/nw/src/main/java/lab/cherry/nw/controller/QsheetController.java b/nw/src/main/java/lab/cherry/nw/controller/QsheetController.java
index 646c8de..0f22e1e 100644
--- a/nw/src/main/java/lab/cherry/nw/controller/QsheetController.java
+++ b/nw/src/main/java/lab/cherry/nw/controller/QsheetController.java
@@ -1,5 +1,21 @@
 package lab.cherry.nw.controller;
 
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PatchMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.media.Content;
 import io.swagger.v3.oas.annotations.media.Schema;
@@ -15,15 +31,6 @@
 import lab.cherry.nw.util.Common;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import java.util.List;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Sort;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.*;
 
 /**
  * 
diff --git a/nw/src/main/java/lab/cherry/nw/controller/TagController.java b/nw/src/main/java/lab/cherry/nw/controller/TagController.java
index c16d997..c757dbe 100644
--- a/nw/src/main/java/lab/cherry/nw/controller/TagController.java
+++ b/nw/src/main/java/lab/cherry/nw/controller/TagController.java
@@ -1,5 +1,19 @@
 package lab.cherry.nw.controller;
 
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.media.Content;
 import io.swagger.v3.oas.annotations.media.Schema;
@@ -15,15 +29,6 @@
 import lab.cherry.nw.util.Common;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.bson.types.ObjectId;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Sort;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.*;
 
 /**
  * 
diff --git a/nw/src/main/java/lab/cherry/nw/controller/UserCardController.java b/nw/src/main/java/lab/cherry/nw/controller/UserCardController.java
index 0f8080f..1ace637 100644
--- a/nw/src/main/java/lab/cherry/nw/controller/UserCardController.java
+++ b/nw/src/main/java/lab/cherry/nw/controller/UserCardController.java
@@ -1,5 +1,21 @@
 package lab.cherry.nw.controller;
 
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PatchMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.media.Content;
 import io.swagger.v3.oas.annotations.media.Schema;
@@ -10,21 +26,11 @@
 import lab.cherry.nw.error.ErrorResponse;
 import lab.cherry.nw.error.ResultResponse;
 import lab.cherry.nw.error.enums.SuccessCode;
-import lab.cherry.nw.model.OrgEntity;
 import lab.cherry.nw.model.UserCardEntity;
-import lab.cherry.nw.service.OrgService;
 import lab.cherry.nw.service.UserCardService;
 import lab.cherry.nw.util.Common;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Sort;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.*;
 
 /**
  * 
diff --git a/nw/src/main/java/lab/cherry/nw/error/ErrorResponse.java b/nw/src/main/java/lab/cherry/nw/error/ErrorResponse.java
index 278e402..070d808 100644
--- a/nw/src/main/java/lab/cherry/nw/error/ErrorResponse.java
+++ b/nw/src/main/java/lab/cherry/nw/error/ErrorResponse.java
@@ -1,6 +1,5 @@
 package lab.cherry.nw.error;
 
-import io.swagger.v3.oas.annotations.media.Schema;
 import lab.cherry.nw.error.enums.ErrorCode;
 import java.util.ArrayList;
 import java.util.List;
diff --git a/nw/src/main/java/lab/cherry/nw/model/BoardEntity.java b/nw/src/main/java/lab/cherry/nw/model/BoardEntity.java
index 6ec7de9..af67ee3 100644
--- a/nw/src/main/java/lab/cherry/nw/model/BoardEntity.java
+++ b/nw/src/main/java/lab/cherry/nw/model/BoardEntity.java
@@ -1,21 +1,19 @@
 package lab.cherry.nw.model;
 
+import java.io.Serializable;
+import java.time.Instant;
+import java.util.List;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.DBRef;
+import org.springframework.data.mongodb.core.mapping.Document;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonPropertyOrder;
 import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.Size;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
-import org.springframework.data.annotation.Id;
-import org.springframework.data.mongodb.core.mapping.DBRef;
-import org.springframework.data.mongodb.core.mapping.Document;
-
-import java.io.Serializable;
-import java.time.Instant;
-import java.util.List;
 
 
 /**
diff --git a/nw/src/main/java/lab/cherry/nw/model/BookmarkEntity.java b/nw/src/main/java/lab/cherry/nw/model/BookmarkEntity.java
index 4812d03..20aeb37 100644
--- a/nw/src/main/java/lab/cherry/nw/model/BookmarkEntity.java
+++ b/nw/src/main/java/lab/cherry/nw/model/BookmarkEntity.java
@@ -1,25 +1,19 @@
 package lab.cherry.nw.model;
 
+import java.io.Serializable;
+import java.time.Instant;
+import java.util.Map;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.DBRef;
+import org.springframework.data.mongodb.core.mapping.Document;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonPropertyOrder;
 import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.Size;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
-import org.springframework.data.annotation.Id;
-import org.springframework.data.mongodb.core.aggregation.VariableOperators;
-import org.springframework.data.mongodb.core.mapping.DBRef;
-import org.springframework.data.mongodb.core.mapping.Document;
-
-import java.io.Serializable;
-import java.time.Instant;
-import java.util.Comparator;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.stream.Collectors;
 
 
 /**
diff --git a/nw/src/main/java/lab/cherry/nw/model/ScheduleEntity.java b/nw/src/main/java/lab/cherry/nw/model/ScheduleEntity.java
index f479cb8..5c56bc9 100644
--- a/nw/src/main/java/lab/cherry/nw/model/ScheduleEntity.java
+++ b/nw/src/main/java/lab/cherry/nw/model/ScheduleEntity.java
@@ -1,20 +1,20 @@
 package lab.cherry.nw.model;
 
-import com.fasterxml.jackson.annotation.JsonFormat;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.DBRef;
+import org.springframework.data.mongodb.core.mapping.Document;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonPropertyOrder;
 import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.Size;
-import lombok.*;
-import org.springframework.data.annotation.Id;
-import org.springframework.data.mongodb.core.mapping.DBRef;
-import org.springframework.data.mongodb.core.mapping.Document;
-
-import java.io.Serializable;
-import java.time.Instant;
-import java.time.LocalDateTime;
-import java.util.List;
-import java.util.Map;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
 
 /**
  * 
diff --git a/nw/src/main/java/lab/cherry/nw/model/TagEntity.java b/nw/src/main/java/lab/cherry/nw/model/TagEntity.java
index 29064c6..114b84a 100644
--- a/nw/src/main/java/lab/cherry/nw/model/TagEntity.java
+++ b/nw/src/main/java/lab/cherry/nw/model/TagEntity.java
@@ -1,6 +1,7 @@
 package lab.cherry.nw.model;
 
-import com.fasterxml.jackson.annotation.JsonFormat;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonPropertyOrder;
 import io.swagger.v3.oas.annotations.media.Schema;
@@ -9,17 +10,6 @@
 import lombok.Builder;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
-import org.springframework.data.annotation.Id;
-import org.springframework.data.mongodb.core.mapping.DBRef;
-import org.springframework.data.mongodb.core.mapping.Document;
-
-import java.io.Serializable;
-import java.time.Instant;
-import java.util.Comparator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
 
 
 /**
diff --git a/nw/src/main/java/lab/cherry/nw/model/UserCardEntity.java b/nw/src/main/java/lab/cherry/nw/model/UserCardEntity.java
index cf10a51..247c426 100644
--- a/nw/src/main/java/lab/cherry/nw/model/UserCardEntity.java
+++ b/nw/src/main/java/lab/cherry/nw/model/UserCardEntity.java
@@ -1,24 +1,20 @@
 package lab.cherry.nw.model;
 
+import java.io.Serializable;
+import java.time.Instant;
+import java.util.Map;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.DBRef;
+import org.springframework.data.mongodb.core.mapping.Document;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonPropertyOrder;
 import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.Email;
 import jakarta.validation.constraints.Size;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
-import org.springframework.data.annotation.Id;
-import org.springframework.data.mongodb.core.mapping.DBRef;
-import org.springframework.data.mongodb.core.mapping.Document;
-
-import java.io.Serializable;
-import java.time.Instant;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
 
 /**
  * 
diff --git a/nw/src/main/java/lab/cherry/nw/repository/OrgRepository.java b/nw/src/main/java/lab/cherry/nw/repository/OrgRepository.java
index 836ff60..6b3dc47 100644
--- a/nw/src/main/java/lab/cherry/nw/repository/OrgRepository.java
+++ b/nw/src/main/java/lab/cherry/nw/repository/OrgRepository.java
@@ -1,13 +1,11 @@
 package lab.cherry.nw.repository;
 
-import lab.cherry.nw.model.FinaldocsEntity;
-import lab.cherry.nw.model.OrgEntity;
+import java.util.List;
+import java.util.Optional;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.mongodb.repository.MongoRepository;
-
-import java.util.List;
-import java.util.Optional;
+import lab.cherry.nw.model.OrgEntity;
 
 
 /**

From d9f6a471dae861b8020762fd9bbedf4427333f81 Mon Sep 17 00:00:00 2001
From: taking 
Date: Sat, 14 Oct 2023 03:12:32 +0000
Subject: [PATCH 4/7] Fix: Minor Updated

---
 application.properties_docker                                  | 3 +++
 .../main/java/lab/cherry/nw/controller/QsheetController.java   | 3 ++-
 nw/src/main/resources/application.properties_sample            | 3 +++
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/application.properties_docker b/application.properties_docker
index 8da10b1..f338d91 100644
--- a/application.properties_docker
+++ b/application.properties_docker
@@ -12,6 +12,9 @@ server.port=8888
 #server.error.include-message=always
 server.servlet.encoding.charset=UTF-8
 server.servlet.encoding.force=true
+spring.servlet.multipart.max-file-size=3096MB
+spring.servlet.multipart.max-request-size=3096MB
+spring.servlet.multipart.enabled=true
 
 # Swagger springdoc-ui Configuration
 spring.messages.encoding=UTF-8
diff --git a/nw/src/main/java/lab/cherry/nw/controller/QsheetController.java b/nw/src/main/java/lab/cherry/nw/controller/QsheetController.java
index bb6b3b2..0f5f0fa 100644
--- a/nw/src/main/java/lab/cherry/nw/controller/QsheetController.java
+++ b/nw/src/main/java/lab/cherry/nw/controller/QsheetController.java
@@ -7,6 +7,7 @@
 import org.springframework.data.domain.Sort;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -99,7 +100,7 @@ public ResponseEntity findAllQsheets(
      *
      * Author : yby654(yby654@github.com)
      */
-    @PostMapping("")
+    @PostMapping(value = "", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_OCTET_STREAM_VALUE})
     @ApiResponses(value = {
             @ApiResponse(responseCode = "200", description = "큐시트 생성이 완료되었습니다.", content = @Content(schema = @Schema(implementation = ResponseEntity.class))),
             @ApiResponse(responseCode = "400", description = "입력 값이 잘못 되었습니다.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
diff --git a/nw/src/main/resources/application.properties_sample b/nw/src/main/resources/application.properties_sample
index 3d30e37..7cc8fc9 100644
--- a/nw/src/main/resources/application.properties_sample
+++ b/nw/src/main/resources/application.properties_sample
@@ -12,6 +12,9 @@ server.port=8888
 #server.error.include-message=always
 server.servlet.encoding.charset=UTF-8
 server.servlet.encoding.force=true
+spring.servlet.multipart.max-file-size=3096MB
+spring.servlet.multipart.max-request-size=3096MB
+spring.servlet.multipart.enabled=true
 
 # Swagger springdoc-ui Configuration
 spring.messages.encoding=UTF-8

From 13aaf5e956086cd49ecca7765f825df42b9a52d2 Mon Sep 17 00:00:00 2001
From: taking 
Date: Sun, 15 Oct 2023 10:27:26 +0000
Subject: [PATCH 5/7] Fix: MultipartFile Fix

---
 .../cherry/nw/controller/QsheetController.java   | 16 +---------------
 1 file changed, 1 insertion(+), 15 deletions(-)

diff --git a/nw/src/main/java/lab/cherry/nw/controller/QsheetController.java b/nw/src/main/java/lab/cherry/nw/controller/QsheetController.java
index d0462a6..52b30da 100644
--- a/nw/src/main/java/lab/cherry/nw/controller/QsheetController.java
+++ b/nw/src/main/java/lab/cherry/nw/controller/QsheetController.java
@@ -109,13 +109,6 @@ public ResponseEntity findAllQsheets(
     @Operation(summary = "Qsheet 생성", description = "Qsheet를 추가합니다.")
     public ResponseEntity createQsheet(@RequestPart QsheetEntity.QsheetCreateDto qsheetCreateDto, @RequestPart(required = false) List files) {
         log.info("[QsheetController] createQsheet...!");
-        log.error ("files : {}", files);
-        for(MultipartFile file:files){
-            if(file.isEmpty()){
-                files = null;
-                break;
-            }
-        }
         
         qsheetService.createQsheet(qsheetCreateDto, files);
 
@@ -139,14 +132,7 @@ public ResponseEntity createQsheet(@RequestPart QsheetEntity.QsheetCreateDto
     public ResponseEntity updateById(
             @PathVariable("id") String id,
             @RequestPart QsheetEntity.QsheetUpdateDto qsheetUpdateDto, @RequestPart(required = false) List files) {
-            
-        log.info("[QsheetController] updateQsheet...!");
-        for(MultipartFile file:files){
-            if(file.isEmpty()){
-                files = null;
-                break;
-            }
-        }
+                
         qsheetService.updateById(id, qsheetUpdateDto, files);
 
 //        final ResultResponse response = ResultResponse.of(SuccessCode.OK);

From 1ad2e68719ae4d87369fe63e6a2e7aab7223d3c3 Mon Sep 17 00:00:00 2001
From: taking 
Date: Tue, 17 Oct 2023 08:54:23 +0000
Subject: [PATCH 6/7] Fix: QSheet File Updated

---
 .../lab/cherry/nw/configuration/bean/BeanConfig.java  |  7 +++----
 .../lab/cherry/nw/controller/QsheetController.java    |  1 -
 .../lab/cherry/nw/service/Impl/QsheetServiceImpl.java | 11 +++++++----
 3 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/nw/src/main/java/lab/cherry/nw/configuration/bean/BeanConfig.java b/nw/src/main/java/lab/cherry/nw/configuration/bean/BeanConfig.java
index d2ce64f..ecf438a 100644
--- a/nw/src/main/java/lab/cherry/nw/configuration/bean/BeanConfig.java
+++ b/nw/src/main/java/lab/cherry/nw/configuration/bean/BeanConfig.java
@@ -1,7 +1,6 @@
 package lab.cherry.nw.configuration.bean;
 
-import lab.cherry.nw.service.security.CustomUserDetailsService;
-import lombok.RequiredArgsConstructor;
+import java.util.Arrays;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.data.mongodb.core.mapping.event.ValidatingMongoEventListener;
@@ -16,8 +15,8 @@
 import org.springframework.web.cors.CorsConfigurationSource;
 import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
 import org.yaml.snakeyaml.Yaml;
-
-import java.util.Arrays;
+import lab.cherry.nw.service.security.CustomUserDetailsService;
+import lombok.RequiredArgsConstructor;
 
 /**
  * 
diff --git a/nw/src/main/java/lab/cherry/nw/controller/QsheetController.java b/nw/src/main/java/lab/cherry/nw/controller/QsheetController.java
index 52b30da..4056e3d 100644
--- a/nw/src/main/java/lab/cherry/nw/controller/QsheetController.java
+++ b/nw/src/main/java/lab/cherry/nw/controller/QsheetController.java
@@ -200,7 +200,6 @@ public ResponseEntity downloadQsheetBySeq(@RequestBody QsheetEntity.QsheetDow
 
         HttpHeaders headers = new HttpHeaders();
         headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + "download.zip");
-
         return new ResponseEntity<>(qsheetService.download(qsheetDownloadDto.getUser()), new HttpHeaders(), HttpStatus.OK);
 
    }
diff --git a/nw/src/main/java/lab/cherry/nw/service/Impl/QsheetServiceImpl.java b/nw/src/main/java/lab/cherry/nw/service/Impl/QsheetServiceImpl.java
index e1fb92a..ef4ad00 100644
--- a/nw/src/main/java/lab/cherry/nw/service/Impl/QsheetServiceImpl.java
+++ b/nw/src/main/java/lab/cherry/nw/service/Impl/QsheetServiceImpl.java
@@ -244,7 +244,7 @@ public void updateById(String id, QsheetEntity.QsheetUpdateDto qsheetUpdateDto,
             //     .org_confirm(qsheetUpdateDto.getFinalConfirm().isOrg_confirm()==!(qsheetEntity.getFinalConfirm().isOrg_confirm())?qsheetUpdateDto.getFinalConfirm().isOrg_confirm():qsheetEntity.getFinalConfirm().isOrg_confirm())
             //     .client_confirm(qsheetUpdateDto.getFinalConfirm().isClient_confirm()==!(qsheetEntity.getFinalConfirm().isClient_confirm())?qsheetUpdateDto.getFinalConfirm().isClient_confirm():qsheetEntity.getFinalConfirm().isClient_confirm())    
             //     .build():qsheetEntity.getFinalConfirm() )
-            .memo(qsheetUpdateDto.getMemo())
+            .memo(qsheetUpdateDto.getMemo() != null ? qsheetUpdateDto.getMemo() : qsheetEntity.getMemo())
 			.updated_at(instant)
 			.build();
 			qsheetRepository.save(qsheetEntity);
@@ -340,17 +340,20 @@ public byte[] download(List users) {
         List userData = new ArrayList<>();
 
         for(String user : users) {
+
             if (userService.checkId(user)) {
                 UserEntity _user = userService.findById(user);
                 userList.add(_user);
 
-                String objectName = _user.getId() +"/";
-                userData.add(fileService.downloadZip("user", objectName)); 
+                // String objectName = _user.getId() + "/";
+                // userData.add(fileService.downloadZip("user", objectName));
             }
         }
 
         if(userList.size() > 1) {
 
+            log.error("userList 가 1명 초과인 경우 # ", userList.size());
+
             ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
             try (ZipOutputStream zipOut = new ZipOutputStream(byteArrayOutputStream)) {
                 for (UserEntity user : userList) {
@@ -380,7 +383,7 @@ public byte[] download(List users) {
 
             String objectName = "사용자/" + user.getId();
 
-            return fileService.downloadZip(user.getOrg().getId(), objectName);
+            return fileService.downloadZip("user", objectName);
         }
     }
 }

From 540893cca7f652db6e27458fd07bd231125798c8 Mon Sep 17 00:00:00 2001
From: taking 
Date: Wed, 25 Oct 2023 03:33:43 +0000
Subject: [PATCH 7/7] =?UTF-8?q?Chore:=20=ED=8C=8C=EC=9D=BC=20=EA=B4=80?=
 =?UTF-8?q?=EB=A6=AC=20=EA=B8=B0=EB=8A=A5=20-=20minio=20=EC=A0=9C=EA=B1=B0?=
 =?UTF-8?q?,=20GridFS=20=EC=B6=94=EA=B0=80=20Fix:=20Organize=20Imports?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 application.properties_docker                 |  10 +-
 docker-compose.yml                            |  28 +-
 docker-compose/.env                           |  11 +-
 docker-compose/docker-compose.yml             |  16 -
 .../cherry/nw/configuration/Initalizer.java   |  21 +-
 .../nw/configuration/bean/MinioConfig.java    |  84 ----
 .../nw/configuration/filter/JwtFilter.java    |   2 +-
 .../nw/controller/BanquetController.java      |   8 +-
 .../cherry/nw/controller/FileController.java  | 104 ++---
 .../nw/controller/PyebaeksilController.java   |   8 +-
 .../nw/controller/WeddinghallController.java  |   8 +-
 .../lab/cherry/nw/error/enums/ErrorCode.java  |   4 +-
 .../lab/cherry/nw/model/BanquetEntity.java    |   6 +-
 .../java/lab/cherry/nw/model/FileEntity.java  |  23 +-
 .../java/lab/cherry/nw/model/OrgEntity.java   |  21 +-
 .../lab/cherry/nw/model/PyebaeksilEntity.java |   6 +-
 .../java/lab/cherry/nw/model/UserEntity.java  |   2 +-
 .../cherry/nw/model/WeddinghallEntity.java    |   6 +-
 .../cherry/nw/repository/FileRepository.java  |   2 +-
 .../lab/cherry/nw/service/FileService.java    |   7 +-
 .../nw/service/Impl/BanquetServiceImpl.java   |  52 ++-
 .../nw/service/Impl/FileServiceImpl.java      | 324 +++++++++------
 .../nw/service/Impl/MinioServiceImpl.java     | 369 ------------------
 .../nw/service/Impl/OrgServiceImpl.java       |  44 +--
 .../service/Impl/PyebaeksilServiceImpl.java   |  38 +-
 .../service/Impl/WeddinghallServiceImpl.java  |  88 ++---
 .../lab/cherry/nw/service/MinioService.java   |  49 ---
 .../cherry/nw/service/WeddinghallService.java |   2 +-
 .../resources/application.properties_sample   |   6 +-
 29 files changed, 398 insertions(+), 951 deletions(-)
 delete mode 100644 nw/src/main/java/lab/cherry/nw/configuration/bean/MinioConfig.java
 delete mode 100644 nw/src/main/java/lab/cherry/nw/service/Impl/MinioServiceImpl.java
 delete mode 100644 nw/src/main/java/lab/cherry/nw/service/MinioService.java

diff --git a/application.properties_docker b/application.properties_docker
index f338d91..08a57ba 100644
--- a/application.properties_docker
+++ b/application.properties_docker
@@ -12,8 +12,8 @@ server.port=8888
 #server.error.include-message=always
 server.servlet.encoding.charset=UTF-8
 server.servlet.encoding.force=true
-spring.servlet.multipart.max-file-size=3096MB
-spring.servlet.multipart.max-request-size=3096MB
+spring.servlet.multipart.max-file-size=${MAX_UPLOAD_SIZE:3096MB}
+spring.servlet.multipart.max-request-size=${MAX_UPLOAD_SIZE:3096MB}
 spring.servlet.multipart.enabled=true
 
 # Swagger springdoc-ui Configuration
@@ -45,8 +45,4 @@ spring.mail.password=${SMTP_PASS:-passWord}
 #echo 'lab-cherry-nw-project-secret-key' | base64
 lab.cherry.nw.jwtSecret= bGFiLWNoZXJyeS1udy1wcm9qZWN0LXNlY3JldC1rZXkK
 lab.cherry.nw.jwtExpirationMs= 86400000
-
-# MinIo Properties
-minio.url=${MINIO_URL:-http://nw-storage:9000}
-minio.access-key=${MINIO_ACCESS_KEY:-admin}
-minio.secret-key=${MINIO_SECRET_KEY:-nangmanwedding}
\ No newline at end of file
+lab.cherry.nw.uploadPath= ${UPLOAD_PATH:/data}
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
index a53369f..c8ef642 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -12,6 +12,8 @@ services:
       DATABASE_NAME: nw
       DATABASE_USERID: nw
       DATABASE_USERPASS: nw
+      UPLOAD_PATH: /data
+      MAX_UPLOAD_SIZE: 3096MB
       #SPRING_PROFILES_ACTIVE: prod
       JAVA_OPTS: "-Xms256m -Xmx512m -XX:+UseG1GC"
     ports:
@@ -19,10 +21,8 @@ services:
     depends_on:
       - nw-db
       - nw-redis
-      - nw-storage
-    #    volumes:
-#      - ./log:/log/spring
-
+    volumes:
+      - ./nw_data:/data
 
   nw-db:
     image: 'bitnami/mongodb:latest'
@@ -55,22 +55,4 @@ services:
       - no-new-privileges:true
     volumes:
       - './redis_data:/data'
-      - '/etc/localtime:/etc/localtime:ro'
-
-
-  nw-storage:
-    image: 'minio/minio:RELEASE.2023-09-04T19-57-37Z'
-    container_name: nw-storage
-    command: server --console-address ":9001" /data
-    restart: unless-stopped
-    logging:
-      driver: json-file
-    environment:
-      MINIO_ACCESS_KEY: admin
-      MINIO_SECRET_KEY: nangmanwedding
-    ports:
-      - "9000:9000"
-      - "9001:9001"
-    volumes:
-      - './storage_data:/data'
-
+      - '/etc/localtime:/etc/localtime:ro'
\ No newline at end of file
diff --git a/docker-compose/.env b/docker-compose/.env
index e7feaef..3ee03b4 100644
--- a/docker-compose/.env
+++ b/docker-compose/.env
@@ -8,9 +8,8 @@ DATABASE_NAME=nw
 DATABASE_USERID=admin
 DATABASE_USERPASS=admin
 #SPRING_PROFILES_ACTIVE=prod
-MINIO_URL=http://nw-storage:9000
-MINIO_ACCESS_KEY=admin
-MINIO_SECRET_KEY=4FqfsKQUVWsca3MsAUVtgcf2  
+UPLOAD_PATH=/data
+MAX_UPLOAD_SIZE=3096MB
 REDIS_HOST=nw-redis
 REDIS_PORT=8083
 JAVA_OPTS="-Xms256m -Xmx512m -XX:+UseG1GC"
@@ -26,8 +25,4 @@ SMTP_PASS=null
 # nw-db
 MONGO_INITDB_DATABASE=nw
 MONGO_INITDB_ROOT_USERNAME=admin
-MONGO_INITDB_ROOT_PASSWORD=admin
-
-# nw-storage
-MINIO_ROOT_USER=admin
-MINIO_ROOT_PASSWORD=4FqfsKQUVWsca3MsAUVtgcf2
\ No newline at end of file
+MONGO_INITDB_ROOT_PASSWORD=admin
\ No newline at end of file
diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml
index 58b44f1..ff310c9 100644
--- a/docker-compose/docker-compose.yml
+++ b/docker-compose/docker-compose.yml
@@ -10,7 +10,6 @@ services:
     ports:
       - "8081:8888"
     depends_on:
-      - nw-storage
       - nw-db
       - nw-redis
       - nw-smtp
@@ -42,21 +41,6 @@ services:
       - './redis_data:/data'
       - '/etc/localtime:/etc/localtime:ro'
 
-  nw-storage:
-    image: 'minio/minio:RELEASE.2023-09-04T19-57-37Z'
-    container_name: nw-storage
-    command: server --console-address ":9001" /data
-    restart: unless-stopped
-    logging:
-      driver: json-file
-    env_file:
-      - ./.env
-    ports:
-      - "9000:9000"
-      - "9001:9001"
-    volumes:
-      - './storage_data:/data'
-
   mailhog:
       image: jcalonso/mailhog
       container_name: 'mailhog'
diff --git a/nw/src/main/java/lab/cherry/nw/configuration/Initalizer.java b/nw/src/main/java/lab/cherry/nw/configuration/Initalizer.java
index 77772e9..cac656e 100644
--- a/nw/src/main/java/lab/cherry/nw/configuration/Initalizer.java
+++ b/nw/src/main/java/lab/cherry/nw/configuration/Initalizer.java
@@ -7,8 +7,9 @@
 import lab.cherry.nw.repository.OrgRepository;
 import lab.cherry.nw.repository.RoleRepository;
 import lab.cherry.nw.repository.UserRepository;
-import lab.cherry.nw.service.MinioService;
 import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.ApplicationArguments;
 import org.springframework.boot.ApplicationRunner;
 import org.springframework.security.crypto.password.PasswordEncoder;
@@ -18,20 +19,23 @@
 import java.security.NoSuchAlgorithmException;
 import java.time.Instant;
 
+@Slf4j
 @RequiredArgsConstructor
 @Component
 public class Initalizer implements ApplicationRunner {
+
+
+	@Value("${lab.cherry.nw.uploadPath}")
+	private String uploadPath;
     
     private final UserRepository userRepository;
     private final RoleRepository roleRepository;
     private final OrgRepository orgRepository;
     private final PasswordEncoder passwordEncoder;
-    private final MinioService minioService;
 
     @Override
     public void run(ApplicationArguments args) {
 
-
         if(roleRepository.findByName("ROLE_ADMIN").isEmpty()) {
 
             RoleEntity roleEntity = RoleEntity.builder()
@@ -58,6 +62,7 @@ public void run(ApplicationArguments args) {
                     .name("DEFAULT")
                     .biznum("123-45-67890")
                     .contact("02-0000-0000")
+                    .address("파인에비뉴")
                     .enabled(true)
                     .created_at(instant)
                     .build();
@@ -95,15 +100,5 @@ public void run(ApplicationArguments args) {
                 .enabled(true)
                 .build());
         }
-
-        // 'user' Bucket 생성
-        try {
-            minioService.createBucketIfNotExists("user");
-			minioService.createGlobalPolicy("user");
-			minioService.setBucketPolicy("user");
-        } catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) {
-            // log.error("{}, e");
-            // e.printStackTrace();
-        }
     }
 }
\ No newline at end of file
diff --git a/nw/src/main/java/lab/cherry/nw/configuration/bean/MinioConfig.java b/nw/src/main/java/lab/cherry/nw/configuration/bean/MinioConfig.java
deleted file mode 100644
index ea30977..0000000
--- a/nw/src/main/java/lab/cherry/nw/configuration/bean/MinioConfig.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package lab.cherry.nw.configuration.bean;
-
-import io.minio.MinioClient;
-import io.minio.admin.MinioAdminClient;
-import io.minio.errors.MinioException;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-/**
- * 
- * ClassName : MinioConfig
- * Type : class
- * Description : Minio 연결에 필요한 정보를 포함하고 있는 클래스입니다.
- * Related : All
- * 
- */ -@Slf4j -@Configuration -@RequiredArgsConstructor -public class MinioConfig { - - @Value("${minio.url}") - private String minioUrl; - - @Value("${minio.access-key}") - private String accessKey; - - @Value("${minio.secret-key}") - private String secretKey; - - - @Bean - public MinioAdminClient minioAdminClient() throws MinioException { - - log.error("url = {}", minioUrl); - log.error("accessKey = {}", accessKey); - log.error("secretKey = {}", secretKey); - - // Minio 클라이언트 생성 - MinioAdminClient adminClient = MinioAdminClient.builder() - .endpoint(minioUrl) - .credentials(accessKey, secretKey) - .build(); - - // 연결 및 작업 시간 제한 설정 - adminClient.setTimeout(10000, 10000, 10000); // connectTimeout, writeTimeout, readTimeout - - return adminClient; - } - - @Bean - public MinioClient minioClient() throws MinioException { - - log.error("url = {}", minioUrl); - log.error("accessKey = {}", accessKey); - log.error("secretKey = {}", secretKey); - - // Minio 클라이언트 생성 - MinioClient minioClient = MinioClient.builder() - .endpoint(minioUrl) - .credentials(accessKey, secretKey) - .build(); - - // 연결 및 작업 시간 제한 설정 - minioClient.setTimeout(10000, 10000, 10000); // connectTimeout, writeTimeout, readTimeout - - return minioClient; - } - - public boolean isMinioConnected() { - try { - // 버킷 목록을 가져와서 Minio 연결 상태 확인 - minioClient().listBuckets(); - return true; // 연결이 성공적으로 확인됨 - } catch (Exception e) { - // Minio 연결 예외 처리 - return false; // 연결 실패 - } - } - -} \ No newline at end of file diff --git a/nw/src/main/java/lab/cherry/nw/configuration/filter/JwtFilter.java b/nw/src/main/java/lab/cherry/nw/configuration/filter/JwtFilter.java index 781c077..01451cd 100644 --- a/nw/src/main/java/lab/cherry/nw/configuration/filter/JwtFilter.java +++ b/nw/src/main/java/lab/cherry/nw/configuration/filter/JwtFilter.java @@ -49,7 +49,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse } - private boolean checkAccessToken(AccessToken accessToken) { + private Boolean checkAccessToken(AccessToken accessToken) { if (accessToken == null) return false; return tokenService.validateToken(accessToken); } diff --git a/nw/src/main/java/lab/cherry/nw/controller/BanquetController.java b/nw/src/main/java/lab/cherry/nw/controller/BanquetController.java index 9fea424..bf000d3 100644 --- a/nw/src/main/java/lab/cherry/nw/controller/BanquetController.java +++ b/nw/src/main/java/lab/cherry/nw/controller/BanquetController.java @@ -103,15 +103,11 @@ public ResponseEntity findAllBanquets( @ApiResponse(responseCode = "400", description = "입력 값이 잘못되었습니다.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))) }) public ResponseEntity createBanquet(@Valid @RequestPart BanquetEntity.BanquetCreateDto banquetCreateDto, - @RequestPart List files) { + @RequestPart List images) { log.info("[BanquetController] createBanquet...!"); - - log.error("이름 : {}", banquetCreateDto.getBanquetName()); - log.error("조직 : {}", banquetCreateDto.getOrg()); - log.error("이미지 : {}", files); - BanquetEntity banquetEntity = banquetService.createBanquet(banquetCreateDto, files); + BanquetEntity banquetEntity = banquetService.createBanquet(banquetCreateDto, images); return new ResponseEntity<>(banquetEntity, new HttpHeaders(), HttpStatus.OK); } diff --git a/nw/src/main/java/lab/cherry/nw/controller/FileController.java b/nw/src/main/java/lab/cherry/nw/controller/FileController.java index 57242f5..804857d 100644 --- a/nw/src/main/java/lab/cherry/nw/controller/FileController.java +++ b/nw/src/main/java/lab/cherry/nw/controller/FileController.java @@ -1,14 +1,10 @@ package lab.cherry.nw.controller; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import java.util.List; -import java.util.zip.ZipOutputStream; -import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; -import org.springframework.core.io.InputStreamResource; +import java.util.Map; +import org.springframework.core.io.ByteArrayResource; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -128,90 +124,42 @@ public ResponseEntity findByFilePath(@RequestParam(required = true) String pa * @return 특정 파일을 반환합니다. * * Author : taking(taking@duck.com) + * @throws IOException + * @throws IllegalStateException */ - @GetMapping("/download/{orgId}") + @GetMapping("/download/{file_id}") @Operation(summary = "특정 파일 다운로드", description = "특정 파일을 다운로드합니다.") - public ResponseEntity downloadFile( - @RequestParam(required = false) Boolean qsheet, - @RequestParam(required = false) List path, - @PathVariable String orgId) { + public ResponseEntity downloadFile(@PathVariable String file_id) throws IllegalStateException, IOException { - if(path.size() > 1) { + FileEntity.LoadFile file = fileService.downloadFile(file_id); - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - try (ZipOutputStream zipOut = new ZipOutputStream(byteArrayOutputStream)) { - for (String data : path) { - - String[] parts = data.split("/"); - String fileName = parts[parts.length - 1]; - - byte[] objectData = fileService.downloadZip(orgId, data); - - // Zip 아카이브에 객체 추가 - ZipArchiveEntry zipEntry = new ZipArchiveEntry(fileName + ".zip"); - zipOut.putNextEntry(zipEntry); - zipOut.write(objectData); - zipOut.closeEntry(); - - } - } catch (IOException e) { - log.error("{}", e); - } + String fileName = null; + try { + fileName = URLEncoder.encode(file.getName(), "UTF-8"); + } catch (UnsupportedEncodingException e) { + log.error("{}", e); + } - byte[] zipBytes = byteArrayOutputStream.toByteArray(); - - HttpHeaders headers = new HttpHeaders(); - headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + "download.zip"); - - return new ResponseEntity<>(zipBytes, headers, HttpStatus.OK); - - } else { - - String objectName = path.get(0); - - if(chkExtension(path.get(0))) { - - // MinioService를 사용하여 MinIO 서버로부터 파일을 가져옵니다. - InputStream fileInputStream = fileService.downloadFile(orgId, objectName); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.parseMediaType(file.getType())); + headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\""); - // 문자열을 '/'로 분할 - String[] parts = objectName.split("/"); - - // 마지막 요소 확인 - String fileName = parts[parts.length - 1]; - - try { - fileName = URLEncoder.encode(fileName, "UTF-8"); - } catch (UnsupportedEncodingException e) { - log.error("{}", e); - } - - // 파일 다운로드를 위한 헤더 설정 - HttpHeaders headers = new HttpHeaders(); - headers.setContentDispositionFormData("attachment", fileName); // 다운로드할 때 파일 이름 지정 - headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); - - // 파일 스트림을 InputStreamResource로 래핑하여 응답합니다. - InputStreamResource resource = new InputStreamResource(fileInputStream); - - return new ResponseEntity<>(resource, headers, HttpStatus.OK); - - } else { + return new ResponseEntity<>(new ByteArrayResource(file.getFile()), headers, HttpStatus.OK); + } - // 파일 다운로드를 위한 헤더 설정 - HttpHeaders headers = new HttpHeaders(); - headers.setContentDispositionFormData("attachment", "download.zip"); // 다운로드할 때 파일 이름 지정 - headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); + @GetMapping("/downloads/{id}") + @Operation(summary = "특정 파일 그룹 다운로드", description = "특정 그룹의 파일을 일괄 다운로드합니다. (ex. 웨딩홀 Seq, 연회장 Seq, 큐시트 Seq 등)") + public ResponseEntity downloadFiles(@PathVariable String id) { - return new ResponseEntity<>(fileService.downloadZip(orgId, objectName), headers, HttpStatus.OK); + Map val = fileService.downloadFiles("seq", id); - } - - } + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.parseMediaType("application/zip")); + headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + val.get("name") + "\""); + return new ResponseEntity<>(val.get("data"), headers, HttpStatus.OK); } - /** * [FileController] 특정 파일 삭제 함수 * diff --git a/nw/src/main/java/lab/cherry/nw/controller/PyebaeksilController.java b/nw/src/main/java/lab/cherry/nw/controller/PyebaeksilController.java index a72afc8..bd848c1 100644 --- a/nw/src/main/java/lab/cherry/nw/controller/PyebaeksilController.java +++ b/nw/src/main/java/lab/cherry/nw/controller/PyebaeksilController.java @@ -103,15 +103,11 @@ public ResponseEntity findAllPyebaeksils( @ApiResponse(responseCode = "400", description = "입력 값이 잘못되었습니다.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))) }) public ResponseEntity createPyebaeksil(@Valid @RequestPart PyebaeksilEntity.PyebaeksilCreateDto pyebaeksilCreateDto, - @RequestPart List files) { + @RequestPart List images) { log.info("[PyebaeksilController] createPyebaeksil...!"); - - log.error("이름 : {}", pyebaeksilCreateDto.getPyebaeksilName()); - log.error("조직 : {}", pyebaeksilCreateDto.getOrg()); - log.error("이미지 : {}", files); - PyebaeksilEntity pyebaeksilEntity = pyebaeksilService.createPyebaeksil(pyebaeksilCreateDto, files); + PyebaeksilEntity pyebaeksilEntity = pyebaeksilService.createPyebaeksil(pyebaeksilCreateDto, images); return new ResponseEntity<>(pyebaeksilEntity, new HttpHeaders(), HttpStatus.OK); } diff --git a/nw/src/main/java/lab/cherry/nw/controller/WeddinghallController.java b/nw/src/main/java/lab/cherry/nw/controller/WeddinghallController.java index 2f4ced5..bdae561 100644 --- a/nw/src/main/java/lab/cherry/nw/controller/WeddinghallController.java +++ b/nw/src/main/java/lab/cherry/nw/controller/WeddinghallController.java @@ -103,15 +103,11 @@ public ResponseEntity findAllWeddinghalls( @ApiResponse(responseCode = "400", description = "입력 값이 잘못되었습니다.", content = @Content(schema = @Schema(implementation = ErrorResponse.class))) }) public ResponseEntity createWeddinghall(@Valid @RequestPart WeddinghallEntity.WeddinghallCreateDto weddinghallCreateDto, - @RequestPart List files) { + @RequestPart List images) { log.info("[WeddinghallController] createWeddinghall...!"); - - log.error("이름 : {}", weddinghallCreateDto.getWeddinghallName()); - log.error("조직 : {}", weddinghallCreateDto.getOrg()); - log.error("이미지 : {}", files); - WeddinghallEntity weddinghallEntity = weddinghallService.createWeddinghall(weddinghallCreateDto, files); + WeddinghallEntity weddinghallEntity = weddinghallService.createWeddinghall(weddinghallCreateDto, images); return new ResponseEntity<>(weddinghallEntity, new HttpHeaders(), HttpStatus.OK); } diff --git a/nw/src/main/java/lab/cherry/nw/error/enums/ErrorCode.java b/nw/src/main/java/lab/cherry/nw/error/enums/ErrorCode.java index 24bf4f3..033ddb4 100644 --- a/nw/src/main/java/lab/cherry/nw/error/enums/ErrorCode.java +++ b/nw/src/main/java/lab/cherry/nw/error/enums/ErrorCode.java @@ -30,7 +30,9 @@ public enum ErrorCode { ACCESS_DENIED_EXCEPTION(401, "인증 정보가 유효하지 않습니다."), DUPLICATE(409, "중복된 데이터가 있습니다."), NO_BODY(400, "파라미터 값이 입력되지 않았습니다."), - URL_NOTFOUND(400, "Minio URL을 다시 확인해주세요."); + URL_NOTFOUND(400, "Minio URL을 다시 확인해주세요."), + FILE_UPLOAD_FAILED(400, "파일 업로드에 실패했습니다."), + FOLDER_CREATE_FAILED(400, "uploadPath를 찾을 수 없습니다."); private final int status; private final String message; diff --git a/nw/src/main/java/lab/cherry/nw/model/BanquetEntity.java b/nw/src/main/java/lab/cherry/nw/model/BanquetEntity.java index b45f16b..f333dd3 100644 --- a/nw/src/main/java/lab/cherry/nw/model/BanquetEntity.java +++ b/nw/src/main/java/lab/cherry/nw/model/BanquetEntity.java @@ -93,9 +93,9 @@ public static class BanquetCreateDto { @Range(min = 1, max = 300, message = "연회장의 최대인원은 1인 이상 300명 이하만 입력 가능합니다.") private Integer maxPerson; - @NotNull(message = "[필수] Org 정보") - @Schema(title = "Org 정보", example = "더모멘트") - private String org; + @NotNull(message = "[필수] Org 고유번호") + @Schema(title = "Org 정보", example = "64ed89aa9e813b5ab16da6de") + private String orgId; @NotNull(message = "[필수] 연회장 행사 시간 간격") @Schema(title = "연회장 행사 시간 간격", example = "30") diff --git a/nw/src/main/java/lab/cherry/nw/model/FileEntity.java b/nw/src/main/java/lab/cherry/nw/model/FileEntity.java index f409517..aba086a 100644 --- a/nw/src/main/java/lab/cherry/nw/model/FileEntity.java +++ b/nw/src/main/java/lab/cherry/nw/model/FileEntity.java @@ -7,6 +7,7 @@ import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; +import lombok.Data; import lombok.Getter; import lombok.NoArgsConstructor; import org.springframework.data.annotation.Id; @@ -60,18 +61,28 @@ public class FileEntity implements Serializable { @Schema(title = "파일 사이즈", example = "20MB") private String size; - @JsonProperty("userId") - @Schema(title = "사용자 아이디", example = "admin") - private String userid; + @JsonProperty("userName") + @Schema(title = "사용자명", example = "체리랩") + private String userName; @NotNull - @JsonProperty("orgId") - @Schema(title = "조직 고유번호", example = "64ed89aa9e813b5ab16da6dd") - private String orgid; + @JsonProperty("orgName") + @Schema(title = "조직명", example = "더모멘트") + private String orgName; @JsonProperty("created_at") @JsonFormat(pattern="yyyy-MM-dd hh:mm:ss", locale = "ko_KR", timezone = "Asia/Seoul") @Schema(title = "조직 생성 시간", example = "2023-07-04 12:00:00") private Instant created_at; + + + @Data + @NoArgsConstructor @AllArgsConstructor + public static class LoadFile { + private String name; + private String type; + private String size; + private byte[] file; + } } \ No newline at end of file diff --git a/nw/src/main/java/lab/cherry/nw/model/OrgEntity.java b/nw/src/main/java/lab/cherry/nw/model/OrgEntity.java index 3072b7c..be018c2 100644 --- a/nw/src/main/java/lab/cherry/nw/model/OrgEntity.java +++ b/nw/src/main/java/lab/cherry/nw/model/OrgEntity.java @@ -63,7 +63,7 @@ public class OrgEntity implements Serializable { @JsonProperty("orgEnabled") @Schema(title = "조직 활성화 여부", example = "true") - private boolean enabled; + private Boolean enabled; @JsonProperty("created_at") @JsonFormat(pattern="yyyy-MM-dd hh:mm:ss", locale = "ko_KR", timezone = "Asia/Seoul") @@ -87,22 +87,22 @@ public static class OrgCreateDto { @NotBlank @Schema(title = "조직 이름", example = "더모멘트") @Size(min = 4, max = 20, message = "Minimum name length: 4 characters") - private String name; + private String orgName; @NotBlank @Schema(title = "조직 사업자번호", example = "123-45-67890") @Size(min = 4, max = 40, message = "Minimum biznum length: 4 characters") - private String biznum; + private String orgBiznum; @NotBlank @Schema(title = "조직 연락처", example = "02-0000-0000") @Size(min = 4, max = 40, message = "Minimum contact length: 4 characters") - private String contact; + private String orgContact; @NotBlank @Schema(title = "조직 주소", example = "서울시 종로구 파인애플주스 A동") @Size(min = 4, max = 255, message = "Minimum address length: 4 characters") - private String address; + private String orgAddress; } @@ -113,19 +113,22 @@ public static class OrgUpdateDto { @Schema(title = "조직 이름", example = "더모멘트") @Size(min = 4, max = 20, message = "Minimum name length: 4 characters") - private String name; + private String orgName; @Schema(title = "조직 사업자번호", example = "123-45-67890") @Size(min = 4, max = 40, message = "Minimum biznum length: 4 characters") - private String biznum; + private String orgBiznum; @Schema(title = "조직 연락처", example = "02-0000-0000") @Size(min = 4, max = 40, message = "Minimum contact length: 4 characters") - private String contact; + private String orgContact; @Schema(title = "조직 주소", example = "서울시 종로구 파인애플주스 A동") @Size(min = 4, max = 255, message = "Minimum address length: 4 characters") - private String address; + private String orgAddress; + + @Schema(title = "조직 활성화 여부", example = "true") + private Boolean orgEnabled; } } \ No newline at end of file diff --git a/nw/src/main/java/lab/cherry/nw/model/PyebaeksilEntity.java b/nw/src/main/java/lab/cherry/nw/model/PyebaeksilEntity.java index 32559f0..913b8e6 100644 --- a/nw/src/main/java/lab/cherry/nw/model/PyebaeksilEntity.java +++ b/nw/src/main/java/lab/cherry/nw/model/PyebaeksilEntity.java @@ -75,9 +75,9 @@ public static class PyebaeksilCreateDto { @Size(min = 4, max = 10, message = "폐백실 이름은 2글자 이상 10글자 이하만 입력 가능합니다.") private String pyebaeksilName; - @NotNull(message = "[필수] Org 정보") - @Schema(title = "Org 정보", example = "더모멘트") - private String org; + @NotNull(message = "[필수] Org 고유번호") + @Schema(title = "Org 정보", example = "64ed89aa9e813b5ab16da6de") + private String orgId; } } diff --git a/nw/src/main/java/lab/cherry/nw/model/UserEntity.java b/nw/src/main/java/lab/cherry/nw/model/UserEntity.java index 7af48c3..4915eb0 100644 --- a/nw/src/main/java/lab/cherry/nw/model/UserEntity.java +++ b/nw/src/main/java/lab/cherry/nw/model/UserEntity.java @@ -69,7 +69,7 @@ public class UserEntity implements Serializable { @JsonProperty("userEnabled") @Schema(title = "사용자 활성화 여부", example = "true") - private boolean enabled; + private Boolean enabled; @JsonProperty("emailVerified") @Schema(title = "이메일 인증 여부", example = "true") diff --git a/nw/src/main/java/lab/cherry/nw/model/WeddinghallEntity.java b/nw/src/main/java/lab/cherry/nw/model/WeddinghallEntity.java index e508b92..508d72a 100644 --- a/nw/src/main/java/lab/cherry/nw/model/WeddinghallEntity.java +++ b/nw/src/main/java/lab/cherry/nw/model/WeddinghallEntity.java @@ -93,9 +93,9 @@ public static class WeddinghallCreateDto { @Range(min = 1, max = 300, message = "웨딩홀(예식장)의 최대인원은 1인 이상 300명 이하만 입력 가능합니다.") private Integer maxPerson; - @NotNull(message = "[필수] Org 정보") - @Schema(title = "Org 정보", example = "더모멘트") - private String org; + @NotNull(message = "[필수] Org 고유번호") + @Schema(title = "Org 정보", example = "64ed89aa9e813b5ab16da6de") + private String orgId; @NotNull(message = "[필수] 웨딩홀(예식장) 행사 시간 간격") @Schema(title = "웨딩홀(예식장) 행사 시간 간격", example = "30") diff --git a/nw/src/main/java/lab/cherry/nw/repository/FileRepository.java b/nw/src/main/java/lab/cherry/nw/repository/FileRepository.java index 89dd051..07a5eaa 100644 --- a/nw/src/main/java/lab/cherry/nw/repository/FileRepository.java +++ b/nw/src/main/java/lab/cherry/nw/repository/FileRepository.java @@ -21,7 +21,7 @@ public interface FileRepository extends MongoRepository { Page findAll(Pageable pageable); - Page findPageByOrgid(String orgid, Pageable pageable); + // Page findPageByOrgid(String orgid, Pageable pageable); Page findPageByName(String filename, Pageable pageable); Optional findByPath(String path); diff --git a/nw/src/main/java/lab/cherry/nw/service/FileService.java b/nw/src/main/java/lab/cherry/nw/service/FileService.java index 3835f71..89aad2a 100644 --- a/nw/src/main/java/lab/cherry/nw/service/FileService.java +++ b/nw/src/main/java/lab/cherry/nw/service/FileService.java @@ -32,7 +32,8 @@ public interface FileService { FileEntity findByPath(String path); void deleteById(String id); - InputStream downloadFile(String orgId, String path); - byte[] downloadZip(String bucketName, String objectName); - void deleteFiles(String orgId, List images); + FileEntity.LoadFile downloadFile(String id) throws IllegalStateException, IOException; + Map downloadFiles(String key, String value); + // byte[] downloadZip(String bucketName, String objectName); + void deleteFiles(String name, List files); } \ No newline at end of file diff --git a/nw/src/main/java/lab/cherry/nw/service/Impl/BanquetServiceImpl.java b/nw/src/main/java/lab/cherry/nw/service/Impl/BanquetServiceImpl.java index 1552c33..7078b80 100644 --- a/nw/src/main/java/lab/cherry/nw/service/Impl/BanquetServiceImpl.java +++ b/nw/src/main/java/lab/cherry/nw/service/Impl/BanquetServiceImpl.java @@ -11,6 +11,7 @@ import lab.cherry.nw.service.OrgService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.bson.types.ObjectId; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @@ -69,35 +70,34 @@ public Page getBanquets(Pageable pageable) { * * Author : taking(taking@duck.com) */ - public BanquetEntity createBanquet(BanquetEntity.BanquetCreateDto banquetCreateDto, List imageFiles) { + public BanquetEntity createBanquet(BanquetEntity.BanquetCreateDto banquetCreateDto, List images) { log.error("[#0] in createBanquet"); checkExistsWithBanquetName(banquetCreateDto.getBanquetName()); // 중복 체크 - String orgId = banquetCreateDto.getOrg(); + String orgId = banquetCreateDto.getOrgId(); OrgEntity orgEntity = orgService.findById(orgId); + ObjectId objectId = new ObjectId(); - // 파일 업로드 시, 구분하기 위한 정보 입력 - // {org_objectId}/웨딩홀/{weddinghallName}/profile.jpg - // {org_objectId}/고객/{userName}/문서.xlsx - Map info = new HashMap<>(); - info.put("type", "연회장"); - info.put("org", banquetCreateDto.getOrg()); - - // 업로드한 파일의 ObjectId 를 List로 반환 - List fileObjectIds = fileService.uploadFiles(info, imageFiles); - - log.error("[#1] imageFileIds = {}", fileObjectIds); + Map info = new HashMap<>(); + info.put("org", orgEntity.getName()); + info.put("type", "연회장"); + // info.put("username", ""); + info.put("kind", banquetCreateDto.getBanquetName()); + info.put("seq", objectId.toString()); + + List imageUrls = fileService.uploadFiles(info, images); BanquetEntity banquetEntity = BanquetEntity.builder() - .name(banquetCreateDto.getBanquetName()) - .max_person(banquetCreateDto.getMaxPerson()) - .org(orgEntity) - .interval(banquetCreateDto.getInterval()) - .images(fileObjectIds) - .created_at(Instant.now()) - .build(); + .id(objectId.toString()) + .name(banquetCreateDto.getBanquetName()) + .max_person(banquetCreateDto.getMaxPerson()) + .org(orgEntity) + .interval(banquetCreateDto.getInterval()) + .images(imageUrls) + .created_at(Instant.now()) + .build(); return banquetRepository.save(banquetEntity); } @@ -156,16 +156,10 @@ public BanquetEntity findById(String id) { */ public void deleteById(String id) { - // 파일 다운로드 - BanquetEntity banquetEntity = findById(id); - - List fileObjectIds = banquetEntity.getImages(); - - if (!fileObjectIds.isEmpty()) { - fileService.deleteFiles(banquetEntity.getOrg().getId(), fileObjectIds); - } + BanquetEntity banquetEntity = findById(id); + fileService.deleteFiles(banquetEntity.getName(), banquetEntity.getImages()); - banquetRepository.delete(banquetRepository.findById(id).orElseThrow(() -> new EntityNotFoundException("Banquet with Id " + id + " Not Found."))); + banquetRepository.delete(banquetRepository.findById(id).orElseThrow(() -> new EntityNotFoundException("Banquet with Id " + id + " Not Found."))); } } \ No newline at end of file diff --git a/nw/src/main/java/lab/cherry/nw/service/Impl/FileServiceImpl.java b/nw/src/main/java/lab/cherry/nw/service/Impl/FileServiceImpl.java index 68e1dab..93ad290 100644 --- a/nw/src/main/java/lab/cherry/nw/service/Impl/FileServiceImpl.java +++ b/nw/src/main/java/lab/cherry/nw/service/Impl/FileServiceImpl.java @@ -1,34 +1,45 @@ package lab.cherry.nw.service.Impl; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.net.URI; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.PosixFilePermissions; import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import org.apache.tomcat.util.codec.binary.Base64; +import java.util.function.Consumer; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; +import org.apache.commons.compress.utils.IOUtils; import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.io.InputStreamResource; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; -import org.springframework.http.HttpHeaders; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.gridfs.GridFsOperations; +import org.springframework.data.mongodb.gridfs.GridFsTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; -import org.springframework.web.util.UriComponentsBuilder; +import com.mongodb.BasicDBObject; +import com.mongodb.DBObject; +import com.mongodb.client.gridfs.GridFSFindIterable; +import com.mongodb.client.gridfs.model.GridFSFile; import lab.cherry.nw.error.enums.ErrorCode; import lab.cherry.nw.error.exception.CustomException; import lab.cherry.nw.error.exception.EntityNotFoundException; import lab.cherry.nw.model.FileEntity; import lab.cherry.nw.repository.FileRepository; import lab.cherry.nw.service.FileService; -import lab.cherry.nw.service.MinioService; import lab.cherry.nw.util.FormatConverter; -import lab.cherry.nw.util.HttpUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -37,17 +48,11 @@ @RequiredArgsConstructor public class FileServiceImpl implements FileService { - private final MinioService minioService; - private final FileRepository fileRepository; - - @Value("${minio.url}") - private String minioUrl; - - @Value("${minio.access-key}") - private String accessKey; - - @Value("${minio.secret-key}") - private String secretKey; + @Value("${lab.cherry.nw.uploadPath}") + private String uploadPath; + private final FileRepository fileRepository; + private final GridFsTemplate template; + private final GridFsOperations operations; public Page getFiles(Pageable pageable) { return fileRepository.findAll(pageable); @@ -55,127 +60,139 @@ public Page getFiles(Pageable pageable) { @Override public List uploadFiles(Map info, List files) { - - String orgId = info.get("org"); // 조직명 - String userId = info.get("user"); // 사용자명 - String type = info.get("type"); - String qsheetSeq= info.get("qsheetSeq"); // 파일 구분명 - String bucketName = null; - - String destPath; - if (userId != null) { - // user가 입력되면, /user/{userId}으로 Path 지정 - bucketName = "user"; - destPath = userId + "/" + qsheetSeq +"/"; + + String orgName = info.get("org"); // 조직명 + String userName = info.get("username"); // 사용자명 + String type = info.get("type"); // 타입 (ex. 웨딩홀, 연회장, 폐백실) + String kind = info.get("kind"); // 구분 (ex. 웨딩홀명, 연회장명, 폐백실명) + String seq = info.get("seq"); // 고유번호 + + Path subPath = null; + if(userName == null) { + subPath = Paths.get("조직" + File.separator + orgName + File.separator + type + File.separator + kind); } else { - // user값이 없을 시, {org_objectId}/관리/로 Path 지정 - bucketName = orgId; - destPath = "/관리/"; + subPath = Paths.get("사용자" + File.separator + userName + File.separator + kind + "-" + seq); } - List fileObjectIds = new ArrayList<>(); + String directoryPath = folderChk("mkdir", subPath.toString()); + + List fileUrls = new ArrayList<>(); for (MultipartFile file : files) { - String originalFilename = (userId != null) ? file.getOriginalFilename() : type + "/" + file.getOriginalFilename(); - String filepath = destPath + originalFilename; + - log.error("objectName is {}", filepath); + DBObject metadata = new BasicDBObject(); + metadata.put("seq", seq); + metadata.put("name", file.getOriginalFilename()); + metadata.put("size", file.getSize()); + metadata.put("type", file.getContentType()); + metadata.put("kind", kind); + metadata.put("path", directoryPath); + Object fileObjectID = null; try { - minioService.uploadObject(bucketName, filepath, file); - } catch (IOException e) { - log.error(e.getMessage()); - } catch (NoSuchAlgorithmException | InvalidKeyException e) { - throw new RuntimeException(e); + fileObjectID = template.store(file.getInputStream(), file.getOriginalFilename(), file.getContentType(), metadata); + } catch (IOException e) { + log.error("파일 업로드 실패 {}", e); + throw new CustomException(ErrorCode.FILE_UPLOAD_FAILED); } - String fileUrl = "/api/v1/file/download/" + bucketName + "?path=" + filepath; + log.error("file.getOriginalFilename() is {}", file.getOriginalFilename()); + + String fullpath = directoryPath + File.separator + file.getOriginalFilename(); + + try { + File destFile = new File(fullpath); + file.transferTo(destFile); + log.info("File uploaded successfully!"); + } catch (IOException e) { + log.info("File upload failed: " + e.getMessage()); + } + + String fileUrl = "/api/v1/file/download/" + fileObjectID.toString(); // 파일 객체 ID 저장 - fileObjectIds.add(fileUrl); + fileUrls.add(fileUrl); FileEntity fileEntity = FileEntity.builder() - .name(file.getOriginalFilename()) - .size(FormatConverter.convertInputBytes(file.getSize())) - .type(file.getContentType()) - .path(filepath) - .url(fileUrl) - .userid(userId) - .orgid(bucketName) - .created_at(Instant.now()) - .build(); + .id(fileObjectID.toString()) + .name(file.getOriginalFilename()) + .size(FormatConverter.convertInputBytes(file.getSize())) + .type(file.getContentType()) + .path(fullpath) + .url(fileUrl) + .userName(userName) + .orgName(orgName) + .created_at(Instant.now()) + .build(); fileRepository.save(fileEntity); } - return fileObjectIds; + return fileUrls; } - public List getAllFiles(String orgId, String path) { + @Override + public FileEntity.LoadFile downloadFile(String id) throws IllegalStateException, IOException { + + GridFSFile gridFSFile = template.findOne( new Query(Criteria.where("_id").is(id)) ); - try { - return minioService.listObjects(orgId, path); + FileEntity.LoadFile fileEntity = new FileEntity.LoadFile(); - } catch (IOException e) { - log.error(e.getMessage()); - } catch (NoSuchAlgorithmException | InvalidKeyException e) { - throw new RuntimeException(e); - } - return null; - } + if (gridFSFile != null && gridFSFile.getMetadata() != null) { - @Override - public InputStream downloadFile(String orgId, String path) { + log.error("fsFile.getMetadata() = {}", gridFSFile.getMetadata()); - try { - return minioService.getObject(orgId, path); + fileEntity.setName( gridFSFile.getFilename() ); + fileEntity.setSize( gridFSFile.getMetadata().get("size").toString() ); + fileEntity.setType( gridFSFile.getMetadata().get("type").toString() ); - } catch (IOException e) { - log.error("파일 콘텐츠 확인 중 오류 발생: {}", e.getMessage()); - } catch (NoSuchAlgorithmException | InvalidKeyException e) { - throw new RuntimeException(e); + fileEntity.setFile( IOUtils.toByteArray(operations.getResource(gridFSFile).getInputStream()) ); + } else { + throw new CustomException(ErrorCode.ENTITY_NOT_FOUND); } - return null; + + return fileEntity; } - @Override - public byte[] downloadZip(String bucketName, String objectName) { - - objectName = Base64.encodeBase64String(objectName.getBytes()); - String addr = minioUrl.substring(0, minioUrl.length()-5) + ":9001"; - - try { - URI uri = UriComponentsBuilder - .fromUriString(addr) - .path("/api/v1/buckets/{bucketName}/objects/download") - // .encode() - .queryParam("prefix", objectName) - .build() - .expand(bucketName, objectName) - .toUri(); - - log.error("uri {}", uri); - return HttpUtils.getForObject(uri); + + public Map downloadFiles(String key, String value) { + List allFiles = new ArrayList<>(); + GridFSFindIterable resources = template.find(new Query().addCriteria(Criteria.where("metadata." + key).is(value))); + resources.forEach((Consumer) file -> allFiles.add(file)); + + log.error("allFiles {}", allFiles); + for(GridFSFile file : allFiles) { + log.error("FileName : {}", file.getFilename()); + } - } catch (Exception ex) { - log.error("error {}", ex); - log.error("error.msg {}", ex.getMessage()); - // throw new CustomException(ErrorCode.URL_NOTFOUND); - } + try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ZipOutputStream zipOut = new ZipOutputStream(byteArrayOutputStream)) { + for (GridFSFile file : allFiles) { - return null; - } + ZipEntry zipEntry = new ZipEntry(file.getFilename()); + zipOut.putNextEntry(zipEntry); - public void deleteById(String id) { - FileEntity fileEntity = findById(id); + byte[] objectData = IOUtils.toByteArray(operations.getResource(file).getInputStream()); + zipOut.write(objectData); + zipOut.closeEntry(); + } + zipOut.finish(); - try { - minioService.deleteObject(fileEntity.getId(), fileEntity.getPath()); + Map returnVal = new HashMap<>(); + returnVal.put("name", value + ".zip"); + returnVal.put("data", byteArrayOutputStream.toByteArray()); + + return returnVal; - System.out.println("파일 삭제 성공: " + fileEntity.getName()); - } catch (IOException e) { - log.error("파일 콘텐츠 확인 중 오류 발생: {}", e.getMessage()); - } catch (NoSuchAlgorithmException | InvalidKeyException e) { - throw new RuntimeException(e); - } + } catch (IOException e) { + log.error("Error creating and sending the zip file: {}", e); + return null; + } + } + + public void deleteById(String id) { + + FileEntity fileEntity = findById(id); + folderChk("rmdir", fileEntity.getPath()); fileRepository.delete(fileRepository.findById(id).orElseThrow(() -> new EntityNotFoundException("File with Id " + id + " Not Found."))); } @@ -186,12 +203,6 @@ public Page findPageByName(String name, Pageable pageable) { return fileRepository.findPageByName(name, pageable); } - @Transactional(readOnly = true) - public Page findPageByOrgId(String orgid, Pageable pageable) { - return fileRepository.findPageByOrgid(orgid, pageable); - } - - @Transactional(readOnly = true) public FileEntity findById(String id) { return fileRepository.findByid(id).orElseThrow(() -> new EntityNotFoundException("file with Id " + id + " Not Found.")); @@ -202,22 +213,79 @@ public FileEntity findByPath(String path) { return fileRepository.findByPath(path).orElseThrow(() -> new EntityNotFoundException("file with Path " + path + " Not Found.")); } - public void deleteFiles(String orgId, List images) { + public void deleteFiles(String name, List files) { - for (String image : images) { - FileEntity fileEntity = findByPath(image); // checkFileExists + String filePath = null; - try { - minioService.deleteObject(orgId, image); + for (String file : files){ + + String[] splitText = file.split("/"); + String objectId = splitText[splitText.length -1]; - System.out.println("파일 삭제 성공: " + image); - } catch (IOException e) { - log.error("파일 콘텐츠 확인 중 오류 발생: {}", e.getMessage()); - } catch (NoSuchAlgorithmException | InvalidKeyException e) { - throw new RuntimeException(e); - } + GridFSFile gridFSFile = template.findOne( new Query(Criteria.where("_id").is(objectId))); + + filePath = gridFSFile.getMetadata().get("path").toString(); + String fileName = gridFSFile.getMetadata().get("name").toString(); + String fullPath = filePath + File.separator + fileName; + + template.delete(new Query(Criteria.where("_id").is(objectId))); - fileRepository.delete(fileRepository.findByPath(image).orElseThrow(() -> new EntityNotFoundException("File with Path " + image + " Not Found."))); + fileRepository.delete(fileRepository.findByPath(fullPath).orElseThrow(() -> new EntityNotFoundException("File with Path " + file + " Not Found."))); } + + if(name != null) { + folderChk("rmdir", filePath); + } } + + public String folderChk(String type, String path) { + + if(!new File(uploadPath).exists()) { + log.error("Folder 생성 실패, 루트 폴더를 수동으로 생성해주세요 : {}", uploadPath); + throw new CustomException(ErrorCode.INVALID_USERNAME); + } else { + + if (type == "mkdir") { + + // 업로드 디렉토리 생성 (만약 존재하지 않는 경우) + Path directoryPath = Paths.get(uploadPath + File.separator + path); + try { + // 디렉토리 생성 + Files.createDirectories(directoryPath, + PosixFilePermissions.asFileAttribute( + PosixFilePermissions.fromString("rwxr-x---") + ));; + System.out.println(directoryPath.toString() + " 디렉토리가 생성되었습니다."); + return directoryPath.toString(); + } catch (IOException e) { + log.error("디렉토리 생성 실패 : {}", e); + } + + } else if (type == "rmdir") { + log.error("폴더 삭제"); + + // 업로드 디렉토리 생성 (만약 존재하지 않는 경우) + Path directoryPath = Paths.get(path); + log.error("directoryPath.toString() is {}", directoryPath.toString()); + File folder = new File(directoryPath.toString()); + // 디렉토리 내 파일 삭제 + while (folder.exists()) { + File[] folder_list = folder.listFiles(); // 파일리스트 얻어오기 + + for (int j = 0; j < folder_list.length; j++) { + folder_list[j].delete(); // 파일 삭제 + System.out.println("파일이 삭제되었습니다."); + } + + if (folder_list.length == 0 && folder.isDirectory()) { + folder.delete(); // 대상폴더 삭제 + System.out.println("폴더가 삭제되었습니다."); + } + } + return ""; + } + + } + return ""; +} } \ No newline at end of file diff --git a/nw/src/main/java/lab/cherry/nw/service/Impl/MinioServiceImpl.java b/nw/src/main/java/lab/cherry/nw/service/Impl/MinioServiceImpl.java deleted file mode 100644 index 0265774..0000000 --- a/nw/src/main/java/lab/cherry/nw/service/Impl/MinioServiceImpl.java +++ /dev/null @@ -1,369 +0,0 @@ -package lab.cherry.nw.service.Impl; - -import java.io.IOException; -import java.io.InputStream; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.springframework.stereotype.Service; -import org.springframework.web.multipart.MultipartFile; -import io.minio.BucketExistsArgs; -import io.minio.GetBucketPolicyArgs; -import io.minio.GetObjectArgs; -import io.minio.GetPresignedObjectUrlArgs; -import io.minio.ListObjectsArgs; -import io.minio.MakeBucketArgs; -import io.minio.MinioClient; -import io.minio.PutObjectArgs; -import io.minio.RemoveBucketArgs; -import io.minio.RemoveObjectArgs; -import io.minio.RemoveObjectsArgs; -import io.minio.Result; -import io.minio.SetBucketPolicyArgs; -import io.minio.admin.MinioAdminClient; -import io.minio.admin.UserInfo; -import io.minio.errors.MinioException; -import io.minio.http.Method; -import io.minio.messages.DeleteError; -import io.minio.messages.DeleteObject; -import io.minio.messages.Item; -import lab.cherry.nw.model.UserEntity; -import lab.cherry.nw.service.MinioService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@Service -@RequiredArgsConstructor -public class MinioServiceImpl implements MinioService { - - private final MinioClient minioClient; - private final MinioAdminClient adminClient; - - public boolean isMinioConnected() { - try { - // 버킷 목록을 가져와서 Minio 연결 상태 확인 - minioClient.listBuckets(); - return true; // 연결이 성공적으로 확인됨 - } catch (Exception e) { - // Minio 연결 예외 처리 - return false; // 연결 실패 - } - } - public Map listUsers() throws InvalidCipherTextException, NoSuchAlgorithmException, IOException, InvalidKeyException { - - return adminClient.listUsers(); - } - - public void newUser(UserEntity user) throws IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidCipherTextException { - - // 새 사용자를 생성합니다. - String userAccessKey = user.getId(); - String userSecretKey = user.getPassword(); - - adminClient.addUser(userAccessKey, UserInfo.Status.ENABLED, userSecretKey, null, null); - - } - - public void deleteUser(UserEntity user) throws IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidCipherTextException { - - // 사용자를 삭제합니다. - String userAccessKey = user.getId(); - - adminClient.deleteUser(userAccessKey); - - } - - public void setUserPolicy(String bucketName, String userId) throws NoSuchAlgorithmException, IOException, InvalidKeyException { - - log.error("Minio Connect Check : {}", isMinioConnected()); - - adminClient.setPolicy(userId, false, bucketName); - - } - - public void createGlobalPolicy(String bucketName) throws NoSuchAlgorithmException, IOException, InvalidKeyException { - - log.error("Minio Connect Check : {}", isMinioConnected()); - - // TODO: bucketName-admin 또는 bucketName-user 권한으로 구분 기능 추후 개발 필요 - String policyJson = "{" + - "\"Version\": \"2012-10-17\"," + - "\"Statement\": [" + - "{" + - "\"Action\": [" + - "\"s3:GetObject\", " + - "\"s3:PutObject\", " + - "\"s3:DeleteObject\", " + - "\"s3:ListBucket\"], " + - "\"Effect\": \"Allow\", " + - "\"Resource\": [\"arn:aws:s3:::" + bucketName + "/*\"], " + // bucketName 변수 사용 - "\"Sid\": \"\"" + // Sid (선택 사항) 추가 - "}" + - "]" + - "}"; - - adminClient.addCannedPolicy(bucketName, policyJson.replaceAll("'", "\"")); - - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - public List listObjects(String bucketName, String prefix) throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - - log.error("Minio Connect Check : {}", isMinioConnected()); - - // bucketName에 있는 objectName을 조회합니다. - - Iterable> objects = null; - - if (prefix == null) { - objects = minioClient.listObjects(ListObjectsArgs.builder() - .bucket(bucketName) - .build()); - } else { - - log.error("path is {}", prefix); - - objects = minioClient.listObjects(ListObjectsArgs.builder() - .bucket(bucketName) - .prefix(prefix) - .build()); - } - - List objecLists = new ArrayList<>(); - for (Result result : objects) { - Item item = result.get(); - log.info("Object Name: {}", item.objectName()); - log.info("Object Size: {}", item.size()); - objecLists.add(item.objectName()); - } - - return objecLists; - - } catch (MinioException e) { - log.error("Error occurred: " + e); - } - - return null; - } - - public InputStream getObject(String bucketName, String objectName) throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - - log.error("Minio Connect Check : {}", isMinioConnected()); - - - log.error("\nbucketName is {}\nobjectName is {}\n", bucketName, objectName); - - // bucketName에 있는 objectName을 조회합니다. - InputStream stream = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build()); - - - return stream; -// List objectList = FormatConverter.convertInputStreamToList(stream); -// -// return objectList; - - } catch (MinioException e) { - log.error("Error occurred: " + e); - } - - return null; - } - - public boolean bucketExists(String bucketName) throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - - log.error("Minio Connect Check : {}", isMinioConnected()); - - // Check whether 'my-bucketname' exist or not. - boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); - - if (found) { - log.info("{} bucket이 존재합니다.", bucketName); - return true; - } else { - log.info("{} bucket이 존재하지 않습니다.", bucketName); - return false; - } - } catch (MinioException e) { - log.error("Error occurred: " + e); - } - - return false; - } - - public void createBucketIfNotExists(String bucketName) throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - - log.error("Minio Connect Check : {}", isMinioConnected()); - - // bucketName이 존재하는지 확인 후, 없다면 bucket 생성 - if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) { - minioClient.makeBucket(MakeBucketArgs.builder() - .bucket(bucketName) -// .region("eu-west-1") -// .objectLock(true) - .build()); - log.info("{} bucket이 생성 완료되었습니다.", bucketName); - } - } catch (MinioException e) { - log.error("Error occurred: " + e); - } - } - public void uploadObject(String bucketName, String objectName, MultipartFile file) throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - - log.error("Minio Connect Check : {}", isMinioConnected()); - - // Object를 업로드합니다. - minioClient.putObject( - PutObjectArgs.builder() - .bucket(bucketName) - .object(objectName) - .contentType(file.getContentType()) - .stream(file.getInputStream(), file.getSize(), -1) - .build() - ); - - log.info("Object가 업로드되었습니다."); - } catch (MinioException e) { - log.error("Error occurred: " + e); - } - } - - public void setBucketPolicy(String bucketName) throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - - log.error("Minio Connect Check : {}", isMinioConnected()); - - // BucketName 에 Policy를 설정합니다. - StringBuilder builder = new StringBuilder(); - builder.append("{\n"); - builder.append(" \"Statement\": [\n"); - builder.append(" {\n"); - builder.append(" \"Action\": [\n"); - builder.append(" \"s3:GetBucketLocation\",\n"); - builder.append(" \"s3:ListBucket\"\n"); - builder.append(" ],\n"); - builder.append(" \"Effect\": \"Allow\",\n"); - builder.append(" \"Principal\": \"*\",\n"); - builder.append(" \"Resource\": \"arn:aws:s3:::" + bucketName + "\"\n"); - builder.append(" },\n"); - builder.append(" {\n"); - builder.append(" \"Action\": \"s3:GetObject\",\n"); - builder.append(" \"Effect\": \"Allow\",\n"); - builder.append(" \"Principal\": \"*\",\n"); - builder.append(" \"Resource\": \"arn:aws:s3:::" + bucketName + "/*\"\n"); - builder.append(" }\n"); - builder.append(" ],\n"); - builder.append(" \"Version\": \"2012-10-17\"\n"); - builder.append("}\n"); - - minioClient.setBucketPolicy( - SetBucketPolicyArgs.builder().bucket(bucketName).config(builder.toString()).build()); - - log.info("{} Policy 생성이 완료되었습니다.", minioClient.getBucketPolicy(GetBucketPolicyArgs.builder().bucket(bucketName).build())); - } catch (MinioException e) { - log.error("Error occurred: " + e); - } - } - - public void deleteBucket(String bucketName) throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - - log.error("Minio Connect Check : {}", isMinioConnected()); - - // Bucket를 삭제합니다. - boolean found = - minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); - if (found) { - minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); - log.info("{} bucket이 삭제되었습니다.", bucketName); - } else { - log.info("{} bucket을 찾을 수 없습니다.", bucketName); - } - } catch (MinioException e) { - log.error("Error occurred: " + e); - } - } - - public void deleteObject(String bucketName, String objectName) throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - - log.error("Minio Connect Check : {}", isMinioConnected()); - - // Object를 삭제합니다. - minioClient.removeObject( - RemoveObjectArgs.builder() - .bucket(bucketName) - .object(objectName) - .build()); - - log.info("Object가 삭제되었습니다."); - } catch (MinioException e) { - log.error("Error occurred: " + e); - } - } - - public void deleteObjects(String bucketName, List objectList) throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - - log.error("Minio Connect Check : {}", isMinioConnected()); - - // List objects = new LinkedList<>(); - // objects.add(new DeleteObject("my-objectname1")); - // objects.add(new DeleteObject("my-objectname2")); - // objects.add(new DeleteObject("my-objectname3")); - - Iterable> results = - minioClient.removeObjects( - RemoveObjectsArgs.builder().bucket(bucketName).objects(objectList).build()); - for (Result result : results) { - DeleteError error = result.get(); - log.info("{} Object 삭제하는데 문제가 발생했습니다. {} ", error.objectName(), error.message()); - } - - log.info("ObjectList가 삭제되었습니다."); - } catch (MinioException e) { - log.error("Error occurred: " + e); - } - } - - public String getPresignedURL(String bucketName, String objectName) throws IOException, NoSuchAlgorithmException, InvalidKeyException { - try { - - // minioService.getPresignedURL(user, "test", "subFolder/64ed89aa9e813b5ab16da6dd"); - // expiration 기간 동안 유지되는 링크 제공 - - log.error("Minio Connect Check : {}", isMinioConnected()); - - Map reqParams = new HashMap(); - reqParams.put("response-content-type", "application/json"); - - log.error("bucketName {}", bucketName); - log.error("objectName {}", objectName); - - // Presigned URL 생성 - return minioClient.getPresignedObjectUrl( - GetPresignedObjectUrlArgs.builder() - .method(Method.GET) - .bucket(bucketName) - .object(objectName) - .expiry(1, TimeUnit.HOURS) // 시간 - .extraQueryParams(reqParams) - .build()); - - } catch (MinioException e) { - log.error("Error occurred: " + e); - } - return null; - } -} \ No newline at end of file diff --git a/nw/src/main/java/lab/cherry/nw/service/Impl/OrgServiceImpl.java b/nw/src/main/java/lab/cherry/nw/service/Impl/OrgServiceImpl.java index 046f9fb..ebd8b85 100644 --- a/nw/src/main/java/lab/cherry/nw/service/Impl/OrgServiceImpl.java +++ b/nw/src/main/java/lab/cherry/nw/service/Impl/OrgServiceImpl.java @@ -7,7 +7,6 @@ import lab.cherry.nw.error.exception.EntityNotFoundException; import lab.cherry.nw.model.OrgEntity; import lab.cherry.nw.repository.OrgRepository; -import lab.cherry.nw.service.MinioService; import lab.cherry.nw.service.OrgService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -33,7 +32,6 @@ @RequiredArgsConstructor public class OrgServiceImpl implements OrgService { - private final MinioService minioService; private final OrgRepository orgRepository; /** @@ -68,29 +66,29 @@ public Page getOrganizations(Pageable pageable) { public OrgEntity createOrganization(OrgEntity.OrgCreateDto orgCreateDto) { ObjectId orgId = new ObjectId(); - try { - // ObjectId orgId로 Bucket 생성 - minioService.createBucketIfNotExists(orgId.toString()); + // try { + // // ObjectId orgId로 Bucket 생성 + // minioService.createBucketIfNotExists(orgId.toString()); - // ObjectId orgId에 해당하는 GlobalPolicy 생성 - minioService.createGlobalPolicy(orgId.toString()); + // // ObjectId orgId에 해당하는 GlobalPolicy 생성 + // minioService.createGlobalPolicy(orgId.toString()); - // 생성된 Bucket에 Policy 적용 - minioService.setBucketPolicy(orgId.toString()); + // // 생성된 Bucket에 Policy 적용 + // minioService.setBucketPolicy(orgId.toString()); - } catch (Exception e) { - log.error(e.getMessage()); - } + // } catch (Exception e) { + // log.error(e.getMessage()); + // } Instant instant = Instant.now(); - checkExistsWithOrgName(orgCreateDto.getName()); // 동일한 이름 중복체크 + checkExistsWithOrgName(orgCreateDto.getOrgName()); // 동일한 이름 중복체크 OrgEntity orgEntity = OrgEntity.builder() .id(orgId.toString()) - .name(orgCreateDto.getName()) - .biznum(orgCreateDto.getBiznum()) - .contact(orgCreateDto.getContact()) - .address(orgCreateDto.getAddress()) + .name(orgCreateDto.getOrgName()) + .biznum(orgCreateDto.getOrgBiznum()) + .contact(orgCreateDto.getOrgContact()) + .address(orgCreateDto.getOrgAddress()) .enabled(true) .created_at(instant) .build(); @@ -113,14 +111,14 @@ public void updateById(String id, OrgEntity.OrgUpdateDto org) { OrgEntity orgEntity = findById(id); - if (org.getName() != null || org.getBiznum() != null || org.getContact() != null || org.getAddress() != null) { - + if (org.getOrgName() != null || org.getOrgBiznum() != null || org.getOrgContact() != null || org.getOrgAddress() != null || org.getOrgEnabled() != null) { orgEntity = OrgEntity.builder() .id(orgEntity.getId()) - .name((org.getName() != null) ? org.getName() : orgEntity.getName()) - .biznum((org.getBiznum() != null) ? org.getBiznum() : orgEntity.getBiznum()) - .contact((org.getContact() != null) ? org.getContact() : orgEntity.getContact()) - .address((org.getAddress() != null) ? org.getAddress() : orgEntity.getAddress()) + .name((org.getOrgName() != null) ? org.getOrgName() : orgEntity.getName()) + .biznum((org.getOrgBiznum() != null) ? org.getOrgBiznum() : orgEntity.getBiznum()) + .contact((org.getOrgContact() != null) ? org.getOrgContact() : orgEntity.getContact()) + .address((org.getOrgAddress() != null) ? org.getOrgAddress() : orgEntity.getAddress()) + .enabled((org.getOrgEnabled() != null) ? org.getOrgEnabled() : orgEntity.getEnabled()) .build(); orgRepository.save(orgEntity); diff --git a/nw/src/main/java/lab/cherry/nw/service/Impl/PyebaeksilServiceImpl.java b/nw/src/main/java/lab/cherry/nw/service/Impl/PyebaeksilServiceImpl.java index a64bbcc..3cb7a76 100644 --- a/nw/src/main/java/lab/cherry/nw/service/Impl/PyebaeksilServiceImpl.java +++ b/nw/src/main/java/lab/cherry/nw/service/Impl/PyebaeksilServiceImpl.java @@ -11,6 +11,7 @@ import lab.cherry.nw.service.OrgService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.bson.types.ObjectId; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @@ -69,33 +70,36 @@ public Page getPyebaeksils(Pageable pageable) { * * Author : taking(taking@duck.com) */ - public PyebaeksilEntity createPyebaeksil(PyebaeksilEntity.PyebaeksilCreateDto pyebaeksilCreateDto, List imageFiles) { + public PyebaeksilEntity createPyebaeksil(PyebaeksilEntity.PyebaeksilCreateDto pyebaeksilCreateDto, List images) { log.error("[#0] in createPyebaeksil"); checkExistsWithPyebaeksilName(pyebaeksilCreateDto.getPyebaeksilName()); // 중복 체크 - String orgId = pyebaeksilCreateDto.getOrg(); + String orgId = pyebaeksilCreateDto.getOrgId(); OrgEntity orgEntity = orgService.findById(orgId); + ObjectId objectId = new ObjectId(); // 파일 업로드 시, 구분하기 위한 정보 입력 // {org_objectId}/웨딩홀/{weddinghallName}/profile.jpg // {org_objectId}/고객/{userName}/문서.xlsx Map info = new HashMap<>(); - info.put("type", "폐백실"); - info.put("org", pyebaeksilCreateDto.getOrg()); + info.put("org", orgEntity.getName()); + info.put("type", "폐백실"); + // info.put("username", ""); + info.put("kind", pyebaeksilCreateDto.getPyebaeksilName()); + info.put("seq", objectId.toString()); // 업로드한 파일의 ObjectId 를 List로 반환 - List fileObjectIds = fileService.uploadFiles(info, imageFiles); - - log.error("[#1] imageFileIds = {}", fileObjectIds); + List imageUrls = fileService.uploadFiles(info, images); PyebaeksilEntity pyebaeksilEntity = PyebaeksilEntity.builder() - .name(pyebaeksilCreateDto.getPyebaeksilName()) - .org(orgEntity) - .images(fileObjectIds) - .created_at(Instant.now()) - .build(); + .id(objectId.toString()) + .name(pyebaeksilCreateDto.getPyebaeksilName()) + .org(orgEntity) + .images(imageUrls) + .created_at(Instant.now()) + .build(); return pyebaeksilRepository.save(pyebaeksilEntity); } @@ -154,14 +158,8 @@ public PyebaeksilEntity findById(String id) { */ public void deleteById(String id) { - // 파일 다운로드 - PyebaeksilEntity pyebaeksilEntity = findById(id); - - List fileObjectIds = pyebaeksilEntity.getImages(); - - if (!fileObjectIds.isEmpty()) { - fileService.deleteFiles(pyebaeksilEntity.getOrg().getId(), fileObjectIds); - } + PyebaeksilEntity pyebaeksilEntity = findById(id); + fileService.deleteFiles(pyebaeksilEntity.getName(), pyebaeksilEntity.getImages()); pyebaeksilRepository.delete(pyebaeksilRepository.findById(id).orElseThrow(() -> new EntityNotFoundException("Pyebaeksil with Id " + id + " Not Found."))); } diff --git a/nw/src/main/java/lab/cherry/nw/service/Impl/WeddinghallServiceImpl.java b/nw/src/main/java/lab/cherry/nw/service/Impl/WeddinghallServiceImpl.java index 5446e30..e506b2e 100644 --- a/nw/src/main/java/lab/cherry/nw/service/Impl/WeddinghallServiceImpl.java +++ b/nw/src/main/java/lab/cherry/nw/service/Impl/WeddinghallServiceImpl.java @@ -1,6 +1,16 @@ package lab.cherry.nw.service.Impl; -import io.minio.errors.MinioException; +import java.io.IOException; +import java.time.Instant; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.bson.types.ObjectId; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; import lab.cherry.nw.error.enums.ErrorCode; import lab.cherry.nw.error.exception.CustomException; import lab.cherry.nw.error.exception.EntityNotFoundException; @@ -12,19 +22,6 @@ import lab.cherry.nw.service.WeddinghallService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.multipart.MultipartFile; - -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.time.Instant; -import java.util.HashMap; -import java.util.List; -import java.util.Map; /** *
@@ -72,37 +69,36 @@ public Page getWeddinghalls(Pageable pageable) {
      * 
* * Author : taking(taking@duck.com) + * @throws IOException */ - public WeddinghallEntity createWeddinghall(WeddinghallEntity.WeddinghallCreateDto weddinghallCreateDto, List imageFiles) { + public WeddinghallEntity createWeddinghall(WeddinghallEntity.WeddinghallCreateDto weddinghallCreateDto, List images) { log.error("[#0] in createWeddinghall"); checkExistsWithWeddingHallName(weddinghallCreateDto.getWeddinghallName()); // 중복 체크 - String orgId = weddinghallCreateDto.getOrg(); + String orgId = weddinghallCreateDto.getOrgId(); OrgEntity orgEntity = orgService.findById(orgId); - - // 파일 업로드 시, 구분하기 위한 정보 입력 - // {org_objectId}/웨딩홀/{weddinghallName}/profile.jpg - // {org_objectId}/고객/{userName}/문서.xlsx - Map info = new HashMap<>(); - info.put("type", "웨딩홀"); - // info.put("type", weddinghallCreateDto.getWeddinghallName()); - info.put("org", weddinghallCreateDto.getOrg()); - - // 업로드한 파일의 ObjectId 를 List로 반환 - List fileObjectIds = fileService.uploadFiles(info, imageFiles); - - log.error("[#1] imageFileIds = {}", fileObjectIds); - - WeddinghallEntity weddinghallEntity = WeddinghallEntity.builder() - .name(weddinghallCreateDto.getWeddinghallName()) - .max_person(weddinghallCreateDto.getMaxPerson()) - .org(orgEntity) - .interval(weddinghallCreateDto.getInterval()) - .images(fileObjectIds) - .created_at(Instant.now()) - .build(); + ObjectId objectId = new ObjectId(); + + Map info = new HashMap<>(); + info.put("org", orgEntity.getName()); + info.put("type", "웨딩홀"); + // info.put("username", ""); + info.put("kind", weddinghallCreateDto.getWeddinghallName()); + info.put("seq", objectId.toString()); + + List imageUrls = fileService.uploadFiles(info, images); + + WeddinghallEntity weddinghallEntity = WeddinghallEntity.builder() + .id(objectId.toString()) + .name(weddinghallCreateDto.getWeddinghallName()) + .max_person(weddinghallCreateDto.getMaxPerson()) + .org(orgEntity) + .interval(weddinghallCreateDto.getInterval()) + .images(imageUrls) + .created_at(Instant.now()) + .build(); return weddinghallRepository.save(weddinghallEntity); } @@ -138,7 +134,7 @@ public WeddinghallEntity createWeddinghall(WeddinghallEntity.WeddinghallCreateDt @Transactional(readOnly = true) public Page findPageByName(String name, Pageable pageable) { - return weddinghallRepository.findPageByName(name, pageable); + return weddinghallRepository.findPageByName(name, pageable); } /** @@ -173,7 +169,7 @@ public void checkExistsWithWeddingHallName(String name) { */ @Transactional(readOnly = true) public WeddinghallEntity findById(String id) { - return weddinghallRepository.findById(id).orElseThrow(() -> new EntityNotFoundException("Weddinghall with Id " + id + " Not Found.")); + return weddinghallRepository.findById(id).orElseThrow(() -> new EntityNotFoundException("Weddinghall with Id " + id + " Not Found.")); } @@ -190,16 +186,10 @@ public WeddinghallEntity findById(String id) { */ public void deleteById(String id) { - // 파일 다운로드 - WeddinghallEntity weddinghallEntity = findById(id); - - List fileObjectIds = weddinghallEntity.getImages(); - - if (!fileObjectIds.isEmpty()) { - fileService.deleteFiles(weddinghallEntity.getOrg().getId(), fileObjectIds); - } + WeddinghallEntity weddinghallEntity = findById(id); + fileService.deleteFiles(weddinghallEntity.getName(), weddinghallEntity.getImages()); - weddinghallRepository.delete(weddinghallRepository.findById(id).orElseThrow(() -> new EntityNotFoundException("Weddinghall with Id " + id + " Not Found."))); + weddinghallRepository.delete(weddinghallRepository.findById(id).orElseThrow(() -> new EntityNotFoundException("Weddinghall with Id " + id + " Not Found."))); } } \ No newline at end of file diff --git a/nw/src/main/java/lab/cherry/nw/service/MinioService.java b/nw/src/main/java/lab/cherry/nw/service/MinioService.java deleted file mode 100644 index c01b651..0000000 --- a/nw/src/main/java/lab/cherry/nw/service/MinioService.java +++ /dev/null @@ -1,49 +0,0 @@ -package lab.cherry.nw.service; - - -import io.minio.admin.UserInfo; -import io.minio.messages.DeleteObject; -import lab.cherry.nw.model.UserEntity; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.springframework.stereotype.Component; -import org.springframework.web.multipart.MultipartFile; - -import java.io.IOException; -import java.io.InputStream; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.List; -import java.util.Map; - -/** - *
- * ClassName : MinioService
- * Type : interface
- * Description : 파일 관리에 필요한 Minio와 관련된 함수를 정리한 인터페이스입니다.
- * Related : MinioServiceImpl
- * 
- */ -@Component -public interface MinioService { - - // minioAdminClient - Map listUsers() throws IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidCipherTextException; - void newUser(UserEntity user) throws IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidCipherTextException; - void deleteUser(UserEntity user) throws IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidCipherTextException; - - void setUserPolicy(String bucketName, String userId) throws NoSuchAlgorithmException, IOException, InvalidKeyException; - void createGlobalPolicy(String bucketName) throws NoSuchAlgorithmException, IOException, InvalidKeyException; - - - // minioClient - List listObjects(String bucketName, String prefix) throws IOException, NoSuchAlgorithmException, InvalidKeyException; - InputStream getObject(String bucketName, String objectName) throws IOException, NoSuchAlgorithmException, InvalidKeyException; - boolean bucketExists(String bucketName) throws IOException, NoSuchAlgorithmException, InvalidKeyException; - void createBucketIfNotExists(String bucketName) throws IOException, NoSuchAlgorithmException, InvalidKeyException; - void uploadObject(String bucketName, String objectName, MultipartFile file) throws IOException, NoSuchAlgorithmException, InvalidKeyException; - void setBucketPolicy(String bucketName) throws IOException, NoSuchAlgorithmException, InvalidKeyException; - void deleteBucket(String bucketName) throws IOException, NoSuchAlgorithmException, InvalidKeyException; - void deleteObject(String bucketName, String objectName) throws IOException, NoSuchAlgorithmException, InvalidKeyException; - void deleteObjects(String bucketName, List objectList) throws IOException, NoSuchAlgorithmException, InvalidKeyException; - String getPresignedURL(String bucketName, String objectName) throws IOException, NoSuchAlgorithmException, InvalidKeyException; -} \ No newline at end of file diff --git a/nw/src/main/java/lab/cherry/nw/service/WeddinghallService.java b/nw/src/main/java/lab/cherry/nw/service/WeddinghallService.java index f047c52..fddd549 100644 --- a/nw/src/main/java/lab/cherry/nw/service/WeddinghallService.java +++ b/nw/src/main/java/lab/cherry/nw/service/WeddinghallService.java @@ -20,7 +20,7 @@ @Component public interface WeddinghallService { Page getWeddinghalls(Pageable pageable); - WeddinghallEntity createWeddinghall(WeddinghallEntity.WeddinghallCreateDto weddinghallCreateDto, List files); + WeddinghallEntity createWeddinghall(WeddinghallEntity.WeddinghallCreateDto weddinghallCreateDto, List images); // void updateById(String id, WeddinghallEntity.UpdateDto weddinghall); WeddinghallEntity findById(String id); // WeddinghallEntity findByName(String name); diff --git a/nw/src/main/resources/application.properties_sample b/nw/src/main/resources/application.properties_sample index 7cc8fc9..167412e 100644 --- a/nw/src/main/resources/application.properties_sample +++ b/nw/src/main/resources/application.properties_sample @@ -45,8 +45,4 @@ spring.mail.password=passWord #echo 'lab-cherry-nw-project-secret-key' | base64 lab.cherry.nw.jwtSecret= bGFiLWNoZXJyeS1udy1wcm9qZWN0LXNlY3JldC1rZXkK lab.cherry.nw.jwtExpirationMs= 86400000 - -# MinIo Properties -minio.url=http://nw-storage:9000 -minio.access-key={your-access-key} -minio.secret-key={your-secret-key} \ No newline at end of file +lab.cherry.nw.uploadPath= /data \ No newline at end of file