Spring + Amazon S3 연동

선종우·2023년 5월 31일
0

1. 공부배경

  • Spring boot 프로젝트에서 Amazon S3연동 방법을 찾던 중 라이브러리에 여러 기능이 있어 정리해보았다.
  • 공식 문서 : docs

2. 공부내용

  • 용어 : Amazon S3에서 객체(object)는 파일 또는 데이터의 집합을 의미한다. 모든 객체는 bucket 내에 있다. -> 아마존 문서에서 객체는 우리가 통상적으로 생각하는 파일이라고 보면 된다.

  • 2.1 파일 업로드

    • putObject메소드를 이용하여 파일을 업로드 한다. 오버로딩된 putObject 메소드는 아래와 같다.

         putObject(String bucketName, String key, File file) //bucket과 파일명, File을 이용하는 방식
          putObject(String bucketName, String key, InputStream input, ObjectMetadata metadata) //bucket과 파일명, InputStream, 파일의 메타데이터를 이용하는 방식
          putObject(PutObjectRequest putObjectRequest) // putObjectRequest를 이용하는 방식
      
    • 아래 예제 코드에서는 PutObjectRequest를 넘기는 방식을 사용하였다.

      @Service
      @RequiredArgsConstructor
      public class S3FileService {
      
          private final AmazonS3 amazonS3Client; // 생성자 주입방식, 별도 config파일에 AmazonS3ClientBean을 생성해 두었다.
      
          //property파일에서 bucket명을 불러오게끔 설정하였다.
          //private String bucket = "버킷명";과 같이 직접 설정해도 무관하다.
          @Value("${cloud.aws.s3.bucket}") 
          private String bucket;
          
          //여러 개의 파일을 동시에 업로드하며 생성된 파일의 URL을 사용자에게 건네는 방식으로 메소드를 구현하였다.
          public List<URL> fileUpload(List<MultipartFile> multipartFiles){
              List<URL> urlList = new ArrayList<>();
              
              multipartFiles.forEach(multipartFile -> {
                  String fileName = makeFileName(multipartFile); //key값으로 넘겨주기 위한 파일명 생성 메소드, 각 파일을 식별할 수 있는 고유한 값만 생성될 수 있다면 생성 방식은 개발자 재량이다.
                  ObjectMetadata objectMetadata = new ObjectMetadata(); 
                  objectMetadata.setContentType(multipartFile.getContentType()); //객체(파일)의 메타데이터 설정
      			/*
                    1. multipartFile로부터 데이터를 읽은 후 PutObjectRequest 객체를 생성한다. 
                    2. 이때 파일을 외부에서 읽을 수 있도록 하기 위해 withCannedAcl을 설정한다.(개별 파일에 cannedAcl(사전 정의된 ACL)을 적용한다는 의미이다.)
                    3. putObject메소드를 이용해 생성된 객체를 AWS S3로 전송한다.
                  */
                  try(InputStream inputStream = multipartFile.getInputStream()){
                      amazonS3Client.putObject(new PutObjectRequest(bucket, fileName, inputStream, objectMetadata)
                              .withCannedAcl(CannedAccessControlList.PublicRead));
      		
                  }catch(IOException e){
                  //파일 생성 및 업로드 과정에서 발생한 예외에 대해 적절한 처리를 해준다.
                      throw new ResourceCreationException(ErrorCode.FILE_UPLOAD_ERROR, "Img Upload Fail");
                  }
                  //bucket으로 부터 key(file명)에 대한 url 정보를 가져온다.
                  urlList.add(amazonS3Client.getUrl(bucket, fileName));
              });
      
              return urlList;
          }
          //key(파일명) 생성전략은 개발자에 자유이다.
          private String makeFileName(MultipartFile multipartFile){
              String originalName = multipartFile.getOriginalFilename();
              final String ext = originalName.substring(originalName.lastIndexOf("."));
              final String fileName = UUID.randomUUID().toString() + ext;
              return System.getProperty("user.dir") + fileName;
          }
      }
    • 아마존 공식 예제 : github

  • 2.2 파일 목록 불러오기

    • listObjectsV2를 이용하여 목록을 가져온다. 오버로딩 메소드는 아래와 같다.
     public ListObjectsV2Result listObjectsV2(String bucketName)
      public ListObjectsV2Result listObjectsV2(String bucketName, String prefix) 
      public ListObjectsV2Result listObjectsV2(ListObjectsV2Request listObjectsV2Request)
    
    • 아래 예제 코드에서는 bucketName만을 넘겨 모든 객체(파일) 리스트를 불러왔다.

      @Service
      @RequiredArgsConstructor
      public class S3FileService {
      
          private final AmazonS3 amazonS3Client; // 생성자 주입방식, 별도 config파일에 AmazonS3ClientBean을 생성해 두었다.
      
          //property파일에서 bucket명을 불러오게끔 설정하였다.
          //private String bucket = "버킷명";과 같이 직접 설정해도 무관하다.
          @Value("${cloud.aws.s3.bucket}") 
          private String bucket;
          
          
          public List<String> getFileList(){
              List<String> fileList = new ArrayList<>();
              
              ListObjectsV2Result result = s3.listObjectsV2(bucket_name);
              List<S3ObjectSummary> objects = result.getObjectSummaries();
              for (S3ObjectSummary os : objects) {
              	    fileList.add(os.getKey());
               }
      
              return fileList;
          }
          
      }
    • 아마존 공식 예제 : github

  • 2.3 파일 가져오기(내 서버로 다운로드)

    • getObject를 이용하여 객체(파일)를 가져온다.

       public S3Object getObject(String bucketName, String key)
        public S3Object getObject(GetObjectRequest getObjectRequest)
        public ObjectMetadata getObject(final GetObjectRequest getObjectRequest, File destinationFile)
                
    • 아래 예제 코드에서는 bucketName과 key(파일명)만으로 객체를 가져왔다.

      @Service
      @RequiredArgsConstructor
      public class S3FileService {
      
         private final AmazonS3 amazonS3Client; // 생성자 주입방식, 별도 config파일에 AmazonS3ClientBean을 생성해 두었다.
      
         //property파일에서 bucket명을 불러오게끔 설정하였다.
         //private String bucket = "버킷명";과 같이 직접 설정해도 무관하다.
         @Value("${cloud.aws.s3.bucket}") 
         private String bucket;
         
         
         public void getFile(String fileName){
               try {
                   //S3로부터 파일 가져오기
                   S3Object o = s3.getObject(bucket, fileName);
                   //가져온 객체로부터 파일 내용 꺼내기
                   S3ObjectInputStream file = o.getObjectContent();
                   //서버에 File Stream 생성
                   FileOutputStream fos = new FileOutputStream(new File(fileName));
                   byte[] read_buf = new byte[1024];
                   int read_len = 0;
                   //파일 저장
                   while ((read_len = file.read(read_buf)) > 0) {
                       fos.write(read_buf, 0, read_len);
               }
               file.close();
               fos.close();
           } catch (AmazonServiceException e) {
               예외처리
           } catch (FileNotFoundException e) {
               예외처리
           } catch (IOException e) {
               예외처리
           }
         }
         
      }
    • 아마존 공식 예제 : github

  • 2.4 파일명 변경 또는 이동

    • copyObject를 이용하여 객체(파일)를 가져온다.

      public CopyObjectResult copyObject(String sourceBucketName, String sourceKey,
                                           String destinationBucketName, String destinationKey)
      public CopyObjectResult copyObject(CopyObjectRequest copyObjectRequest)
                
    • 아래 예제 코드에서는 bucketName과 key(파일명)만으로 객체를 이동(복사)시켰다.(기존 객체는 삭제되지 않음)

      @Service
      @RequiredArgsConstructor
      public class S3FileService {
      
         private final AmazonS3 amazonS3Client; // 생성자 주입방식, 별도 config파일에 AmazonS3ClientBean을 생성해 두었다.
      
         //property파일에서 bucket명을 불러오게끔 설정하였다.
         //private String bucket = "버킷명";과 같이 직접 설정해도 무관하다.
         @Value("${cloud.aws.s3.bucket}") 
         private String bucket;
         
         
         public void moveFile(String destBucket, String sourcefileName, String destFileName){
          try {
               amazonS3Client.copyObject(bucekt, sourceFileName, destBucket, destFileName);
           } catch (AmazonServiceException e) {
               에러처리
           }
         
      }
    • 아마존 공식 예제 : github

  • 2.5 파일삭제

    • deleteObject를 이용하여 객체(파일)를 삭제한다.

      public void deleteObject(String bucketName, String key)
       public void deleteObject(DeleteObjectRequest deleteObjectRequest)         
    • 아래 예제 코드에서는 bucketName과 key(파일명)만으로 객체를 삭제한다.

      @Service
      @RequiredArgsConstructor
      public class S3FileService {
      
         private final AmazonS3 amazonS3Client; // 생성자 주입방식, 별도 config파일에 AmazonS3ClientBean을 생성해 두었다.
      
         //property파일에서 bucket명을 불러오게끔 설정하였다.
         //private String bucket = "버킷명";과 같이 직접 설정해도 무관하다.
         @Value("${cloud.aws.s3.bucket}") 
         private String bucket;
         
         
         public void deleteFile(String fileName){
           try {
               amazonS3Client.deleteObject(bucket, fileName);
           } catch (AmazonServiceException e) {
               에러처리
           }
         
      }
  • 아마존 공식 예제 : github

3. 정리

  • 아마존에서는 S3 bucket 내 객체(파일)에 대한 업로드/다운로드/복사/삭제 API를 제공한다.
  • API는 각각 putObject, getObject, copyObject, deleteObject이다.

0개의 댓글