AWS, SpringBoot - S3, 파일 업로드

희운·2025년 6월 30일

aws

목록 보기
2/9

사용자가 이미지 업로드를 하면 서버에서 S3 로 사진을 저장해주면된다.(Service layer)

예를들어 , 사용자가 게시글에 사진을 첨부하면, 그 사진들은 S3 에 저장이 될것이다.
그리고 RDS 에 게시글, 이미지URL 이 연관관계를 통해서 저장이 될것이다.

SpringBoot 에서 S3 와 연결을 위해 의존성을 추가하자


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

의존성을 추가했으면

S3Config 에 수동으로 빈등록을 해야한다. 여기서 중요한 점이 외부에서 S3 를 접근하기 위해서는 액세스 키를 발급 받아서 사용해야한다.

액세스 키 발급 과정 : https://jscode.notion.site/2-S3-IAM-fa151c4afcad4d00b0dc6f6518d83c0c

우리는 발급받은 키를 저장해놓고 SpringBoot 내부에서 사용하자.



package com.project.modac.global.config;

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


@Slf4j
@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;


    //S3 를 접근하기 위한 객체이다.
    @Bean
    public AmazonS3Client amazonS3Client() {

        //accessKey, secretKey 를 인자로
        BasicAWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey);

        log.info("S3Config 등록 성공");
        return (AmazonS3Client) AmazonS3ClientBuilder
                .standard()
                .withRegion(region)
                .withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
                .build();

    }
    

}

발급받은 엑세스 키는 application.yml 에 두고 , @Value 를 통해서 주입을 받으면 된다.

AmazonS3Client 는 S3 에 접근하기 위한 객체라고 생각하자.


package com.project.modac.controller;

import com.project.modac.service.ImageService;
import com.project.modac.service.RegisterService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Map;

@RestController
@RequiredArgsConstructor
public class ImageController {

    private final ImageService imageService;

    @PostMapping(value = "/image/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public String imageUpload(@RequestParam("request") MultipartFile request
    ) throws Exception {

        String s3UploadUrl = imageService.imageUpload(request);
        return s3UploadUrl;
    }
}

컨트롤러에서 받은 MultipartFile 을 서비스단에 넘기자.


package com.project.modac.service;

import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.project.modac.global.config.S3Config;
import jakarta.servlet.annotation.WebServlet;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartRequest;

import java.io.File;
import java.io.IOException;
import java.util.UUID;

@Service
@RequiredArgsConstructor
public class ImageService {

    private final AmazonS3Client s3Client;

    @Value("${file.dir}")
    private String dir;

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


    @Transactional
    public String imageUpload(MultipartFile file) throws IOException {

        String originalFilename = file.getOriginalFilename();

        //확장자 가져오기
        String ext = originalFilename.substring(originalFilename.indexOf("."));

        //이미지 파일이름 유일성을 위해서
        String uuidFileName = UUID.randomUUID() + ext;

        // 서버local, 저장url
        String localPath = dir + uuidFileName;

        File localFile = new File(localPath);


        // transferTo(localFile) 은 파일을 내 로컬(서버로컬) 해당 경로에 넣어준다.
        file.transferTo(localFile);

        //S3 의 파일은 오브젝트라고 한다. 그래서 putObject
        s3Client.putObject(
                new PutObjectRequest(
                        bucketName, uuidFileName, localFile
                )
        );

        //S3에 이미지 올림
        //S3에 이미지가 저장된경로
        String S3url = s3Client.getUrl(bucketName,uuidFileName).toString();

        //로컬에 저장한거 삭제
        localFile.delete();

        return S3url;

    }
}


여기서 putObject 는 S3에 저장하는 메서드인다.
여기서 new PutObjectRequest("버킷이름", "버킷에 저장할 파일명", "실제파일") 을 넣어주면 S3에 이미지가 올라간다.


이미지를 다운받을때 S3 를 사용하기 전에는 local 에 요청을 보내면 local 에서 이미지를 직접 client 에게 넘겨주었다. 하지만 S3 를 사용하면 서버에서는 RDS 를 통해서 S3 에 저장한 이미지 URL 을 client 에 넘기고 직접 S3 를 통해서 이미지를 다운받는다.

profile
기록하는 공간

0개의 댓글