build.gradle
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.0.1.RELEASE'
aws.yml
cloud:
aws:
credentials:
accessKey: IAM-accessKey
secretKey: IAM-secretKey
s3:
bucket: bucketName
region:
static: ap-northeast-2
stack:
auto: false
main class
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
@SpringBootApplication
public class Hanghae99cloneApplication {
public static final String APPLICATION_LOCATIONS = "spring.config.location="
+ "classpath:application.properties,"
+ "classpath:aws.yml";
public static void main(String[] args) {
new SpringApplicationBuilder(Hanghae99cloneApplication.class)
.properties(APPLICATION_LOCATIONS)
.run(args);
}
}
ImageController
import com.sparta.hanghae99clone.config.S3Uploader;
import java.io.IOException;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RequiredArgsConstructor
@RestController
public class ImageController {
private final S3Uploader s3Uploader;
@PostMapping("/images")
public String upload(@RequestParam("images") MultipartFile multipartFile) throws IOException {
return s3Uploader.upload(multipartFile);
}
}
S3 uploader
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.PutObjectRequest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Optional;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
@Slf4j
@RequiredArgsConstructor
@Component
public class S3Uploader {
private static final String IMAGE_UPLOAD_DIR = "static/image";
private final AmazonS3Client amazonS3Client;
@Value("${cloud.aws.s3.bucket}")
public String bucket; // S3 버킷 이름
public String upload(MultipartFile multipartFile) throws IOException {
File uploadFile = convert(multipartFile) // 파일 변환할 수 없으면 에러
.orElseThrow(() -> new IllegalArgumentException("error: MultipartFile -> File convert fail"));
return upload(uploadFile);
}
// S3로 파일 업로드하기
private String upload(File uploadFile) {
// S3에 저장된 파일 이름 (한글 파일 이름이 올라올 경우 s3에서 문제가 발생함 -> 한글파일 이름을 빼고 UUid 이름만 저장하려고 함)
// String fileName = dirName + "/" + UUID.randomUUID() + uploadFile.getName();
String fileName = IMAGE_UPLOAD_DIR + "/" + UUID.randomUUID();
// s3로 업로드
String uploadImageUrl = putS3(uploadFile, fileName);
removeNewFile(uploadFile);
return uploadImageUrl;
}
// S3로 업로드
private String putS3(File uploadFile, String fileName) {
amazonS3Client.putObject(new PutObjectRequest(bucket, fileName, uploadFile).withCannedAcl(
CannedAccessControlList.PublicRead));
return amazonS3Client.getUrl(bucket, fileName).toString();
}
// 로컬에 저장된 이미지 지우기
private void removeNewFile(File targetFile) {
if (targetFile.delete()) {
log.info("File delete success");
return;
}
log.info("File delete fail");
}
// 로컬에 파일 업로드 하기
private Optional<File> convert(MultipartFile file) throws IOException {
// "현재 폴더/파일 이름" 정보를 가지고 있는 file 객체 생성
File convertFile = new File(System.getProperty("user.dir") + "/" + file.getOriginalFilename());
// 바로 위에서 지정한 경로에 File이 생성됨 (경로가 잘못되었다면 생성 불가능)
if (convertFile.createNewFile()) {
try (FileOutputStream fos = new FileOutputStream(convertFile)) {
// FileOutputStream 데이터를 파일에 바이트 스트림으로 저장하기 위함
fos.write(file.getBytes());
}
return Optional.of(convertFile);
}
return Optional.empty();
}
}
Reference
https://devlog-wjdrbs96.tistory.com/323