반응형

AWS S3 란?

  • AWS Simple Storage Service의 줄임말로 파일 서버의 역할을 하는 서비스
  • 프로젝트 개발 중 파일을 저장하고 불러오는 작업이 필요한 경우에 프로젝트 내부 폴더에 저장할 수 있지만, AWS S3를 사용하여 파일을 관리할 수도 있음

AWS S3의 장점

  • 무제한 용량 (하나의 파일에 대한 용량 제한은 있지만, 전체 용량은 무제한)
  • 파일 저장에 최적화 (개발자가 따로 용량을 추가하거나 성능을 높이는 작업을 하지 않아도 됨)
  • 99.999%라는 높은 내구도 (파일이 유실될 가능성이 낮음)
  • 이 외에도 저렴한 비용, 높은 객체 가용성, 뛰어난 보안성 등의 장점이 있음

AWS S3 생성

  • 객체(Object) : 파일과 파일정보로 구성된 저장단위로 파일이라 생각하면 됨
  • 버킷(Bucket) : 저장된 객체에 대한 컨테이너
  • 버킷은 최대 100개 생성 가능하며, 버킷에 저장할 수 있는 객체수는 제한이 없음

Bucket 생성

  1. AWS Console 접속 후 S3 서비스 선택
  2. 버킷 만들기 클릭
  3. 원하는 버킷 이름 입력
  4. AWS 리전 선택 (아시아 태평양(서울) ap-northeast-2 )
  5. 객체 소유권 선택 (ACL 비활성화)
  6. '모든 퍼블릭 액세스 차단' 해제
  7. 나머지는 Default

사용자 생성

  1. AWS Console 접속 후 IAM 서비스 선택
  2. 액세스 관리 -> 사용자 -> 사용자 추가
  3. 원하는 이름 입력 후 다음
  4. 직접 정책 연결 -> AmazonS3FullAccess 선택 후 다음
  5. 사용자 생성

액세스 키 생성

  1. 방금 생성한 사용자 선택 후 보안 자격 증명 탭 클릭
  2. 액세스 키 만들기 클릭
  3. 기타 선택 후 다음
  4. 원하는 설명 태그 입력 후 액세스 키 만들기
  5. 액세스 키를 만들면 아래와 같이 액세스 키와 비밀 액세스 키를 확인할 수 있는데, 이 값들을 저장후 완료

버킷 정책 변경

  1. AWS Console에서 생성한 버킷으로 이동
  2. 권한 -> 버킷 정책 -> 편집
  3. 정책이 비어있으면 '+ 새 문 추가' 클릭
  4. 정책 내용을 아래와 같이 변경
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement1",
            "Principal": "*",
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::<버킷 이름>/*"
        }
    ]
}

Spring 프로젝트와 연동

라이브러리 추가 (build.gradle)

implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'

application.yml에 아래 내용 추가

cloud:
  aws:
    s3:
      bucket: <S3 버킷 이름>
    credentials:
      access-key: <저장해놓은 액세스 키>
      secret-key: <저장해놓은 비밀 액세스 키>
    region:
      static: ap-northeast-2
      auto: false
    stack:
      auto: false

S3Config.java 생성

@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 credentials = new BasicAWSCredentials(accessKey, secretKey);

        return (AmazonS3Client) AmazonS3ClientBuilder
                .standard()
                .withRegion(region)
                .withCredentials(new AWSStaticCredentialsProvider(credentials))
                .build();
    }
}

파일 업로드 구현

@Service
@RequiredArgsConstructor
public class S3UploadService {

    private final AmazonS3 amazonS3;

    @Value("${cloud.aws.s3.bucket}")
    private String bucket;

    public String saveFile(MultipartFile multipartFile) throws IOException {
        String originalFilename = multipartFile.getOriginalFilename();

        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(multipartFile.getSize());
        metadata.setContentType(multipartFile.getContentType());

        amazonS3.putObject(bucket, originalFilename, multipartFile.getInputStream(), metadata);
        return amazonS3.getUrl(bucket, originalFilename).toString();
    }
}
  • putObject() 메소드가 파일을 저장해주는 메소드
  • getURl()을 통해 파일이 저장된 URL을 return 해주고, 이 URL로 이동 시 해당 파일이 오픈됨 (버킷 정책 변경을 하지 않았으면 파일은 업로드 되지만 해당 URL로 이동 시 accessDenied 됨)
  • 만약 MultipartFile에 대해 잘 모르거나 웹 페이지에서 form으로 파일을 입력받고 싶다면 [Spring Boot] 파일 업로드 참고

파일 다운로드 구현

public ResponseEntity<UrlResource> downloadImage(String originalFilename) {
    UrlResource urlResource = new UrlResource(amazonS3.getUrl(bucket, originalFilename));

    String contentDisposition = "attachment; filename=\"" +  originalFilename + "\"";

    // header에 CONTENT_DISPOSITION 설정을 통해 클릭 시 다운로드 진행
    return ResponseEntity.ok()
            .header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition)
            .body(urlResource);

}
  • 로컬 파일 다운로드 할 때에는 UrlResource() 메소드에 "file:" + 로컬 파일 경로를 넣어주면 로컬 파일이 다운로드 되었음
  • S3에 올라간 파일은 위와 같이 amazonS3.getUrl(버킷이름, 파일이름)을 통해 파일 다운로드를 할 수 있음

HTML 파일에서 이미지 미리보기 구현

String url = amazonS3.getUrl(bucket, filename).toString();
  • 위에서 구한 amazonS3 URL을 Model에 담아 HTML 파일로 전송
  • 아래와 같이 Thymeleaf를 이용해 URL을 받고 src에 넣어주면 화면에서 이미지 미리보기 가능
<img th:src="${s3ImageUrl}"/>

파일 삭제 구현

public void deleteImage(String originalFilename)  {
    amazonS3.deleteObject(bucket, originalFilename);
}
반응형

↓ 클릭시 이동

복사했습니다!