티스토리 뷰

저번시간에 간단하게 내 컴퓨터에다가 이미지를 저장하고, 현재 진행하고 있는 프로젝트에 적용해보았다. 

이번포스팅에서는 s3에 이미지를 업로드하는 방법을 알아보겠다. 

 

 

내 로컬에다 이미지를 저장하면 안되는 이유

내 컴퓨터에다 이미지를 저장하면 안된다. 가장 큰 문제는 이미지경로를 조회하면 내 컴퓨터의 절대경로가 조회되기 때문에 해당경로를 가지고 이미지를 띄울 수 없다. 즉, 이미지는 저장되었지만 실제로 DB에 저장한 이미지경로는 그냥 문자열이나 똑같은 것이다. 두번째로는 용량이다. 나 혼자서 즐길 사이트를 만든다면 아무 문제 없겠지만, 사용자가 100명만 되도 아마 용량이 꽉 찰 것이다. 

 

 

S3

그래서 우리는 이미지를 자신의 컴퓨터 대신 가상의 공간에 넣어두고 관리할 것이다. 대표적으로 Amazon S3가 있다. S3는 데이터를 저장하고 보호, 관리하는 객체 스토리지 서비스다. 한마디로 자주 바뀌는 대용량 데이터를 아마존 S3가 다 보관하고 관리해준다는 소리다. 

 

 

버킷

s3에 데이터를 저장하고 관리하려면 버킷이라는 것을 생성해야 된다. 실질적으로 데이터는 버킷에 저장하고 관리된다. 

 

 

구현

그럼 구현을 해보자. 전체코드는 깃허브에 있으니 참고하면 될 것이다.

 

 

build.gradle

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

 

aws를 사용하기 위한 의존성을 추가해준다. 

 

 

AwsS3Config

@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();
    }
}

 

 

먼저 aws IAM에 자신의 계정을 만들어야 한다. 그리고 콘솔에 로그인을 하고 홈에 들어가서 IAM을 클릭한다. 

읽기가 귀찮으신분들은 사진의 빨간박스를 참고하면서 빠르게 넘어가도 상관없다. 

 

 

 

그럼 이 화면이 뜰 것이다. 액세스 관리에 사용자를 클릭한다. 

 

 

 

그리고 사용자 추가버튼을 누른다. 계정을 처음 만들었다면 생성된 사용자가 없는게 당연하니 밑 사진에 보이는 이미 생성되있는 사용자들은 무시해도 상관없다. 

 

 

 

사용자 추가 버튼을 클릭하면 다음과 같이 뜰 것이다. 사용자 이름은 아무거나 해도 상관없다. 액세스 키 유형을 클릭하고 다음버튼을 누른다.

 

 

 

그리고 기존 정책 직접 연결을 누르고 검색창에 s3라고 검색하면 빨간박스로 표시되어 있는 정책이 뜰것이다. 해당 정책을 체크하고 다음으로 넘어간다. 

 

 

 

태그는 설정을 하지 않아도 상관없다. 

 

 

 

마지막으로 사용자 만들기 버튼을 눌러주면 된다. 

 

 

 

그럼 아래화면이 나올 것이다. 

 

 

 

액세스 키 ID 값과 비밀 액세스 키는 중요하므로 어딘가에 소중히 보관해야 한다. 그럼 액세스 키 ID 값과 비밀 액세스 키를 application.yml에 추가한다. 

 

cloud:
  aws:
    credentials:
      access-key: 액세스 키 ID 값
      secret-key: 비밀 액세스 키

    region:
      static: ap-northeast-2 (=> 버킷리전(지역))
    s3:
      bucket: tistory-image-bucket (=> 버킷명)
    stack:
      auto: false

 

 

그럼 실질적으로 이미지파일을 저장하고 관리하는 버킷을 생성해보자.

다시 콘솔 홈으로 가서 이번엔 S3를 클릭한다. 

 

 

 

그리고 버킷만들기를 눌러준다. 아까와 마찬가지로 밑 사진에 이미 있는 버킷들은 무시해도 된다. 

 

 

 

먼저 버킷 이름을 정하면 된다. 아무 이름이나 해도 상관없다. 그리고 리전을 서울로 선택한다. 

 

 

 

그리고 밑으로 내리면 객체 소유권을 설정하는 곳이 있다. 여기서 아래와 같이 설정한다. 

 

 

 

밑으로 내리면 액세스 차단 설정이 있다. 이것도 아래와 같이 설정한다.

 

 

 

마지막으로 나머지는 건드리지 않고 넘어간다. 

 

 

 

그리고 버킷을 생성하면 아래와 같이 생성되는데 아직 퍼블릭이 안된 것을 볼 수 있다. 

 

 

 

자신이 만든 버킷이름을 클릭하고 권한으로 들어가서 버켓정책 편집버튼을 누른다.

 

 

 

편집버튼을 누르고 먼저 버킷 ARN을 복사한 후 정책 생성기를 클릭한다.

 

 

 

그럼 새창이 켜지면서 아래와 같은 화면이 나올 것이다. 

 

 

 

아래와 같이 설정한다. 

 

 

 

 

Actions에서 3 Action(s) Selected 선택사항이 없다고 당황하지 말자. 아래와 같이 이미지 업로드, 조회, 삭제를 위해 추가한다. 

 

 

 

그리고 ARN에 아까 복사해둔 ARN을 넣고 Add Statement버튼을 누르면 밑에 뭐가 더 추가된다. Generate Policy버튼을 누른다.

 

 

 

그럼 JSON 데이터가 뜨는데, 다 복사해준다. 

 

 

 

그리고 다시 돌아와서 정책에다 붙여준다. 여기서 중요한 점은 빨간 박스처럼 Resource 경로에 /*를 추가해주어야 한다. 

 

 

 

그럼 다 끝났다. 실제로 Spring boot에서 사진을 업로드하고 수정, 삭제하는 코드를 구현하기만 하면 된다.

 

 

FileService

@Service
@RequiredArgsConstructor
public class FileService {

    @Value("${cloud.aws.s3.bucket}")
    private String bucket;
    private final AmazonS3 amazonS3;
    private final AmazonS3Client amazonS3Client;

    public FileResponseDto saveFile(MultipartFile multipartFile) throws IOException {
        String imgPath = UUID.randomUUID() + "_" + multipartFile.getOriginalFilename();
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentLength(multipartFile.getSize());
        objectMetadata.setContentType(multipartFile.getContentType());
        amazonS3.putObject(new PutObjectRequest(bucket, imgPath, multipartFile.getInputStream(), objectMetadata)
                .withCannedAcl(CannedAccessControlList.PublicRead));

        return FileResponseDto.builder()
                .imgPath(imgPath)
                .imgUrl(String.valueOf(amazonS3Client.getUrl(bucket, imgPath)))
                .build();
    }

    public void deleteFile(String imgPath) {
        amazonS3.deleteObject(new DeleteObjectRequest(bucket, imgPath));
    }
}

 

만약 이미지를 로컬에 저장하는 법을 알고 있다면 어려운 코드가 아닐 것이다. InputStream을 추가하는 이유는 원래 MultipartFile은 로컬에 저장하기 위한 객체인데, s3에 저장하려고 하니까 로컬, s3에 두 개 다 저장되는 상황이 발생한다. 그래서 로컬에 이미지를 저장하지 않기 위해서 InputStream을 추가해준다. 

 

추가로 amazonS3Client.getUrl(bucket, imgPath)는 s3에 저장된 이미지 링크를 반환하는 메서드이다. 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday