[GCP] Spring Boot에서 GCS로 이미지 파일 저장

Donghoon Jeong·2024년 1월 26일
1
post-thumbnail

Cloud Storage Bucket 생성

1. Console로 이동

📌 Goole Cloud
https://cloud.google.com/?hl=ko

2. Cloud Storage - 버킷

3. 버킷 생성

만들기 버튼 클릭합니다.

버킷 이름 지정을 입력하고 위치는 Region asia-northeast3(서울) 로 변경 후, 이 버킷에 공개 액세스 방지 적용 체크 해제합니다.

버킷이 잘 생성된걸 확인할 수 있습니다.

4. 버킷 공개 액세스 적용

생성한 버킷을 선택 후, 권한으로 이동합니다.

Bucket의 모든 객체들을 모든 사용자들에게 공개된 상태로 변경하기 위해 다음과 같이 설정합니다.

5. 접근 권한 허용, key 파일 생성

5번 과정은 JSON key를 만들어, Spring Boot에서 JSON key를 이용해 storage에 접근하기 위한 설정입니다.

IAM 및 관리자 - 서비스 계정으로 이동합니다.

서비스 계정에 프로젝트에 대한 액세스 권한 부여에서 다음과 같이 역할을 추가해 줍니다.

추후에 Spring Boot 파일로 옮기기 위해 JSON 키 파일은 컴퓨터에 저장해둡니다.


Spring Boot 설정

build.gradle 의존성 추가

// Google Cloud Platform Storage(GCP Storage)
implementation group: 'org.springframework.cloud', name: 'spring-cloud-gcp-starter', version: '1.2.5.RELEASE'
implementation group: 'org.springframework.cloud', name: 'spring-cloud-gcp-storage', version: '1.2.5.RELEASE'

application.yml 설정

위에서 만든 JSON key file을 resources 폴더에 넣고, application.yml에 아래 코드를 추가해 줍니다.

spring:
    cloud:
    gcp:
      storage:
        credentials:
          location: ${LOCATION}
        project-id: ${PROJECT_ID}
        bucket: ${BUCKET}

application.yml에 JSON key 파일의 경로를 적어주면 스프링 부트는 키 파일의 내용을 바탕으로 stroage 변수에 자동으로 의존성을 부여합니다.

location은 JSON 키의 경로, project-id는 JSON key 파일에 있는 project-id, bucket은 Cloud Storage 콘솔 들어가시면 나오는 버킷 이름입니다.

이미지 업로드

Storage 내에서 이름이 동일한 파일은 덮어쓰기가 되거나 저장되지 않기 때문에 파일명을 중복되지 않게 만들어줘야 하기 때문에 UUID를 사용하여 URL을 저장해 보겠습니다.

이미지 업로드 코드

@Value("${spring.cloud.gcp.storage.credentials.location}")
private String keyFileName;

@Value("${spring.cloud.gcp.storage.bucket}")
private String bucketName;

public String exec(MultipartFile multipartFile) throws IOException {
	InputStream keyFile = ResourceUtils.getURL(keyFileName).openStream();

	String uuid = UUID.randomUUID().toString(); 
    String ext = multipartFile.getContentType(); 

	Storage storage = StorageOptions.newBuilder()
    			.setCredentials(GoogleCredentials.fromStream(keyFile))
                .build()
                .getService();

	String imgUrl = "https://storage.googleapis.com/" + bucketName + "/" + uuid;

    if (multipartFile.isEmpty()) {
    	imgUrl = null;
    } else {
            BlobInfo blobInfo = BlobInfo.newBuilder(bucketName, uuid)
            .setContentType(ext).build();

            Blob blob = storage.create(blobInfo, multipartFile.getInputStream());
    }
    
    return imgUrl;
}

전체코드를 나눠서 보겠습니다.

Storage storage = StorageOptions.newBuilder()
         .setCredentials(GoogleCredentials.fromStream(keyFile))
         .build()
         .getService();

이 코드가 구글 클라우드 스토리지 옵션과 제공된 인증 자격 증명을 사용하여 Storage 객체를 생성합니다.

String imgUrl = "https://storage.googleapis.com/" + bucketName + "/" + uuid;

if (multipartFile.isEmpty()) {
	imgUrl = null;
} else {
    BlobInfo blobInfo = BlobInfo.newBuilder(bucketName, uuid)
            .setContentType(ext).build();

    Blob blob = storage.create(blobInfo, multipartFile.getInputStream());
}

return imgUrl;

GCS 버킷 이름 및 생성된 고유 식별자를 사용하여 업로드된 이미지의 초기 URL을 구성합니다. 업로드된 파일이 비어있으면 imgUrl을 null로 설정합니다. 그렇지 않으면 파일을 storage.create 메소드를 사용하여 GCS에 업로드하는 로직으로 진행됩니다.

Controller

@Operation(summary = "Baby 등록")
@PostMapping("/baby")
public StateRes registerUser(@RequestPart BabyRegistReq babyRegistReq,
                                 @RequestPart MultipartFile multipartFile) throws IOException {
    return babyService.registerBaby(babyRegistReq, multipartFile);
}

Baby 등록 정보와 업로드된 파일을 받아 서비스 계층으로 전달하는 코드입니다. 여기서 주의 할 점은 매개변수를 받을 때, @RequestBody가 아닌 @RequestPart을 사용한다는 점입니다.


테스트

Postman을 활용해서 다음과 같이 요청을 보냈을 때, 오류 없이 응답이 오는 것을 확인할 수 있습니다.

DTO의 Content-Typeapplication/json으로 변경해 주셔야 합니다.

또한 사진이 버킷에도 잘 들어간 것과 해당 url로 접속 시 사진이 잘 나오는 것을 확인할 수 있습니다.

profile
정신 🍒 !

0개의 댓글