AWS S3๋ž€??

0taetaeยท2025๋…„ 1์›” 24์ผ
post-thumbnail

ํ”„๋กœํ•„ ์‚ฌ์ง„, ๋ ˆ์‹œํ”ผ ์‚ฌ์ง„, SNS ํ”ผ๋“œ ์‚ฌ์ง„ ๋“ฑ์„ ์—…๋กœ๋“œ ํ•˜๊ธฐ ์œ„ํ•ด์„œ AWS S3๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•œ๋‹ค.

๐Ÿ“™AWS S3๋ž€?

  • Amazon Web Service Simple Storage Service์˜ ์•ฝ์ž
  • ํŒŒ์ผ, ๋ฐ์ดํ„ฐ ๋ฐ ๋‹ค์–‘ํ•œ ์œ ํ˜•์˜ ๋ฏธ๋””์–ด ๋“ฑ์„ ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋˜๋Š” ์›น ๊ธฐ๋ฐ˜ ์Šคํ† ๋ฆฌ์ง€ ์‹œ์Šคํ…œ์ด๋‹ค.

โœ๏ธS3์˜ ํŠน์ง•

  • ๋ฌด์ œํ•œ ์Šคํ† ๋ฆฌ์ง€
  • ๋†’์€ ๋‚ด๊ตฌ์„ฑ๊ณผ ๊ฐ€์šฉ์„ฑ
  • ๋ณด์•ˆ : SSL ์•”ํ˜ธํ™”๋œ ์—”๋“œํฌ์ธํŠธ๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ „์†ก
    ๐Ÿ’กSSL์ด๋ž€?
    ์ธํ„ฐ๋„ท ์ƒ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ „์†กํ•˜๊ธฐ ์œ„ํ•œ ๋ณด์•ˆ ํ”„๋กœํ† ์ฝœ
    ์ฆ‰, ์›น ๋ธŒ๋ผ์šฐ์ €์™€ ์›น ์„œ๋ฒ„ ๊ฐ„์˜ ํ†ต์‹ ์„ ์•”ํ˜ธํ™”ํ•˜์—ฌ ๊ฐœ์ธ์ •๋ณด์™€ ๊ฐ™์€ ๋ฏผ๊ฐํ•œ ์ •๋ณด๋ฅผ ๋ณดํ˜ธํ•œ๋‹ค.
  • ๋‹ค์–‘ํ•œ ์Šคํ† ๋ฆฌ์ง€ ํด๋ž˜์Šค๋ฅผ ์ œ๊ณตํ•˜์—ฌ ๋ฐ์ดํ„ฐ ์•ก์„ธ์Šค ํŒจํ„ด์— ๋”ฐ๋ผ ์ตœ์ ํ™”๋œ ๋น„์šฉ์œผ๋กœ ์ €์žฅ ๊ฐ€๋Šฅ

โœ๏ธS3์˜ ๊ตฌ์กฐ

  1. ๋ฒ„ํ‚ท(Bucket)
    • ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•˜๋Š” ์ตœ์ƒ์œ„ ๋””๋ ‰ํ† ๋ฆฌ
    • ๊ฐ ๋ฒ„ํ‚ท์€ ๊ณ ์œ ํ•œ ์ด๋ฆ„์„ ๊ฐ€์ง€๋ฉฐ, ํŠน์ • AWS ๋ฆฌ์ „์— ์ƒ์„ฑ๋œ๋‹ค.
  2. ๊ฐ์ฒด(Object)
    • ์‹ค์ œ ์ €์žฅ๋˜๋Š” ๋ฐ์ดํ„ฐ ๋‹จ์œ„
    • ๊ฐ ๊ฐ์ฒด๋Š” ํ‚ค(ํŒŒ์ผ๋ช…), ๊ฐ’(๋ฐ์ดํ„ฐ), ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๋“ฑ์œผ๋กœ ๊ตฌ์„ฑ
    • ๊ฐ์ฒด๋งˆ๋‹ค ์ ‘๊ทผ ๊ถŒํ•œ ์„ค์ •์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
    • ์ €์žฅ ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด์˜ ๊ฐœ์ˆ˜๋Š” ๋ฌด์ œํ•œ์ด๋‹ค.

๐Ÿ“™AWS S3๋ฅผ ์ด์šฉํ•œ ํŒŒ์ผ ์—…๋กœ๋“œ

โœ๏ธ์„ค์ •

  1. Spring Cloud AWS์˜ ๋ฒ„์ „ ์„ค์ •

    <properties>
    			<spring-cloud-aws.version>3.1.1</spring-cloud-aws.version>
    		</properties>
  2. Spring Cloud AWS์˜ ์˜์กด์„ฑ ๊ด€๋ฆฌ

    <dependencyManagement>
    			<dependencies>
    				<dependency>
    					<groupId>io.awspring.cloud</groupId>
    					<artifactId>spring-cloud-aws-dependencies</artifactId>
    					<version>${spring-cloud-aws.version}</version>
    					<type>pom</type>
    					<scope>import</scope>
    				</dependency>
    			</dependencies>
    		</dependencyManagement>
  3. Amazon S3 SDK ์˜์กด์„ฑ ์ถ”๊ฐ€

    <dependencies>
        <dependency>
    				<groupId>software.amazon.awssdk</groupId>
    				<artifactId>s3</artifactId>
    				<version>2.21.46</version>
    		   </dependency>
    		</dependencies>
  4. AWS S3 ์„œ๋น„์Šค ์„ค์ •

    cloud.aws.s3.bucket=<S3 ๋ฒ„ํ‚ท ์ด๋ฆ„> 
    cloud.aws.region.auto=false // AWS ๋ฆฌ์ „์„ ์ž๋™์œผ๋กœ ๊ฐ์ง€ํ•˜๋Š” ๊ธฐ๋Šฅ ๋น„ํ™œ์„ฑํ™” 
    cloud.aws.stack.auto=false // AWS CloudFormation ์Šคํƒ์—์„œ ๋ฆฌ์†Œ์Šค๋ฅผ ์ž๋™์œผ๋กœ ๊ฐ์ง€ํ•˜๋Š” ๊ธฐ๋Šฅ ๋น„ํ™œ์„ฑํ™” 
    cloud.aws.region.static=ap-northeast-2 // ์‚ฌ์šฉํ•  AWS ๋ฆฌ์ „์„ ์„ค์ • (ap-northeast-2 : ์„œ์šธ ๋ฆฌ์ „)
    cloud.aws.credentials.access-key= // AWS ๊ณ„์ •์˜ access key ์„ค์ •
    cloud.aws.credentials.secret-key= // AWS ๊ณ„์ •์˜ secret key ์„ค์ • 
    spring.servlet.multipart.enabled=true // Spring์˜ Multipart ํŒŒ์ผ ์—…๋กœ๋“œ ๊ธฐ๋Šฅ ํ™œ์„ฑํ™” 

โœ๏ธS3Config

  • Amazon S3 ํด๋ผ์ด์–ธํŠธ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ์„ค์ •
@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 S3Client s3Client(){
        AwsBasicCredentials awsBasicCredentials = AwsBasicCredentials.create(accessKey, secretKey); // AWS ์ž๊ฒฉ ์ฆ๋ช… ์ƒ์„ฑ 

        return S3Client.builder() // S3 ํด๋ผ์ด์–ธํŠธ ๊ตฌ์„ฑ 
                .credentialsProvider(StaticCredentialsProvider.create(awsBasicCredentials)) // ์ƒ์„ฑ๋œ ์ž๊ฒฉ ์ฆ๋ช… ์ œ๊ณต
                .region(Region.of(region)) // ์„ค์ •๋œ AWS ๋ฆฌ์ „์„ ์ง€์ • 
                .build(); // S3Client ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
    }
}

โœ๏ธS3Service

@Service
public class S3Service {

    private final S3Client s3Client;

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

    @Autowired
    public S3Service(S3Client s3Client) {
        this.s3Client = s3Client;
    }

    // MultipartFile์„ ๋ฐ›์•„ S3์— ์—…๋กœ๋“œํ•˜๊ณ , ์—…๋กœ๋“œ๋œ ํŒŒ์ผ์˜ URL์„ ๋ฐ˜ํ™˜
    public String uploadFile(MultipartFile file) {
        String fileName = generateFileName(file);
        try {
            PutObjectRequest putObjectRequest = PutObjectRequest.builder()
                    .bucket(bucketName)
                    .key(fileName)
                    .acl("public-read") // ํŒŒ์ผ์„ ๊ณต๊ฐœ์ ์œผ๋กœ ์ฝ์„ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
                    .contentType(file.getContentType()) // ์—…๋กœ๋“œํ•˜๋Š” ํŒŒ์ผ์˜ ์‹ค์ œ MIME ํƒ€์ž…์„ ์„ค์ •
                    .contentDisposition("inline") // ๋ธŒ๋ผ์šฐ์ €์—์„œ ํŒŒ์ผ์„ ์ง์ ‘ ํ‘œ์‹œ
                    .build();

            s3Client.putObject(putObjectRequest, RequestBody.fromInputStream(file.getInputStream(), file.getSize()));

            return String.format("https://%s.s3.amazonaws.com/%s", bucketName, fileName);
        } catch (IOException e) {
            throw new RuntimeException("ํŒŒ์ผ ์—…๋กœ๋“œ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค", e);
        }
    }

    // ํŒŒ์ผ ์ด๋ฆ„ ์ƒ์„ฑ
    private String generateFileName(MultipartFile file) {
        return UUID.randomUUID().toString() + "-" + file.getOriginalFilename();
    }
}

์ฐธ๊ณ  ์ž๋ฃŒ
https://gaeggu.tistory.com/33
https://bigco-growth-diary.tistory.com/43

0๊ฐœ์˜ ๋Œ“๊ธ€