aws.. 다양한 서비스를 제공해주지만 잠깐 까먹으면 과금나오는.. 진짜 진짜 조심해야 한다. 성윤민짜짜의 성씨도 오늘 과금 만원이 넘게 나왔다. 모르고 방치했으면 정말 큰일날 뻔. AWS 서비스 사용할 때는 과금진짜 조심하자!!
Amazon Simple Storage Service(S3)는 객체 스토리지 서비스이다. 다양한 사용 사례에서 원하는 만큼의 양의 데이터를 저장하고 보호할 수 있다. 또, 사용자의 요구사항에 맞게 데이터에 대한 엑세스를 조절할 수 있는 관리 기능을 제공한다.
Aws console ➡️ S3 서비스 ➡️ 버킷 만들기로 이동한다. 버킷 이름을 입력하고, 모든 퍼블릭 엑세스 차단을 풀어준 후 버킷을 생성한다.
여러 조건을 설정할 수 있는데 꼼꼼하게 읽어본 후에 자신에게 맞는 것을 선택한다.
이렇게 생성된다!
S3에 접근하기 위해서 IAM 사용자에게 S3 접근 권한을 주어야 한다.
IAM 서비스 ➡️ 사용자 ➡️ 사용자 추가로 이동해서 사용자 이름을 입력하고 엑세스키 - 프로그래밍 방식 엑세스를 눌러준다.
기존 정책 직접 연결을 클릭하고, S3를 검색하여 원하는 접근권한을 선택한다. 나는 여기서 AmazonS3FullAccess를 선택하였다. 다음의 태그는 선택사항이니 입력해도 좋고 입력하지 않아도 좋다.
사용자 생성이 완료되면, Access-key와 Secret-key를 발급해주는데, 생성 직후에만 볼 수 있으니 안전한 곳에 저장해 두어야 한다.
application.properties에 추가해준다.
💥💥💥github에 올릴 때 진짜 꼭 제발 밑의 accesskey, secretkey 지우고 올리기💥💥💥
💥💥💥gitIgnore 페이지에 application.properties 꼭 꼭 넣고 올리기 💥💥💥
밑의 두 줄은 과금 방지를 위해 올릴 이미지의 파일 크기를 한정지어 준 것이다.
cloud.aws.region.static=ap-northeast-2
cloud.aws.stack.auto=false
cloud.aws.s3.bucket=mysparta4
cloud.aws.credentials.access-key= 발급받은 access키
cloud.aws.credentials.secret-key= 발급받은 secret키
spring.servlet.multipart.max-file-size: 10MB
spring.servlet.multipart.max-request-size: 10MB
implementation'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
build.gradle에 추가하고, 코끼리 눌러서 install해준다.
S3config.java
@Configuration
public class AwsS3Config {
@Value("${cloud.aws.credentials.access-key}")
private String accessKey;
@Value("${cloud.aws.credentials.secret-key}")
private String secretKey;
@Value("${cloud.aws.region.static}")
private String region;
@Bean
public AmazonS3Client amazonS3Client() {
BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey,secretKey);
return (AmazonS3Client) AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.build();
}
}
S3Uploader.java
@Component
@RequiredArgsConstructor
public class S3Uploader {
private final AmazonS3Client amazonS3Client;
@Value("${cloud.aws.s3.bucket}")
private String bucket;
public String uploadFiles(MultipartFile multipartFile, String dirName) throws IOException {
File uploadFile = convert(multipartFile) // 파일 변환할 수 없으면 에러
.orElseThrow(() -> new IllegalArgumentException("error: MultipartFile -> File convert fail"));
return upload(uploadFile, dirName);
}
public String upload(File uploadFile, String filePath) {
String fileName = filePath + "/" + UUID.randomUUID() + uploadFile.getName(); // S3에 저장된 파일 이름
String uploadImageUrl = putS3(uploadFile, fileName); // s3로 업로드
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()) {
System.out.println("File delete success");
return;
}
System.out.println("File delete fail");
}
// 로컬에 파일 업로드 하기
private Optional<File> convert(MultipartFile file) throws IOException {
File convertFile = new File(System.getProperty("user.dir") + "/" + file.getOriginalFilename());
if (convertFile.createNewFile()) { // 바로 위에서 지정한 경로에 File이 생성됨 (경로가 잘못되었다면 생성 불가능)
try (FileOutputStream fos = new FileOutputStream(convertFile)) { // FileOutputStream 데이터를 파일에 바이트 스트림으로 저장하기 위함
fos.write(file.getBytes());
}
return Optional.of(convertFile);
}
return Optional.empty();
}
}
아래의 controller와 service는 지금 진행중인 프로젝트에서 발췌하였다.
(1) Controller
폴더명에는 버킷에 생성한 폴더의 이름을 넣어주면 된다.
@Transactional
public GlobalResponseDto createPost(MultipartFile multipartFile, PostRequestDto postRequestDto, Account account) throws IOException {
String img = s3Uploader.uploadFiles(multipartFile, "폴더명");
Post post = new Post(postRequestDto, account, null);
postRepository.save(post);
return new GlobalResponseDto("Success Post", HttpStatus.OK.value());
}
(2) Service
@Transactional
public GlobalResponseDto createPost(MultipartFile multipartFile, PostRequestDto postRequestDto, Account account) throws IOException {
String img = s3Uploader.uploadFiles(multipartFile, "폴더명");
Post post = new Post(postRequestDto, account, null);
postRepository.save(post);
return new GlobalResponseDto("Success Post", HttpStatus.OK.value());
}
Postman으로 실행해서 확인해보면, post가 파일 변환되어 잘 업로드 되고 게시글 전체조회를 하면 url로 잘 리턴되는 것을 확인할 수 있다!