diff --git a/src/main/java/kr/re/etri/autoflow/controllers/AttachmentController.java b/src/main/java/kr/re/etri/autoflow/controllers/AttachmentController.java index 2db0877..9f82339 100644 --- a/src/main/java/kr/re/etri/autoflow/controllers/AttachmentController.java +++ b/src/main/java/kr/re/etri/autoflow/controllers/AttachmentController.java @@ -3,7 +3,6 @@ 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.enums.ParameterIn; import io.swagger.v3.oas.annotations.tags.Tag; import kr.re.etri.autoflow.entity.MinioAttachmentEntity; import kr.re.etri.autoflow.payload.request.BaseSearchRequest; @@ -12,7 +11,6 @@ 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.data.domain.Page; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -96,4 +94,33 @@ public class AttachmentController { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } } + + @Operation(summary = "파일 업데이트", description = "파일을 새 버전으로 업로드합니다. 기존 파일은 그대로 보존되고, 버전은 +1 증가합니다.") + @PutMapping(value = "/{id}/update", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public ResponseEntity> updateFile( + @Parameter(description = "기존 첨부파일 ID", required = true) + @PathVariable("id") Long id, + @Parameter(description = "새 파일") @RequestPart("file") MultipartFile file, + @RequestPart(value = "path", required = false) String path, + @RequestParam(value = "title", required = false) String title, + @RequestParam(value = "description", required = false) String description, + @RequestParam(value = "regUserId") String regUserId + ) { + try { + MinioAttachmentEntity updated = minioAttachmentService.updateFile( + id, file, path, title, description, regUserId + ); + + Map response = new HashMap<>(); + response.put("attachment", updated); + response.put("minioUrl", minioAttachmentService.getFileUrl(updated.getStoragePath())); + + return ResponseEntity.ok(response); + + } catch (Exception e) { + log.error("파일 업데이트 실패", e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + } \ No newline at end of file diff --git a/src/main/java/kr/re/etri/autoflow/repository/MinioAttachmentRepository.java b/src/main/java/kr/re/etri/autoflow/repository/MinioAttachmentRepository.java index 2290520..87f717a 100644 --- a/src/main/java/kr/re/etri/autoflow/repository/MinioAttachmentRepository.java +++ b/src/main/java/kr/re/etri/autoflow/repository/MinioAttachmentRepository.java @@ -6,8 +6,10 @@ import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.stereotype.Repository; import java.util.List; +import java.util.Optional; @Repository public interface MinioAttachmentRepository extends JpaRepository, JpaSpecificationExecutor { - + //최신버전 파일 가져오기 + Optional findTopByRefIdAndRefTypeOrderByVersionDesc(Long refId, String refType); } 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 a7c86d9..0971479 100644 --- a/src/main/java/kr/re/etri/autoflow/service/MinioAttachmentService.java +++ b/src/main/java/kr/re/etri/autoflow/service/MinioAttachmentService.java @@ -91,7 +91,6 @@ public class MinioAttachmentService { /** * 전체 조회 */ - @Transactional public List findAll() { return minioAttachmentRepository.findAll(); } @@ -99,7 +98,6 @@ public class MinioAttachmentService { /** * ID 조회 */ - @Transactional public Optional findById(Long id) { return minioAttachmentRepository.findById(id); } @@ -141,10 +139,65 @@ public class MinioAttachmentService { } } + public MinioAttachmentEntity updateFile( + Long id, + MultipartFile file, + String path, + String title, + String description, + String regUserId + ) throws Exception { + // 기존 엔티티 조회 + MinioAttachmentEntity existing = minioAttachmentRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("첨부파일을 찾을 수 없습니다. ID=" + id)); + + // 최신 버전 조회 + Integer latestVersion = minioAttachmentRepository + .findTopByRefIdAndRefTypeOrderByVersionDesc(existing.getRefId(), existing.getRefType()) + .map(MinioAttachmentEntity::getVersion) + .orElse(0); + + int newVersion = latestVersion + 1; + + // 새 파일 업로드 + String storedName = UUID.randomUUID() + "-" + file.getOriginalFilename(); + String objectName = (path == null || path.isEmpty()) + ? storedName + : path + "/" + storedName; + + try (InputStream is = file.getInputStream()) { + minioClient.putObject( + PutObjectArgs.builder() + .bucket(bucketName) + .object(objectName) + .stream(is, is.available(), -1) + .contentType(file.getContentType()) + .build() + ); + } + + // 새로운 엔티티 생성 (이전 데이터는 그대로 두고, 새로운 버전 생성) + MinioAttachmentEntity newAttachment = MinioAttachmentEntity.builder() + .refId(existing.getRefId()) + .refType(existing.getRefType()) + .originalName(file.getOriginalFilename()) + .storedName(storedName) + .contentType(file.getContentType()) + .size(file.getSize()) + .storagePath(objectName) + .title(title != null ? title : existing.getTitle()) + .description(description != null ? description : existing.getDescription()) + .version(newVersion) + .regUserId(regUserId) + .build(); + + return minioAttachmentRepository.save(newAttachment); + } + + /** * 생성 (DB만 저장, 파일은 따로 업로드된 경우) */ - @Transactional public MinioAttachmentEntity create(MinioAttachmentEntity entity) { return minioAttachmentRepository.save(entity); } @@ -152,7 +205,6 @@ public class MinioAttachmentService { /** * 업데이트 */ - @Transactional public Optional update(Long id, MinioAttachmentEntity dto) { return minioAttachmentRepository.findById(id) .map(entity -> { @@ -164,7 +216,6 @@ public class MinioAttachmentService { /** * 삭제 */ - @Transactional public boolean delete(Long id) { if (!minioAttachmentRepository.existsById(id)) { return false;