diff --git a/src/main/java/kr/re/etri/autoflow/controllers/AttachmentController.java b/src/main/java/kr/re/etri/autoflow/controllers/MinioAttachmentController.java similarity index 60% rename from src/main/java/kr/re/etri/autoflow/controllers/AttachmentController.java rename to src/main/java/kr/re/etri/autoflow/controllers/MinioAttachmentController.java index 24815ac..e5113ae 100644 --- a/src/main/java/kr/re/etri/autoflow/controllers/AttachmentController.java +++ b/src/main/java/kr/re/etri/autoflow/controllers/MinioAttachmentController.java @@ -1,20 +1,19 @@ package kr.re.etri.autoflow.controllers; -import io.minio.*; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import kr.re.etri.autoflow.entity.MinioAttachmentEntity; -import kr.re.etri.autoflow.payload.request.BaseSearchRequest; +import kr.re.etri.autoflow.payload.request.ProjectBaseSearchRequest; import kr.re.etri.autoflow.service.MinioAttachmentService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springdoc.core.annotations.ParameterObject; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.InputStreamResource; import org.springframework.data.domain.Page; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -26,10 +25,13 @@ import java.util.*; @RequiredArgsConstructor @Slf4j @Tag(name = "첨부파일", description = "MinIO 첨부파일 관리 API") -public class AttachmentController { +public class MinioAttachmentController { private final MinioAttachmentService minioAttachmentService; + @Value("${kubeflow.url}") + private String kubeflowBaseUrl; + @Operation(summary = "첨부파일 전체 조회") @GetMapping public ResponseEntity> getAll() { @@ -49,7 +51,7 @@ public class AttachmentController { @Operation(summary = "검색 및 페이지네이션 첨부파일 목록 조회") @GetMapping("/search") public ResponseEntity> search( - @ParameterObject @ModelAttribute BaseSearchRequest request, + @ParameterObject @ModelAttribute ProjectBaseSearchRequest request, @Parameter( description = "첨부파일 구분자. 예: WORKFLOW_STEP, DATASET, TRAINING_SCRIPT", example = "WORKFLOW_STEP" @@ -100,6 +102,72 @@ public class AttachmentController { } } +// @Operation(summary = "파일 업로드 및 Kubeflow 업로드", +// description = "MinIO와 DB에 저장하고 Kubeflow REST API에도 업로드합니다. Kubeflow API 경로는 요청 시 지정 가능") +// @PostMapping(value = "/upload-and-kubeflow", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) +// public ResponseEntity> uploadFileAndKubeflow( +// @Parameter(description = "업로드할 파일") @RequestPart("file") MultipartFile file, +// @RequestPart(value = "path", required = false) String path, +// @RequestParam(value = "refId", required = false) Long refId, +// @RequestParam(value = "refType", required = false, defaultValue = "TRAINING_SCRIPT") String refType, +// @RequestParam(value = "title", required = false) String title, +// @RequestParam(value = "description", required = false) String description, +// @RequestParam(value = "version", required = false, defaultValue = "1") Integer version, +// @RequestParam(value = "regUserId") String regUserId, +// @RequestParam(value = "kubeflowApi") String kubeflowApi +// ) { +// Map response = new HashMap<>(); +// try { +// MinioAttachmentEntity saved = minioAttachmentService.uploadFile( +// file, path, refId, refType, title, description, version, regUserId +// ); +// String minioUrl = minioAttachmentService.getFileUrl(saved.getStoragePath()); +// response.put("attachment", saved); +// response.put("minioUrl", minioUrl); +// +// RestTemplate restTemplate = new RestTemplate(); +// MultiValueMap body = new LinkedMultiValueMap<>(); +// body.add("uploadfile", new MultipartInputStreamFileResource(file.getInputStream(), file.getOriginalFilename())); +// +// HttpHeaders headers = new HttpHeaders(); +// headers.setContentType(MediaType.MULTIPART_FORM_DATA); +// +// HttpEntity> requestEntity = new HttpEntity<>(body, headers); +// +// String fullUrl = kubeflowBaseUrl + kubeflowApi; +// ResponseEntity kubeflowResponse = restTemplate.postForEntity(fullUrl, requestEntity, String.class); +// +// response.put("kubeflowResponse", kubeflowResponse.getBody()); +// +// return ResponseEntity.ok(response); +// +// } catch (Exception e) { +// log.error("파일 업로드 실패", e); +// response.put("error", e.getMessage()); +// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); +// } +// } + + // 파일 업로드용 InputStreamResource + private static class MultipartInputStreamFileResource extends InputStreamResource { + private final String filename; + + public MultipartInputStreamFileResource(InputStream inputStream, String filename) { + super(inputStream); + this.filename = filename; + } + + @Override + public String getFilename() { + return this.filename; + } + + @Override + public long contentLength() { + return -1; + } + } + @Operation(summary = "파일 업데이트", description = "파일을 새 버전으로 업로드합니다. 기존 파일은 그대로 보존되고, 버전은 +1 증가합니다.") @PutMapping(value = "/{id}/update", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity> updateFile( diff --git a/src/main/java/kr/re/etri/autoflow/entity/MinioAttachmentEntity.java b/src/main/java/kr/re/etri/autoflow/entity/MinioAttachmentEntity.java index 16f516d..b043c61 100644 --- a/src/main/java/kr/re/etri/autoflow/entity/MinioAttachmentEntity.java +++ b/src/main/java/kr/re/etri/autoflow/entity/MinioAttachmentEntity.java @@ -87,4 +87,8 @@ public class MinioAttachmentEntity { @Comment("파일 설명") @Column(length = 1000) private String description; + + @Schema(description = "프로젝트 아이디", example = "1", defaultValue = "0") + @Column(nullable = false) + private Long projectId; } diff --git a/src/main/java/kr/re/etri/autoflow/service/MinioAttachmentService.java b/src/main/java/kr/re/etri/autoflow/service/MinioAttachmentService.java index 0971479..c6b27ff 100644 --- a/src/main/java/kr/re/etri/autoflow/service/MinioAttachmentService.java +++ b/src/main/java/kr/re/etri/autoflow/service/MinioAttachmentService.java @@ -5,6 +5,7 @@ import io.minio.PutObjectArgs; import jakarta.transaction.Transactional; import kr.re.etri.autoflow.entity.MinioAttachmentEntity; import kr.re.etri.autoflow.payload.request.BaseSearchRequest; +import kr.re.etri.autoflow.payload.request.ProjectBaseSearchRequest; import kr.re.etri.autoflow.repository.MinioAttachmentRepository; import kr.re.etri.autoflow.specification.MinioAttachmentSpecification; import lombok.RequiredArgsConstructor; @@ -105,7 +106,7 @@ public class MinioAttachmentService { /** * 검색 + 페이지네이션 */ - public Page search(BaseSearchRequest request, String refType) { + public Page search(ProjectBaseSearchRequest request, String refType) { int pageIndex = request.getPage() > 0 ? request.getPage() - 1 : 0; Pageable pageable = PageRequest.of( @@ -126,6 +127,12 @@ public class MinioAttachmentService { endDate ); + if (request.getProjectId() != null) { + spec = spec.and((root, query, cb) -> + cb.equal(root.get("projectId"), request.getProjectId()) + ); + } + return minioAttachmentRepository.findAll(spec, pageable); }