Spring boot 간단한 AWS S3 MultipartFile 업로드

2023. 12. 13. 20:06Springboot

0. 개요

       Spring boot의 프로젝트 내부의 폴더 안에 MultipartFile을 받지 않고 S3를 이용하여

       해당 MultipartFile을 받는 방법을 구현해보고자 합니다.

1. AWS S3를 이용하는 이유?

     1) 많은 사용자가 접속을 해도 감당할 수 있다.

     2) 저장 할 수 있는 파일의 수와 파일 용량이 5TB까지 저장이 가능하다.

     3) 액세스키와 비밀키를 통한 인증을 하기에 안전하다.

     4) 실수에 의한 데이터 손실이 발생하여도 자동으로 복원해준다. 

2. Requirement

  • Spring boot version 3.1.6 

   1. Stacks

      Springboot

  • Loombook
  • Spring Boot DevTools
  • Spring Web

3. AWS S3와 Spring boot 연동

     AWS S3 spring boot 연동하기 : 

https://velog.io/@gmlstjq123/AWS-S3%EB%A1%9C-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%97%85%EB%A1%9C%EB%93%9C%ED%95%98%EA%B8%B0

 

AWS S3와 스프링부트 연동하기

이전 포스팅을 읽지 않으신 분들은 반드시 이전 포스팅의 내용을 숙지하고 아래의 내용을 읽어주세요. >> 이전 포스팅 1. Access key와 Secret key 발급받기 S3를 스프링 부트에서 사용하려면 AWS 계정의

velog.io

     

     1) build.gradle

implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
// s3 연동

 

     2) application.yml

         ** cloud : aws : region : static : ap-northeast-2 >> aws 한국서버

         ** spring : servlet : multipart : max-file-size : multipartfile로 받는 최대 용량

cloud:
  aws:
    s3:
      bucket: ${your_bucket_name}
    region:
      static: ap-northeast-2
    credentials:
      accessKey: ${your_accessKey}
      secretKey: ${your_secretKey}

spring:
  servlet:
    multipart:
      max-file-size: 2MB

       

     3) S3Config.java

           ** 환경변수 지정 이후, accessKey, secretKey, region 지정

              https://pjh3797.tistory.com/30

 

Spring boot 환경 변수 설정

0. 개요 application.yml 또는 application.properties에 민감한 정보를 넣어야할 때, 이를 안 보이게 설정하기 1. application.yml spring: jpa: show-sql: true properties: hibernate: format_sql: true defer-datasource-initialization: true

pjh3797.tistory.com

           ** amazonS3Client() : amazon s3의 자신의 정보를 저장

package com.pjh.s3imageupload.Config;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class S3Config {

    @Value("${cloud.aws.credentials.accessKey}")
    private String accessKey;

    @Value("${cloud.aws.credentials.secretKey}")
    private String secretKey;

    @Value("${cloud.aws.region.static}")
    private String region;

    @Bean
    public AmazonS3 amazonS3Client(){
        // accessKey, secretKey를 Credentials에 저장

        BasicAWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey);

        /*  해당 BasicAWSCredenitals의 AllArgumentConstructor :
            public BasicAWSCredentials(String accessKey, String secretKey) {
            if (accessKey == null) {
                throw new IllegalArgumentException("Access key cannot be null.");
            }
            if (secretKey == null) {
                throw new IllegalArgumentException("Secret key cannot be null.");
            }

            this.accessKey = accessKey;
            this.secretKey = secretKey;
        }*/

        return AmazonS3ClientBuilder.standard()
                .withRegion(region)
                .withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
                .build();
    }
}

 

     4) S3FileUploadController.java

           ** uploadFile() : 파일을 업로드 하는 메서드 

package com.pjh.s3imageupload.Controller;

import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.ObjectMetadata;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.util.UUID;

@RestController
@RequestMapping("/upload")
public class S3FileUploadController {

    private final AmazonS3 amazonS3;

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

    public S3FileUploadController(AmazonS3 amazonS3){
        this.amazonS3 = amazonS3;
    }

    @PostMapping
    public ResponseEntity<?> uploadFile(@RequestParam("file")MultipartFile file){
        try {
            String fileOriginalName = file.getOriginalFilename();
            // 파일을 중복해서 올리면 s3에 올라가지 않음, 그러므로 uuid를 추가해서
            // 해당 이미지 파일을 엄청 낮은 확률이 아닌이상 중복을 제거
            UUID uuid = UUID.randomUUID();
            String uuidFileName = uuid+"_"+fileOriginalName;

            String url = "http://"+bucket+"/test"+fileOriginalName;
            ObjectMetadata metaData = new ObjectMetadata();
            metaData.setContentType(file.getContentType());
            metaData.setContentLength(file.getSize());
            amazonS3.putObject(bucket, uuidFileName, file.getInputStream(), metaData);

            return new ResponseEntity<>("msg : 파일 업로드 성공", HttpStatus.OK);
        }catch(Exception e){
            e.printStackTrace();
            return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}