AWS S3 사용하기

최준호·2022년 8월 8일
0

AWS

목록 보기
1/10
post-thumbnail

해당글은 java v1입니다. v2 버전은 AWS SDK v2 S3 적용하기 글을 참고해 주세요!

참고 aws 프리티어로 진행했습니다.
참고 AWS S3 공식문서
참고 AWS S3 for Java
참고 AWS S3 With Java 밸덩 문서
참고 AWS S3 SDK 2.0 for Java
참고 AWS S3 gradle 적용

📗 S3란?

S3란 AWS에서 제공하는 객체 스토리지 서비스(=저장소)이다. AWS 자체적으로 확장성과 데이터 가용성, 보안 및 성능을 제공하기 때문에 개발자가 따로 데이터를 저장할 서버를 만들거나 확장성과 보안성을 고려할 필요가 없이 AWS가 모두 관리해준다.

사용 용도로는 백업 데이터 저장소, 빅데이터 데이터 저장소, 웹의 이미지/동영상 저장소, 공용 저장소 등 다양하게 사용할 수 있다. 나는 그 중 웹의 이미지/동영상을 저장하는 공간으로 예제를 진행해보려고 한다.

S3 관리

  • S3 Lifecycle
    S3의 생명 주기 적책을 설정하여 데이터를 효율적으로 저장할 수 있다.
  • S3 Object Lock
    S3의 데이터를 고정된 시간(무기한까지 가능) 동안 삭제되어지거나 덮어쓰여지는 것을 방지한다.
  • S3 Replication
    데이터를 복제할 수 있다.
  • S3 Batch Operations
    대규모 데이터를 간단하게 관리할 수 있다.

👏 S3 버킷 생성

aws의 S3 페이지에 접근하면 다음과 같이 버킷 만들기를 누를 수 있다.

프리티어이기 때문에 괜히 건들지 않고 bucket 이름만 설정해준 뒤 버킷 만들기를 눌러 생성했다.

bucket은 저장되는 경로라고 생각하면 편할거 같다.

대시보드에서 bucket이 추가되어진 것을 확인할 수 있다.

👏 S3에 IAM 설정하기

IAM을 제품에서 검색하여 들어가서 사용자 추가를 눌러준다.

이름과 자격 증명 유형을 선택해준다.

S3용으로 사용할 것이기 때문에 정책을 기존 정책에서 검색하여 선택해준다.

태그는 지금 당장 필요하지 않으니 패스

만들기 버튼을 통해 생성해보자.

그럼 다음과 같이 액세스 키 ID비밀 액세스 키가 나오는데 둘다 따로 꼭 저장해두자. 그럼 이제 우리 계정에서 S3에 접근하는 액세스 키와 비밀 액세스 키는 해당 키들로 접근하면 된다.

📕 Project에 S3 추가하기

📄 종속성 추가

참고 AWS S3 gradle 적용

implementation platform('com.amazonaws:aws-java-sdk-bom:1.11.1000')
implementation 'com.amazonaws:aws-java-sdk-s3'

gradle은 다음과 같이 추가해주었다.

📄 설정 추가

#S3 설정
cloud:
  s3:
    bucket: bucket 이름
    access-id: access id
    secret-key: secret key

bucket 이름과 IAM에서 발급받은 각 키값들을 yml에 먼저 저장해두었다.

@Configuration
@RequiredArgsConstructor
public class S3ClientConfig {
    private final Environment env;

    @Bean
    public AmazonS3 amazoneS3(){
        return AmazonS3ClientBuilder
        .standard()
        .withCredentials(
            new AWSStaticCredentialsProvider(
                new BasicAWSCredentials(env.getProperty("cloud.s3.access-id"), env.getProperty("cloud.s3.secret-key"))
            )
        )
        .withRegion(Regions.AP_NORTHEAST_2)
        .build();
    }
}

그리고 하나의 S3Client만 사용하면 될거 같아서 싱글톤으로 사용하기 위해 Bean으로 등록해주었다.

📄 파일 업로드 예제

public interface S3Service {
    int putObject();
}
@Service
@RequiredArgsConstructor
public class S3ServiceImpl implements S3Service{
    private final AmazonS3 s3Client;
    private final Environment env;

    @Override
    public int putObject() {
        String fileName = "test.txt";
        String fullPath = "C:/project/";
        try{
            s3Client.putObject(
                env.getProperty("cloud.s3.bucket"), // bucket 이름
                String.format("juno/%s", fileName),     // s3 bucket에 저장될 파일의 경로
                new File(String.format(fullPath+"%s", fileName))    // 서버에서 파일을 가져올 경로
            );
        }catch(AmazonS3Exception ae){
            throw new IllegalArgumentException(ae.getMessage());
        }
        
        return 0;
    }
}

다음과 같이 service를 만들고 중요한 코드는 s3Client.putObject() 메서드이다. S3에 파일을 올려주는 코드로 사용한다. 또한 당연히 MultipartFile과 같은 매개변수를 사용해서 받아야하지만 우리는 테스트를 위한 것이니 컴퓨터 내 해당 경로에 test.txt 파일을 준비해두었다.

@RestController
@RequestMapping(value = "/s3")
@RequiredArgsConstructor
@Slf4j
public class S3Controller {
    private final S3Service s3Service;    
    
    @GetMapping("/put")
    public ResponseEntity<CommonResponse<TestData>> put(){
        log.info("S3 put start");
        int result = s3Service.putObject();
        CommonResponse<TestData> response = new CommonResponse<TestData>(result, new TestData("테스트 실행"));
        log.info("S3 put end");
        return ResponseEntity.status(HttpStatus.CREATED).body(response);
    }
}

Controller에서도 Post가 맞겠지만 예제니까 간단하게 GetMapping으로만 실행되게 설정해두었다.

그후 http://localhost:8080/s3/put url로 요청을 하면 다음과 같이 파일이 정상적으로 올라간 것을 확인할 수 있다.

파일을 local server에 write한 뒤 upload하는 방식이 아닌 바로 upload할 수 있다. AWS S3 Server에 저장하지 않고 upload하기 글을 참고하자!

📄 파일 조회 예제

public interface S3Service {
    ...
    void getObject(String path);
}
@Service
@RequiredArgsConstructor
@Slf4j
public class S3ServiceImpl implements S3Service{
    private final AmazonS3 s3Client;
    private final Environment env;

	...
    
    @Override
    public void getObject(String path) {
        String bucketName = env.getProperty("cloud.s3.bucket");
        try {
            S3Object s3Object = s3Client.getObject(bucketName, path);
            S3ObjectInputStream objectContent = s3Object.getObjectContent();
            FileCopyUtils.copy(objectContent, new FileOutputStream("C:/project/test2.txt"));
        } catch (AmazonS3Exception ae){
            throw new IllegalArgumentException(ae.getMessage());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
@RestController
@RequestMapping(value = "/s3")
@RequiredArgsConstructor
@Slf4j
public class S3Controller {
    private final S3Service s3Service;    
	
    ...
    
    @GetMapping("/get")
    public ResponseEntity<CommonResponse<TestData>> getObject(String path){
        log.info("S3 get start");
        s3Service.getObject(path);
        log.info("S3 get end");
        return ResponseEntity.ok(new CommonResponse<TestData>(0, new TestData("테스트 실행")));
    }
}

코드를 다음과 같이 작성하면 가져온 데이터를 컴퓨터에 저장시키도록 했다. 실행해보면

해당 폴더에 test2.txt가 추가되어질 것이다.

정상 실행되었고

파일도 정상적으로 새로 추가된 것을 확인할 수 있다.

📄 파일 삭제 예제

s3에 추가된 파일을 삭제해야할 수도 있다.

다음과 같이 파일이 존재한다.

public interface S3Service {
	
    ...
    
    void deleteObject(String path);
}
@Service
@RequiredArgsConstructor
@Slf4j
public class S3ServiceImpl implements S3Service{
    private final AmazonS3 s3Client;
    private final Environment env;

    ...

    @Override
    public void deleteObject(String path) {
        String bucketName = env.getProperty("cloud.s3.bucket");
        try{
            s3Client.deleteObject(bucketName, path);
        }catch(AmazonS3Exception ae){
            throw new IllegalArgumentException(ae.getMessage());
        }
    }
}
@RestController
@RequestMapping(value = "/s3")
@RequiredArgsConstructor
@Slf4j
public class S3Controller {
    private final S3Service s3Service;    
    
    ...
    
    @GetMapping("/delete")
    public ResponseEntity<CommonResponse<TestData>> deleteObject(String path){
        log.info("S3 delete start");
        s3Service.deleteObject(path);
        log.info("S3 delete end");
        return ResponseEntity.ok(new CommonResponse<TestData>(0, new TestData("테스트 실행")));
    }
}

다음과 같이 작성했을 때 실행해보자.

http://localhost:8080/s3/delete?path=juno/test.txt

나의 경우 위 url로 요청했다.

정상적으로 실행되면 다음과 같이 버킷 내 데이터가 사라진 것을 확인할 수 있다.

바로 안되면 새로고침을 해보자 생각보다 시간이 쪼금 걸린다.

profile
코딩을 깔끔하게 하고 싶어하는 초보 개발자 (편하게 글을 쓰기위해 반말체를 사용하고 있습니다! 양해 부탁드려요!) 현재 KakaoVX 근무중입니다!

0개의 댓글