S3Service.java
package qwerty.chaekit.service.util;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import qwerty.chaekit.global.enums.ErrorCode;
import qwerty.chaekit.global.enums.S3Directory;
import qwerty.chaekit.global.exception.BadRequestException;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;
import java.io.InputStream;
import java.time.Duration;
import java.util.Objects;
import java.util.UUID;
@Service
@RequiredArgsConstructor
public class S3Service {
private final S3Presigner s3Presigner;
private final S3Client s3Client;
// Download URL
public String getPresignedDownloadUrl(String bucket, String fileKey, Long expirationTime) {
GetObjectRequest getObjectRequest = GetObjectRequest.builder()
.bucket(bucket)
.key(fileKey)
.build();
PresignedGetObjectRequest presignedRequest = s3Presigner.presignGetObject(builder -> builder
.getObjectRequest(getObjectRequest)
.signatureDuration(Duration.ofSeconds(expirationTime))
);
return presignedRequest.url().toString();
}
// Upload
public boolean isFileMissing(MultipartFile file) {
return file == null
|| file.isEmpty()
|| file.getOriginalFilename() == null
|| file.getOriginalFilename().isBlank();
}
public String uploadFile(String bucket, S3Directory directory, MultipartFile file) {
if (isFileMissing(file)) {
throw new BadRequestException(ErrorCode.FILE_MISSING);
}
String fileName = file.getOriginalFilename();
String extension = Objects.requireNonNull(fileName).substring(fileName.lastIndexOf("."));
assertByS3DirectoryRule(directory, file, extension);
String fileKey = directory.getPath() + UUID.randomUUID() + extension;
uploadToS3(bucket, fileKey, file);
return fileKey;
}
private static void assertByS3DirectoryRule(S3Directory directory, MultipartFile file, String extension) {
if (file.getSize() > directory.getMaxSize()) {
throw new BadRequestException(ErrorCode.FILE_SIZE_EXCEEDED);
}
if (!directory.getAllowedExtensions().contains(extension)) {
throw new BadRequestException(ErrorCode.INVALID_EXTENSION);
}
}
private void uploadToS3(String bucket, String fileKey, MultipartFile file) {
try (InputStream inputStream = file.getInputStream()) {
s3Client.putObject(
PutObjectRequest.builder()
.bucket(bucket)
.key(fileKey)
.build(),
RequestBody.fromInputStream(inputStream, file.getSize()));
} catch (Exception e) {
throw new RuntimeException("Failed to upload file to S3", e);
}
}
}