멋사 Backend Plus 39일차 🦁

μ‹ μž¬μ›Β·2023λ…„ 12μ›” 26일

μ˜€λŠ˜μ€ μ˜€μ „ μ˜€ν›„ λ™μ•ˆ AWS의 S3 버킷에 이미지λ₯Ό λ“±λ‘ν•˜λŠ” κΈ°λŠ₯을 κ΅¬ν˜„μ„ ν•˜μ˜€κ³ ,
Spring Bootμ—μ„œμ˜ AWS S3 μ„€μ •κ³Ό λ‘œμ§μ— λŒ€ν•œ 정리λ₯Ό 해보렀고 ν•©λ‹ˆλ‹€.

AWS S3 κ°œλ… 및 ν•„μš”μ„±

AWS S3λŠ” κ°„λ‹¨νžˆ μƒκ°ν•˜μ—¬ ν™•μž₯ κ°€λŠ₯ν•œ ν΄λΌμš°λ“œ μ €μž₯μ†Œ 라고 생각 ν•˜λ©΄ 될 것 κ°™λ‹€.
(넀이버 ν΄λΌμš°λ“œ, I ν΄λΌμš°λ“œ λ“±)
νŒ€ ν”„λ‘œμ νŠΈλ₯Ό ν•˜λ©°, 이미지 (파일)을 μ„œλ²„λ₯Ό 톡해 κ΄€λ¦¬μ˜ ν•„μš”μ„±μ„ 느끼게 λ˜μ–΄, AWS S3의 버킷을 ν™œμš©ν•˜μ—¬ μ €μž₯μ†Œλ‘œ ν™œμš© ν•˜λ €κ³  ν•œλ‹€.

μ˜€μ „

1. AWS S3 λ§Œλ“€κΈ°

AWS의 둜그인 ν›„ S3λ₯Ό 검색 ν•˜κ³ , 접속 ν•©λ‹ˆλ‹€.

버킷 λ§Œλ“€κΈ° λ²„νŠΌμ„ 눌러 AWS S3의 λŒ€ν•œ 버킷 (μ»¨ν…Œμ΄λ„ˆ)λ₯Ό λ§Œλ“€μ–΄ μ€λ‹ˆλ‹€.

λ²„ν‚·μ˜ λŒ€ν•œ 이름을 μ§€μ–΄μ£ΌλŠ” 것이며, λ²„ν‚·μ˜ 이름은 λ‹€λ₯Έ μ‚¬λžŒλ“€μ˜ 버킷 이름 κΉŒμ§€ ν†΅ν‹€μ–΄μ„œ κ³ μœ ν•œ 이름 이어야 ν•©λ‹ˆλ‹€.

λͺ¨λ“  퍼블릭 μ•‘μ„ΈμŠ€λ₯Ό μ°¨λ‹¨ν•˜κ²Œ 되면 인터넷 μ‚¬μš©μžλ“€μ—κ²Œ κ³΅κ°œλ˜μ§€ μ•ŠμœΌλ©°, νŠΉλ³„ν•œ 경우일 λ•Œλ§Œ, 체크λ₯Ό ν•΄μ œ ν•œλ‹€κ³  ν•œλ‹€.

λ²„ν‚·μ˜ 버전 κ΄€λ¦¬λŠ” λΉ„ν™œμ„±ν™”λ₯Ό 체크 ν•©λ‹ˆλ‹€.

κΈ°λ³Έ μ„€μ •λŒ€λ‘œ 체크 ν•˜κ³  λ‚˜μ„œ 버킷을 생성 ν•©λ‹ˆλ‹€.

2. μ‚¬μš©μž 생성

μ‚¬μš©μžλ₯Ό 생성 ν•΄μ•Ό ν•˜λŠ” μ΄μœ λŠ” S3에 μ ‘κ·Όν•˜κΈ° μœ„ν•΄ μ ‘κ·Ό κΆŒν•œμ„ μ£Όκ³ , μ—‘μ„ΈμŠ€ ν‚€ 와 μ‹œν¬λ¦Ώ μ—‘μ„ΈμŠ€λ₯Ό μƒμ„±ν•˜μ—¬ μ ‘κ·Όν•˜κΈ° μœ„ν•΄μ„œ μž…λ‹ˆλ‹€.

I AM 을 κ²€μƒ‰ν•˜μ—¬ 접속 ν•©λ‹ˆλ‹€.

μ‚¬μš©μž 생성 λ²„νŠΌμ„ 눌러 μ§„ν–‰ ν•©λ‹ˆλ‹€.

μ‚¬μš©μž 이름을 μž‘μ„±ν•˜μ—¬ λ‹€μŒ λ²„νŠΌμ„ 클릭 ν•©λ‹ˆλ‹€.

직접 μ •μ±… μ—°κ²° 선택 ν›„, S3 κΆŒν•œ 정책을 μ„ νƒν•˜κ³  λ‹€μŒμ„ 클릭 ν•˜κ²Œ 되면,
μ‚¬μš©μžκ°€ 생성 λ©λ‹ˆλ‹€.

3. μ•‘μ„ΈμŠ€ ν‚€ 생성

μ™ΈλΆ€μ—μ„œ 접속 ν•˜κΈ° μœ„ν•œ μ‚¬μš©μžμ˜ μ•‘μ„ΈμŠ€ ν‚€λ₯Ό 생성 ν•΄μ•Ό ν•©λ‹ˆλ‹€.

μ‚¬μš©μž 탭을 클릭 ν›„, μƒμ„±ν–ˆλ˜ μ‚¬μš©μžλ₯Ό 클릭 ν•©λ‹ˆλ‹€.

λ³΄μ•ˆ 자격 증λͺ… νƒ­ 클릭후, μ•‘μ„ΈμŠ€ ν‚€ λ§Œλ“€κΈ°λ₯Ό 클릭 ν•©λ‹ˆλ‹€.

μ•„λ¬΄κ±°λ‚˜ ν΄λ¦­ν•œ ν›„ λ‹€μŒ λ²„νŠΌμ„ 클릭 ν•©λ‹ˆλ‹€.

μ•‘μ„ΈμŠ€ 킀와 λΉ„λ°€ μ•‘μ„ΈμŠ€ ν‚€κ°€ 생성 λ˜λŠ” 것을 λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.
(μ•ˆλ‚΄λ¬Έκ΅¬λ‘œ 생성 ν™”λ©΄μ—μ„œλ§Œ ν‚€λ₯Ό 확인 ν•  수 있으며, .CSV 파일둜 λ°›μ•„ λ‘λŠ” 것을 ꢌμž₯ν•œλ‹€. λ”°λΌν•˜μž.)

4.μƒμ„±ν–ˆλ˜ S3에 κΆŒν•œ μ •μ±… μ„€μ •

  • μƒμ„±ν–ˆλ˜ S3에 κΆŒν•œμ„ μ„€μ •ν•˜μ—¬ μ•„λž˜μ˜ Json ν˜•μ‹μ— 맞좰 μž‘μ„±ν•˜κ³  μ €μž₯ν•˜λ©΄ λœλ‹€.
{
    "Version": "2012-10-17",
    "Id": "Policy1702863852313",
    "Statement": [
        {
            "Sid": "Stmt1702863805510",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::λ§Œλ“€μ—ˆλ˜ 버킷 이름/*"
        }
    ]
}

μ˜€ν›„

5. Spring Bootμ—μ„œ S3 적용

1) build.gradle에 μ˜μ‘΄μ„± μΆ”κ°€

dependencies {
	// μΆ”κ°€ μ˜μ‘΄μ„±...
    implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
}

2) application.yml에 μ„€μ • μΆ”κ°€
ap-northeast-2 : μ„€μ • 지역이 μ„œμšΈμ΄λΌλŠ” 뜻

λ°œκΈ‰ 받은 μ•‘μ„ΈμŠ€ ν‚€, λΉ„λ°€ μ•‘μ„ΈμŠ€ 킀에 λŒ€ν•΄μ„œλŠ” κΉƒν—ˆλΈŒμ— μ˜¬λΌκ°€μ§€ μ•Šκ²Œ
.gitIgnore μ„€μ • 등을 톡해 κΉƒν—ˆλΈŒμ— μ˜¬λΌκ°€μ§€ μ•Šκ²Œ 쑰심 ν•΄μ•Ό ν•œλ‹€.

cloud:
  aws:
    s3:
      bucket: <버킷 이름>
      url: https://<버킷 이름>.s3.ap-northeast-2.amazonaws.com/
    stack.auto: false
    region.static: ap-northeast-2
    credentials:
      accessKey: <λ°œκΈ‰ 받은 μ•‘μ„ΈμŠ€ ν‚€>
      secretKey: <λ°œκΈ‰ 받은 λΉ„λ°€ μ•‘μ„ΈμŠ€ ν‚€>

3) Config μ„€μ •

yml νŒŒμΌμ—μ„œ μ„€μ •ν•œ 값을 가져와 μ‚¬μš©ν•˜λŠ” μ„€μ • μ½”λ“œ μž…λ‹ˆλ‹€.

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

controller μ½”λ“œ

@RestController
@RequestMapping("/upload")
@RequiredArgsConstructor

public class FileUploadController {
   private final FileUploadService fileUploadService;
   
   @PostMapping
   public ResponseEntity<String> uploadFile(@ModelAttribute(
   								name = "images") MultipartFile images) {
   		fileUploadService.createFile(images);
        
        return ResponseEntity.ok("파일 μ—…λ‘œλ“œ 성곡")
      }
   }
}

service μ½”λ“œ

@Service
@RequiredArgsConstructor
public class ImageService {
    private final AmazonS3Client amazonS3Client;

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

    @Value("${cloud.aws.s3.url}")
    private String bucketUrl;
    
 	@Transactional
    public void uploadImage(MultipartFile file) throws IOException {
        String imageLocation = bucketUrl;
        String imageName = file.getOriginalFilename();
        String requestTypeSimpleName = "product" + "/";

        String imagePath = imageLocation + requestTypeSimpleName + imageName;

        String fileName = requestTypeSimpleName + file.getOriginalFilename();

        createS3Bucket(fileName, file);
    }

    private void createS3Bucket(String fileName, MultipartFile image) throws IOException {
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentType(image.getContentType());
        metadata.setContentLength(image.getSize());
        amazonS3Client.putObject(bucket, fileName, image.getInputStream(), metadata);
    }
    
}

AWS S3 버킷에 product νŒ¨ν‚€μ§€λ‘œ 잘 μ €μž₯ λ˜λŠ” 것을 확인 ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

마무리

κ°„λ‹¨ν•˜κ²Œ AWS S3 버킷에 이미지λ₯Ό μ—…λ‘œλ“œ ν• μˆ˜ μžˆλŠ” 방법에 λŒ€ν•΄ 정리 ν•΄λ³΄μ•˜μŠ΅λ‹ˆλ‹€.
λ§ˆμ§€λ§‰ λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ— λŒ€ν•΄μ„œλŠ” μ‚¬μš©μžμ— 맞게 μ»€μŠ€ν…€ν•΄μ„œ μ‚¬μš©ν•˜λ©΄ 쒋을 것 κ°™μŠ΅λ‹ˆλ‹€. (κΈ°λŠ₯ 뢄리 λ“±)

0개의 λŒ“κΈ€