반응형
Spring Boot에서 AWS S3저장
- MultipartFile 또는 File 방식으로 이미지 전달받음
- AWS S3 퍼블릭 버킷을 생성하여 전달
- AWS S3 관련 계정 정보는 소스 코드 외 관리
MultipartFile 또는 File 방식으로 이미지 전달받음
S3UploaderController
package swlee.logiclist.controller;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import swlee.logiclist.utils.S3UploaderService;
import java.io.IOException;
@Slf4j
@RequiredArgsConstructor
@Controller
public class S3UploaderController {
private final S3UploaderService s3UploaderService;
@GetMapping("/image")
public String image() {
return "image-upload";
}
//
// @GetMapping("/video")
// public String video() {
// return "video-upload";
// }
@PostMapping("/image-upload")
@ResponseBody
public String imageUpload(@RequestParam("data") MultipartFile multipartFile) throws IOException {
log.info("imageUpload IN");
String result = s3UploaderService.upload(multipartFile, "logiclist", "image");
//JSON Response
Gson gson = new Gson();
// Json key, value 추가
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("result", result);
// JsonObject를 Json 문자열로 변환
String jsonStr = gson.toJson(jsonObject);
// 생성된 Json 문자열 출력
log.info("JSONSTR::{}",jsonStr);
return jsonStr;
}
}
S3UploaderService
package swlee.logiclist.utils;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.PutObjectRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.util.Optional;
import java.util.UUID;
@Service
@Slf4j
public class S3UploaderService {
// private static final Logger log = org.slf4j.LoggerFactory.getLogger(S3UploaderService.class);
// local, development 등 현재 프로파일
@Value("${spring.environment}")
private String environment;
// 파일이 저장되는 경로
@Value("${spring.file-dir}")
private String rootDir;
private String fileDir;
private final AmazonS3Client amazonS3Client;
public S3UploaderService(AmazonS3Client amazonS3Client) {
this.amazonS3Client = amazonS3Client;
}
/**
* 서버가 시작할 때 프로파일에 맞는 파일 경로를 설정해줌
*/
@PostConstruct
private void init(){
if(environment.equals("local")){
this.fileDir = System.getProperty("user.dir") + this.rootDir;
}
else if(environment.equals("development")){
this.fileDir = this.rootDir;
}
}
public String upload(MultipartFile multipartFile, String bucket, String dirName) throws IOException {
File uploadFile = convert(multipartFile) // 파일 변환할 수 없으면 에러
.orElseThrow(() -> new IllegalArgumentException("error: MultipartFile -> File convert fail"));
return upload(uploadFile, bucket, dirName);
}
// S3로 파일 업로드하기
private String upload(File uploadFile, String bucket, String dirName) {
String fileName = dirName + "/" + UUID.randomUUID() + uploadFile.getName(); // S3에 저장된 파일 이름
String uploadImageUrl = putS3(uploadFile, bucket, fileName); // s3로 업로드
removeNewFile(uploadFile);
return uploadImageUrl;
}
// S3로 업로드
private String putS3(File uploadFile, String bucket, 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");
}
/**
* @param multipartFile
* 로컬에 파일 저장하기
*/
private Optional<File> convert(MultipartFile multipartFile) throws IOException {
if (multipartFile.isEmpty()) {
return Optional.empty();
}
String originalFilename = multipartFile.getOriginalFilename();
String storeFileName = createStoreFileName(originalFilename);
//파일 업로드
File file = new File(fileDir+storeFileName);
multipartFile.transferTo(file);
return Optional.of(file);
}
/**
* @description 파일 이름이 이미 업로드된 파일들과 겹치지 않게 UUID를 사용한다.
* @param originalFilename 원본 파일 이름
* @return 파일 이름
*/
private String createStoreFileName(String originalFilename) {
String ext = extractExt(originalFilename);
String uuid = UUID.randomUUID().toString();
return uuid + "." + ext;
}
/**
* @description 사용자가 업로드한 파일에서 확장자를 추출한다.
*
* @param originalFilename 원본 파일 이름
* @return 파일 확장자
*/
private String extractExt(String originalFilename) {
int pos = originalFilename.lastIndexOf(".");
return originalFilename.substring(pos + 1);
}
}
application.yml
실제 운영환경과 개발환경 분리
spring:
profiles:
group:
"local": "local, common"
"development": "development,common"
active: local
---
# 공통
spring:
config:
activate:
on-profile: "common"
servlet:
multipart:
max-file-size: 100MB
# s3에 필요한 정보
cloud:
aws:
region:
static: ap-northeast-2
s3:
bucket: logiclist
stack:
auto: false
logging:
level:
com:
amazonaws:
util:
EC2MetadataUtils: error
---
# 로컬 환경
spring:
environment: "local"
config:
activate:
on-profile: "local"
file-dir: /src/main/resources/static/files/
---
# 배포 환경
spring:
environment: "development"
config:
activate:
on-profile: "development"
file-dir: /home/ec2-user/files/
aws.yml - S3 버킷에 대한 권한을 가지고 있는 IAM 생성 후 관련 credentials 기재
cloud:
aws:
credentials:
access-key: 사용자 액세스 키
secret-key: 사용자 시크릿 키
반응형
'Project' 카테고리의 다른 글
[LogicList]TodoList 프론트 기능 (0) | 2022.10.22 |
---|---|
[LogicList] Toast Ui Editor & SpringBoot AWS S3 업데이트[0] (0) | 2022.10.10 |
[LogicList]Toast Ui Editor 이미지 URL 삽입방법과 문제점 (0) | 2022.09.23 |
[LogicList]Init[0] (0) | 2022.09.21 |
2020 포트폴리오 (0) | 2022.03.08 |