|
|
|
@ -5,6 +5,9 @@ import io.minio.messages.Item;
|
|
|
|
import io.swagger.v3.oas.annotations.Operation;
|
|
|
|
import io.swagger.v3.oas.annotations.Operation;
|
|
|
|
import io.swagger.v3.oas.annotations.Parameter;
|
|
|
|
import io.swagger.v3.oas.annotations.Parameter;
|
|
|
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
|
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
|
|
|
|
|
|
import jakarta.transaction.Transactional;
|
|
|
|
|
|
|
|
import kr.re.etri.autoflow.entity.FileUploadEntity;
|
|
|
|
|
|
|
|
import kr.re.etri.autoflow.repository.FileUploadRepository;
|
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
|
|
@ -17,6 +20,7 @@ import org.springframework.web.multipart.MultipartFile;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
import java.util.UUID;
|
|
|
|
|
|
|
|
|
|
|
|
@RestController
|
|
|
|
@RestController
|
|
|
|
@RequestMapping("/api/minio")
|
|
|
|
@RequestMapping("/api/minio")
|
|
|
|
@ -25,6 +29,8 @@ import java.util.List;
|
|
|
|
@Tag(name = "MinIO Controller", description = "MinIO 버킷/파일 관리 API")
|
|
|
|
@Tag(name = "MinIO Controller", description = "MinIO 버킷/파일 관리 API")
|
|
|
|
public class MinIOController {
|
|
|
|
public class MinIOController {
|
|
|
|
private final MinioClient minioClient;
|
|
|
|
private final MinioClient minioClient;
|
|
|
|
|
|
|
|
private final FileUploadRepository fileUploadRepository;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Value("${minio.bucket}")
|
|
|
|
@Value("${minio.bucket}")
|
|
|
|
private String bucketName;
|
|
|
|
private String bucketName;
|
|
|
|
@ -68,8 +74,9 @@ public class MinIOController {
|
|
|
|
return files;
|
|
|
|
return files;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Operation(summary = "파일 업로드", description = "MultipartFile을 MinIO 버킷에 업로드합니다. path를 지정하면 하위 폴더에 저장 가능합니다.")
|
|
|
|
@Operation(summary = "파일 업로드", description = "MultipartFile을 MinIO 버킷에 업로드하고 DB에 메타데이터를 저장합니다.")
|
|
|
|
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
|
|
|
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
|
|
|
|
|
|
|
@Transactional
|
|
|
|
public String uploadFile(
|
|
|
|
public String uploadFile(
|
|
|
|
@Parameter(description = "업로드할 파일")
|
|
|
|
@Parameter(description = "업로드할 파일")
|
|
|
|
@RequestPart("file") MultipartFile file,
|
|
|
|
@RequestPart("file") MultipartFile file,
|
|
|
|
@ -77,44 +84,28 @@ public class MinIOController {
|
|
|
|
@RequestPart(value = "path", required = false) String path
|
|
|
|
@RequestPart(value = "path", required = false) String path
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
try (InputStream is = file.getInputStream()) {
|
|
|
|
try (InputStream is = file.getInputStream()) {
|
|
|
|
String objectName = (path == null || path.isEmpty())
|
|
|
|
// ===== 버전 (지금은 기본값 1, 필요 시 자동 증가 로직 가능) =====
|
|
|
|
? file.getOriginalFilename()
|
|
|
|
int version = 1;
|
|
|
|
: path + "/" + file.getOriginalFilename();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
minioClient.putObject(
|
|
|
|
// ===== 파일명 처리 =====
|
|
|
|
PutObjectArgs.builder()
|
|
|
|
String uuid = UUID.randomUUID().toString();
|
|
|
|
.bucket(bucketName)
|
|
|
|
String originalName = file.getOriginalFilename();
|
|
|
|
.object(objectName)
|
|
|
|
String extension = "";
|
|
|
|
.stream(is, is.available(), -1)
|
|
|
|
|
|
|
|
.contentType(file.getContentType())
|
|
|
|
|
|
|
|
.build()
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// MinIO 경로 URL 생성 (NodePort 기반)
|
|
|
|
|
|
|
|
String minioUrl = String.format("%s/%s/%s", minioEndpoint, bucketName, objectName);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return "파일 업로드 성공: " + minioUrl;
|
|
|
|
if (originalName != null && originalName.contains(".")) {
|
|
|
|
} catch (Exception e) {
|
|
|
|
extension = originalName.substring(originalName.lastIndexOf(".")); // ".yaml"
|
|
|
|
log.error("파일 업로드 실패", e);
|
|
|
|
originalName = originalName.substring(0, originalName.lastIndexOf(".")); // "step1"
|
|
|
|
return "파일 업로드 실패: " + e.getMessage();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Operation(summary = "다중 파일 업로드", description = "MultipartFile 배열을 MinIO 버킷에 업로드합니다. path를 지정하면 하위 폴더에 저장 가능합니다.")
|
|
|
|
// 최종 저장 파일명 => UUID-step1-ver.1.yaml
|
|
|
|
@PostMapping(value = "/upload-multiple", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
|
|
|
String storedName = String.format("%s-%s-ver.%d%s", uuid, originalName, version, extension);
|
|
|
|
public List<String> uploadMultipleFiles(
|
|
|
|
|
|
|
|
@Parameter(description = "업로드할 파일들")
|
|
|
|
// MinIO 저장 경로
|
|
|
|
@RequestPart("files") MultipartFile[] files,
|
|
|
|
|
|
|
|
@Parameter(description = "저장 경로 (선택)")
|
|
|
|
|
|
|
|
@RequestPart(value = "path", required = false) String path
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
List<String> uploadedUrls = new ArrayList<>();
|
|
|
|
|
|
|
|
for (MultipartFile file : files) {
|
|
|
|
|
|
|
|
try (InputStream is = file.getInputStream()) {
|
|
|
|
|
|
|
|
String objectName = (path == null || path.isEmpty())
|
|
|
|
String objectName = (path == null || path.isEmpty())
|
|
|
|
? file.getOriginalFilename()
|
|
|
|
? storedName
|
|
|
|
: path + "/" + file.getOriginalFilename();
|
|
|
|
: path + "/" + storedName;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ===== MinIO 업로드 =====
|
|
|
|
minioClient.putObject(
|
|
|
|
minioClient.putObject(
|
|
|
|
PutObjectArgs.builder()
|
|
|
|
PutObjectArgs.builder()
|
|
|
|
.bucket(bucketName)
|
|
|
|
.bucket(bucketName)
|
|
|
|
@ -124,18 +115,33 @@ public class MinIOController {
|
|
|
|
.build()
|
|
|
|
.build()
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// MinIO 접근 URL (NodePort 기반)
|
|
|
|
String minioUrl = String.format("%s/%s/%s", minioEndpoint, bucketName, objectName);
|
|
|
|
String minioUrl = String.format("%s/%s/%s", minioEndpoint, bucketName, objectName);
|
|
|
|
uploadedUrls.add(minioUrl);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ===== DB 저장 =====
|
|
|
|
|
|
|
|
FileUploadEntity entity = FileUploadEntity.builder()
|
|
|
|
|
|
|
|
.refType("workflow_step") // 필요시 파라미터로 변경 가능
|
|
|
|
|
|
|
|
.refId(1L) // 필요시 파라미터로 변경 가능
|
|
|
|
|
|
|
|
.originalName(file.getOriginalFilename())
|
|
|
|
|
|
|
|
.storedName(storedName)
|
|
|
|
|
|
|
|
.contentType(file.getContentType())
|
|
|
|
|
|
|
|
.size(file.getSize())
|
|
|
|
|
|
|
|
.storagePath(objectName)
|
|
|
|
|
|
|
|
.regUserId("admin") // 로그인 사용자 ID로 변경 가능
|
|
|
|
|
|
|
|
.version(version)
|
|
|
|
|
|
|
|
.title(null) // 필요 시 @RequestPart 로 받도록 확장
|
|
|
|
|
|
|
|
.description(null) // 필요 시 @RequestPart 로 받도록 확장
|
|
|
|
|
|
|
|
.build();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fileUploadRepository.save(entity);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return "파일 업로드 성공: " + minioUrl;
|
|
|
|
} catch (Exception e) {
|
|
|
|
} catch (Exception e) {
|
|
|
|
log.error("파일 업로드 실패: {}", file.getOriginalFilename(), e);
|
|
|
|
log.error("파일 업로드 실패", e);
|
|
|
|
uploadedUrls.add("업로드 실패: " + file.getOriginalFilename() + " (" + e.getMessage() + ")");
|
|
|
|
return "파일 업로드 실패: " + e.getMessage();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return uploadedUrls;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Operation(summary = "파일 다운로드", description = "MinIO에서 파일을 다운로드합니다.")
|
|
|
|
@Operation(summary = "파일 다운로드", description = "MinIO에서 파일을 다운로드합니다.")
|
|
|
|
@GetMapping("/download")
|
|
|
|
@GetMapping("/download")
|
|
|
|
public ResponseEntity<byte[]> downloadFile(@RequestParam String objectName) {
|
|
|
|
public ResponseEntity<byte[]> downloadFile(@RequestParam String objectName) {
|
|
|
|
|