SpringBoot로 aws S3에 사진 업로드 하는 방법

개발하는 구황작물·2022년 9월 24일
0

메인 프로젝트

목록 보기
2/10

project 에서 사진을 업로드 기능을 만들어야 해서 사진을 저장하는 여러방법 중 AWS S3에 업로드 하고 url만 DB에 저장하는 방식을 선택하였다.

※ 이 포스트는 AWS 계정이 있고 S3 설정까지 했다는 전제하에 작성하였습니다.

1. 의존성 추가

  • build.gradle
    implementation 'io.awspring.cloud:spring-cloud-starter-aws:2.4.4'

implementation 사이트

org.springframework.cloud:spring-cloud-starter-aws ~ 는 업데이트가 2021년도 이후로 되지 않으니 쓰지 말자

2. 환경변수 설정

  • application.yml
 
 # 파일 업로드 크기 설정 
 spring:
 	servlet:
    multipart:
      max-file-size: 20MB # 파일 하나당 크기
      max-request-size: 20MB # 전송하려는 총 파일 크기

cloud:
  aws:
    credentials:
      accessKey: {AWS IAM AccessKey}
      secretKey: {AWS IAM SecretKey}
    s3:
      bucket: {버킷 이름}
    region:
      static: {S3 버킷 지역}
    stack:
      auto: false

🚨🚨🚨주의사항🚨🚨🚨

git에 업로드 하기 전 반드시 .gitignore 에 application.yml 추가하세요.
accessKey와 SecretKey 가 git에 올라갈 경우(public repository) 여러분의 계정은 비트코인 채굴장소가 될 수 있습니다.

3. Controller

@RequiredArgsConstructor
@RequestMapping("/v1/posts")
@RestController
public class PostsController {

    @PostMapping("/create") 
    public ResponseEntity create(@RequestPart(value = "request") @Valid PostsDto.PostDto request,
                                 @RequestPart(value = "file") List<MultipartFile> file) {

	...

        return new ResponseEntity<>(mapper.postsToResponseDto(response), HttpStatus.CREATED);
    }

@RequestPart 어노테이션을 사용하여 multipart/form-data 요청을 받습니다.
만약 dto도 사용해야 한다면 dto 또한 @RequestPart를 사용하여 데이터를 받아야 합니다.

4. config

@Configuration
public class AWSConfig {

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

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

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

    @Bean
    public AmazonS3 s3Client() {
        AWSCredentials credentials = new BasicAWSCredentials(accessKey, accessSecret);
        return AmazonS3ClientBuilder.standard()
                .withCredentials(new AWSStaticCredentialsProvider(credentials))
                .withRegion(region).build();
    }
}

5. AwsService

@RequiredArgsConstructor
@Service
@Slf4j
public class AwsS3Service {

    private final AmazonS3 amazonS3Client;

    @Value("${cloud.aws.s3.bucket}")
    private String bucketName; //버킷 이름
    
    public String uploadFile(MultipartFile multipartFile) throws IOException {
        validateFileExists(multipartFile); //파일이 있는지 확인하는 메서드

        String fileName = CommonUtils.buildFileName(multipartFile.getOriginalFilename()); //fileName

        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentType(multipartFile.getContentType());
        try (InputStream inputStream = multipartFile.getInputStream()) {

            amazonS3Client.putObject(new PutObjectRequest(bucketName, fileName, inputStream, objectMetadata)
                    .withCannedAcl(CannedAccessControlList.PublicRead));
        } catch (Exception e) {
            log.error("Can not upload image, ", e);
            throw new RuntimeException("cannot upload image);
        }
        String url = amazonS3Client.getUrl(bucketName, fileName).toString();

        return url;
    }
    
    ...
    
    private void validateFileExists(MultipartFile multipartFile) {
        if(multipartFile.isEmpty()) {
            throw new RuntimeException("file is empty");
        }
    }

6. CommonUtils

파일 이름 생성할 때 사용되는 클래스

public class CommonUtils {
    private static final String FILE_EXTENSION_SEPARATOR = ".";

    public static String buildFileName(String originalFileName) {
        int fileExtensionIndex = originalFileName.lastIndexOf(FILE_EXTENSION_SEPARATOR); //파일 확장자 구분선
        String fileExtension = originalFileName.substring(fileExtensionIndex); //파일 확장자
        String fileName = originalFileName.substring(0, fileExtensionIndex); 파일 이름
        String now = String.valueOf(System.currentTimeMillis()); 파일 업로드 시간

        return fileName + "_" + now + fileExtension;
    }
}

reference
https://www.sunny-son.space/spring/Springboot%EB%A1%9C%20S3%20%ED%8C%8C%EC%9D%BC%20%EC%97%85%EB%A1%9C%EB%93%9C/
https://github.com/Java-Techie-jt/s3-file-storage-example/tree/10bf1924b0bc7fbec6b8985849750cb2df89255c

profile
어쩌다보니 개발하게 된 구황작물

0개의 댓글