프로젝트를 진행하면 이미지를 서버에 저장해야 하는 경우가 많은데, 이럴 때 많은 사람들이 AWS의 S3를 이용하여 데이터를 저장하고, 이 링크를 DB에 저장하여 사용하는 경우가 많습니다.
왜냐하면 프로젝트 서버 내에 직접 파일을 적재하면 용량이 많이 필요하기 때문입니다.
그래서 이번 포스팅에서는 AWS S3 버킷을 생성한 후, Spring을 이용해 데이터를 저장해보도록 하겠습니다.
s3 버킷 생성
1. AWS > S3 > 버킷 > 버킷 만들기 클릭
또는 다음 주소에 접속합니다.
https://ap-northeast-2.console.aws.amazon.com/s3/bucket/create?region=ap-northeast-2
2. 버킷 생성
버킷을 생성하기 위해 이름을 입력합니다.
액세스 차단 설정의 경우에는 모든 퍼블릭 액세스 차단을 해제해주세요.
3. 버킷 정책 설정
퍼블릭IP에서 데이터를 조회할 수 있도록 정책을 설정해주어야 합니다.
그러기 위해 S3 > 버킷 > 권한 > 버킷 정책 > 편집을 클릭합니다.
정책 설정을 입력합니다. 저는 다음과 같이 입력해주었고, 입력시 모든 주석을 삭제해야합니다.
{
"Version": "2012-10-17",
"Id": "Policy1464968545158",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow", // 허용
"Principal": "*",
"Action": "s3:GetObject", // 객체 읽기 권한
"Resource": "arn:aws:s3:::<버킷명>/*"
},
{
"Sid": "DenyOtherAccess",
"Effect": "Deny", // 차단
"Principal": "*",
"Action": "s3:PutObject", // 객체 업로드 권한
"NotResource": [
"arn:aws:s3:::<버킷명>/*.jpg",
"arn:aws:s3:::<버킷명>/*.png",
"arn:aws:s3:::<버킷명>/*.jpeg",
"arn:aws:s3:::<버킷명>/*.gif"
] // 해당 확장자를 가지지 않은 객체
}
]
}
사용자(I AM 자격증명) 설정
1. AWS > IAM > 엑세스 관리 > 사용자 > 사용자 추가를 클릭합니다.
2. 사용자 이름 설정
3. 권한 설정
직접 정책 연결 > AmazonS3FullAccess을 설정합니다.
4. 사용자 생성 누르기
액세스 키 생성
1. AWS > IAM > 사용자 > 액세스 키 만들기를 선택합니다.
2. 액세스 키 모범 사례 및 대안
아무거나 선택 후 계속해도 됩니다. 저는 로컬 코드를 선택해주었습니다.
3.액세스 키, 비밀 액세스키 확인
사용자가 생성이 되었으면, 액세스키를 생성할 수 있습니다. 여기서 비밀 액세스키는 다시 볼 수 없기 때문에 csv 파일로 받아두는 것을 추천합니다.
spring 설정
1. 의존성 추가
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
2. application.yml
cloud:
aws:
credentials:
accessKey: ${AWS_ACCESS_KEY_ID} # AWS IAM AccessKey 적기
secretKey: ${AWS_SECRET_ACCESS_KEY} # AWS IAM SecretKey 적기
s3:
bucket: 버킷명 # 예) myawsbucket
dir: S3 디렉토리 이름 # 예) /home
region:
static: ap-northeast-2
stack:
auto: false
3. S3Config
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class S3Config {
@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();
}
}
4. S3Service
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.ObjectMetadata;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.UUID;
@RequiredArgsConstructor
@Service
public class S3ServiceImpl implements S3Service {
private final AmazonS3 amazonS3;
@Value("${cloud.aws.s3.bucket}")
private String bucket;
// 파일 업로드
@Override
public String uploadFile(MultipartFile multipartFile, String url) throws IOException {
String fileName = url+"/"+UUID.randomUUID().toString() + "_" + multipartFile.getOriginalFilename();
ObjectMetadata objMeta = new ObjectMetadata();
objMeta.setContentLength(multipartFile.getSize());
amazonS3.putObject(bucket, fileName, multipartFile.getInputStream(), objMeta);
return amazonS3.getUrl(bucket, fileName).toString();
}
// 파일 삭제
@Override
public boolean delete(String fileUrl) {
try {
String[] temp = fileUrl.split("/");
String fileKey = temp[temp.length-1];
amazonS3.deleteObject(bucket, fileKey);
return true;
} catch (Exception e) {
return false;
}
}
}
5. controller
데이터를 받을 때에는 @RequestPart로 받으면 됩니다.
import com.restgram.domain.feed.dto.request.AddFeedRequest;
import com.restgram.domain.feed.service.FeedService;
import com.restgram.global.exception.entity.CommonResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;
@RequiredArgsConstructor
@RestController
@RequestMapping("/feed")
@Slf4j
public class FeedController {
private final FeedService feedService;
@PostMapping
public CommonResponse postFeed(Authentication authentication, @RequestPart AddFeedRequest req, @RequestPart("images") List<MultipartFile> images)) {
...
}
}
POSTMAN을 이용하여 테스트를 해본 결과 S3에 데이터가 잘 저장됨을 확인할 수 있습니다.
참고
https://velog.io/@shwj203/Spring-AWS-S3-%EC%83%9D%EC%84%B1-SpringBoot-%EC%97%B0%EB%8F%99
'프로젝트' 카테고리의 다른 글
[JPA] Column 'chatroom_id' cannot be null 문제 해결하기 (0) | 2024.05.31 |
---|---|
[Spring] entity 변경해도 update 쿼리 안날라가는 이슈 (0) | 2024.05.28 |
[Spring Security] 인가 실패 시 카카오 로그인 화면 리턴 오류 (0) | 2024.05.17 |
[CS] WebSocket이란 ? (0) | 2024.04.23 |
[채팅] Spring Security + WebSocket 연결하기 (0) | 2024.02.22 |