본문 바로가기
토이프로젝트 - 백오피스

23.07.21

by J1-H00N 2023. 7. 21.

s3를 적용하기 위해 글들을 찾아보던 와중 버킷명과 접근키 등의 정보를 yml에 담아야 한다고 해서 해당 파일을 찾아보았는데, 글들이 소개하는 위치에는 properties밖에 없어서 임의로 만들어서 정보를 담거나 하는 등 여러 방법을 사용해도 인식을 못 해 알아보니, 보통 properties나 yml 하나만 사용하고 같이 사용할 경우 오버라이딩 순서에 따라 결과가 달라질 수있어 properties에 정보를 담고 yml 파일은 삭제하기로 했다.

 

@Variable로 properties에 있는 변수들을 인식하지 못하는 일이 있었는데, lombok에 있는 에너테이션을 사용해서 생긴 문제였다. 아래를 import하니 해결됐다.

import org.springframework.beans.factory.annotation.Value;

 

이제 postcontroller를 만들어 제대로 AWS에 파일이 업로드 되는지 확인하고, get으로 가져와지는지 확인만 하면 된다.

 

이미지를 업로드하기 위해 만든 메서드인데 블로그에서 긁어 온 코드라 내용을 제대로 숙지하진 못했다. 시간이 날 때 제대로 읽어봐야겠다.

import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.PutObjectRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Optional;

@Slf4j
@RequiredArgsConstructor    // final 멤버변수가 있으면 생성자 항목에 포함시킴
@Component
@Service
public class S3Uploader {

    private final AmazonS3Client amazonS3Client;

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

    // MultipartFile을 전달받아 File로 전환한 후 S3에 업로드
    public String upload(MultipartFile multipartFile, String dirName) throws IOException {
        File uploadFile = convert(multipartFile)
                .orElseThrow(() -> new IllegalArgumentException("MultipartFile -> File 전환 실패"));
        return upload(uploadFile, dirName);
    }

    private String upload(File uploadFile, String dirName) {
        String fileName = dirName + "/" + uploadFile.getName();
        String uploadImageUrl = putS3(uploadFile, fileName);

        removeNewFile(uploadFile);  // 로컬에 생성된 File 삭제 (MultipartFile -> File 전환 하며 로컬에 파일 생성됨)

        return uploadImageUrl;      // 업로드된 파일의 S3 URL 주소 반환
    }

    private String putS3(File uploadFile, String fileName) {
        amazonS3Client.putObject(
                new PutObjectRequest(bucket, fileName, uploadFile)
                        .withCannedAcl(CannedAccessControlList.PublicRead)	// PublicRead 권한으로 업로드 됨
        );
        return amazonS3Client.getUrl(bucket, fileName).toString();
    }

    private void removeNewFile(File targetFile) {
        if(targetFile.delete()) {
            log.info("파일이 삭제되었습니다.");
        }else {
            log.info("파일이 삭제되지 못했습니다.");
        }
    }

    private Optional<File> convert(MultipartFile file) throws  IOException {
        File convertFile = new File(file.getOriginalFilename());
        if(convertFile.createNewFile()) {
            try (FileOutputStream fos = new FileOutputStream(convertFile)) {
                fos.write(file.getBytes());
            }
            return Optional.of(convertFile);
        }
        return Optional.empty();
    }

}

 

컨트롤러에서 dto와 함께 image를 받을 때 계속해서 생긴 오류가 몇 개 있는데, 

1. java.lang.IllegalArgumentException: MultipartFile -> File 전환 실패

2.com.amazonaws.services.s3.model.AmazonS3Exception: The bucket does not allow ACLs (Service: Amazon S3; Status Code: 400; Error Code: AccessControlListNotSupported; Request ID: G2V1HKAPTZW5JRVP; S3 Extended Request ID: T9MANpF8l8yQ6Eso5Zmf1s9X+HYkgfclEQmLbc7U+izon5Ahg6k/N0YCLJSE0NXmlNiTgCzQk/EreAtYo3i4ZQ==; Proxy: null)

3. 파일 업로드 실패

 

1번은 어째서인지 png가 아닌 jpg형식의 이미지만 업로드가 됐다. 이거는 이미지 형식을 jpg만 받는 것으로 임시로 해결했으나 정확한 이유는 아직도 알지 못한다.

2번은 버킷 > 권한 > 객체 소유권 > ACL 활성화됨을 통해 해결했다.

3번은 dto는 body로, image는 param으로 받는 것이 안돼서 아래와 같이 수정하니 해결됐다.

editProfile(@AuthenticationPrincipal UserDetailsImpl userDetails, @RequestPart ProfileRequestDto requestDto, @RequestPart MultipartFile image)

 

'토이프로젝트 - 백오피스' 카테고리의 다른 글

23.07.24  (0) 2023.07.24
23.07.20  (0) 2023.07.20
23.07.19  (0) 2023.07.19
23.07.18  (0) 2023.07.18
23.07.17  (0) 2023.07.17