반응형

기존에 로컬에 이미지를 저장하던 형식에서 클라우드인 aws 의 s3에 올리는 방법으로 변경했다.

s3는 aws에서 지원해주는 파일을 저장해주는 서비스인데 간단하게 네이버박스나 구글드라이브 정도를 생각하면 될것같다. 

 

s3 버켓 생성 

aws의 s3를 이용하려면 s3버켓을 생성해주어야한다.  

aws에 접속해서 s3를 검색하고 페이지에서 버킷 만들기를 선택한다.

여기서 버켓의 이름을 만들고 옵션은 모두 기본으로 설정해주었다. 

버켓의 이름은 유일해야하는 조건이 있어서 흔한 mybucket같은 이름은 지정할수 없었다.

 

버켓을 생성하고나면 버켓에 접근할 권한이 필요하다.

IAM으로 들어가서 s3에 접근할 사용자를 생성해준다.

 

사용자 이름을 설정하고 권한에 AmazonS3FullAccess를 설정해준다.

이후 해당 사용자로 들어가서 액세스키를 만들면 s3에 접근할 키 생성도 끝난다. 

액세스 키를 만들고나서는 추후에 다시 볼수없기때문에  파일로 저장하는걸 추천한다.

 

이제 스프링 부트에서 s3를 사용하기위한 설정을 해보자.

 

build.gradle 에 라이브러리 추가

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

 

 

application.yml

cloud:
  aws:
    s3:
      bucket: "버킷이름"
    stack.auto: false
    region.static: ap-northeast-2
    credentials:
      accessKey: "${S3_ACCESS_KEY}"
      secretKey: "${S3_SECRET_KEY}"

 

만약 버킷안에 폴더를 만들고 그안에 저장하고싶다면 버킷이름/폴더이름 으로 접근하면 된다.

 

S3Config

@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(){
        return (AmazonS3Client) AmazonS3ClientBuilder.standard()
                .withCredentials(
                        new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey,secretKey))
                )
                .withRegion(region)
                .build();
    }
}

 이렇게 S3Config까지 설정해주면 AmazonS3 클래스로 s3에 접근이 가능해진다.

 

S3UploadService

@Service
@RequiredArgsConstructor
public class S3UploadService {

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

    public void saveFile(MultipartFile multipartFile, String userName) throws IOException {
        String fileName = createFileName(multipartFile);
        ObjectMetadata metadata = getObjectMetadata(multipartFile);
        amazonS3.putObject(bucket, fileName, multipartFile.getInputStream(), metadata);
    }

    public void deleteFile(String fileName) {
        amazonS3.deleteObject(bucket, fileName);
    }

    public FileEntity updateFile(String oldFileName, MultipartFile newFile, String uploader) throws IOException {
        //기존이미지를 삭제
        deleteFile(oldFileName);
        //새로운 이미지를 추가
        return saveFile(newFile, uploader);
    }
    
    public String getPath(String fileName){
    	return amazonS3.getUrl(bucket, fileName).toString();
    }

    private static ObjectMetadata getObjectMetadata(MultipartFile multipartFile) {
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentLength(multipartFile.getSize());
        objectMetadata.setContentType(multipartFile.getContentType());
        return objectMetadata;
    }
}

 

파일저장

파일을 저장하기위해서는 버켓이름,파일의이름,파일의 인풋스트림,메타데이터가 필요하다.

메타데이터는 파일의 크기와 컨텐츠의 타입이 들어가게된다. 

putObject로 파일을 저장하게되면 설정한 이름으로 파일이잘 저장되는걸 확인할수있다. 

 

파일삭제

삭제는 간단하게 어떤 버켓의 어떤 파일을 삭제할지에 대한 정보만 있으면된다. 

deleteObject에 버켓과 파일의 이름을 파라미터로 넣으면 해당하는 파일이 삭제된다.

 

이미지에 접근

파일을 저장하면 해당 파일이나 이미지에 접근을 해야한다.

나의 경우는 이미지를 올리고 페이지에서 띄워줘야하는데 어떤 경로로 접근해야할지 알수없었다.

getUrl 을 사용하면 해당 파일에 접근할수있는경로를 리턴해준다. 

이 경로로 바로 접근하려고하면 에러 페이지를 띄워준다.

이를 해결하기 위해서는 cloudFront로 s3이미지를 배포해서 접근하는 방법이 필요하다고 한다.

cloudFront를 생성할때 domain을 클릭하면 내가만든 s3버켓이 나온다 해당 s3버켓을 선택하고 

보안보호만 비활성화로 선택해준다음 나머지 옵션은 모두기본으로 두었다. 그후에 배포를 생성해준다.

 

이후에도  access denied가 뜰텐데 s3bucket의 정책이 접근권한이 aws사용자에게만 열려있기때문이다. 

접근하려는 s3 bucket으로 다시 이동하여 권한으로 들어가면 버킷정책이있다. 여기에서 옵션을 지정해주면된다.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AddPerm",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::버켓이름/*"
        }
    ]
}

 

나는 해당 버켓의 모든 폴더에 접근가능하도록 열었는데 특정폴더만 열어놓을수도있다.

이렇게 하면 getUrl로 얻어지는 주소로 저장한 파일에 접근이 가능하다.

 

https://s3.ap-northeast-2.amazonaws.com/cokeholics-bucket/coctail_library_imgs/18153d0d-63be-4bec-834b-8a54f4566dfb_martini.jpg

 

반응형

+ Recent posts