[SPRING] S3에 이미지 업로드

CHOI IN HO·2024년 1월 22일
0

SPRING

목록 보기
38/45

📌 서론

spring으로 이미지 업로드를 구현하던 도중 로컬 디렉토리가 아닌 S3에 이미지를 저장하게 할 수 있도록 만들고자 했다.
출처 : https://chb2005.tistory.com/200

📌 AWS S3란?

  • AWS Simple Storage Service의 줄임말로 파일 서버의 역할을 하는 서비스
  • 프로젝트 개발 중 파일을 저장하고 불러오는 작업이 필요한 경우에 프로젝트 내부 폴더에 저장할 수 있지만, AWS S3를 사용하여 파일을 관리할 수도 있음

장점

  • 무제한 용량 (하나의 파일에 대한 용량 제한은 있지만, 전체 용량은 무제한)
  • 파일 저장에 최적화 (개발자가 따로 용량을 추가하거나 성능을 높이는 작업을 하지 않아도 됨)
  • 99.999%라는 높은 내구도 (파일이 유실될 가능성이 낮음)
  • 이 외에도 저렴한 비용, 높은 객체 가용성, 뛰어난 보안성 등의 장점이 있음

📌 1.AWS S3 생성

  • 객체(Object) : 파일과 파일정보로 구성된 저장단위로 파일이라 생각하면 됨
  • 버킷(Bucket) : 저장된 객체에 대한 컨테이너
  • 버킷은 최대 100개 생성 가능하며, 버킷에 저장할 수 있는 객체수는 제한이 없음

📌 1.1.AWS bucket 생성

  1. AWS Console 접속 후 S3 서비스 선택
  2. 버킷 만들기 클릭
  3. 원하는 버킷 이름 입력
  4. AWS 리전 선택 (아시아 태평양(서울) ap-northeast-2 )
  5. 객체 소유권 선택 (ACL 비활성화)
  6. '모든 퍼블릭 액세스 차단' 해제
  7. 나머지는 Default

📌 1.2.사용자 생성

  1. AWS Console 접속 후 IAM 서비스 선택
  2. 액세스 관리 -> 사용자 -> 사용자 추가
  3. 원하는 이름 입력 후 다음
  4. 직접 정책 연결 -> AmazonS3FullAccess 선택 후 다음
  5. 사용자 생성

📌 1.3.엑세스 키 생성

  1. 방금 생성한 사용자 선택 후 보안 자격 증명 탭 클릭
  2. 액세스 키 만들기 클릭
  3. 기타 선택 후 다음
  4. 원하는 설명 태그 입력 후 액세스 키 만들기
  5. 액세스 키를 만들면 아래와 같이 액세스 키와 비밀 액세스 키를 확인할 수 있는데, 이 값들을 저장후 완료

📌 1.4.버킷 정책 변경

  1. AWS Console에서 생성한 버킷으로 이동
  2. 권한 -> 버킷 정책 -> 편집
  3. 정책이 비어있으면 '+ 새 문 추가' 클릭
  4. 정책 내용을 아래와 같이 변경

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Statement1",
"Principal": "",
"Effect": "Allow",
"Action": "s3:
",
"Resource": "arn:aws:s3:::<버킷 이름>/*"
}
]
}

📌 2.spring 연동

📌 2.1.라이브러리 추가(build.gradle)

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

📌 2.2.application.yml에 아래 내용 추가

📌 2.3.S3Config.java 생성

📌 2.4.파일 업로드 구현

@Service
@RequiredArgsConstructor
public class PropertyImageService {

private final PropertyRepository propertyRepository;
private final PropertyImageRepository propertyImageRepository;

private final AmazonS3 amazonS3;


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


public void uploadImage(Long propertyID, PropertyImageDto propertyImageDto) {
    Property property = propertyRepository.findById(propertyID)
            .orElseThrow(() -> new ApplicationException(ErrorCode.Property_NOT_FOUND, "없음"));

    List<PropertyImage> propertyImages = propertyImageDto.getImages().stream()
            .map(image -> new PropertyImage(property, saveImage(image)))
            .collect(Collectors.toList());

    propertyImageRepository.saveAll(propertyImages);
}

private String saveImage(MultipartFile image) {

    String fileName = "image_" + UUID.randomUUID() + "." + getFileExtension(image.getOriginalFilename());

    ObjectMetadata metadata = new ObjectMetadata();
    metadata.setContentLength(image.getSize());
    metadata.setContentType(image.getContentType());
    try {
        amazonS3.putObject(bucket, fileName, image.getInputStream(),metadata);
    } catch (IOException e) {
        e.printStackTrace();
        throw new ApplicationException(ErrorCode.IMAGE_SAVE_ERROR, "이미지 저장 실패");
    }

    return amazonS3.getUrl(bucket,fileName).toString();
}

private String getFileExtension(String filename) {
    return filename.substring(filename.lastIndexOf(".")+1);
}

}

profile
개발자기 되기 위해선 무엇이든!

0개의 댓글