안녕하세요. J4J입니다.
이번 포스팅은 AWS S3에 파일 업로드하는 방법에 대해 적어보는 시간을 가져보려고 합니다.
들어가기에 앞서 Controller에서 파일 데이터를 받을 수 있기 위해 multipartfile을 사용할 예정입니다.
또한 AWS S3 버켓 생성하는 방법은 [AWS] 이미지 저장을 위한 S3 버킷 생성하기를 참고해주시길 바랍니다.
S3에 접근할 IAM 계정 생성
가장 먼저 S3에 접근할 수 있는 IAM 계정 생성을 해줘야 합니다.
계정 생성이 완료되면 해당 계정 정보를 SpringBoot에 입력해줄 것이고 이를 기반으로 S3에 접근할 수 있는 사용자인지를 판단할 수 있게 도와줍니다.
[ 1. IAM 서비스 접근 ]
[ 2. 사용자 추가 클릭 ]
[ 3. 사용자 정보 입력 ]
사용자 이름은 사용하고 싶은 이름으로 자유롭게 기입해주시면 됩니다.
액세스 유형 같은 경우는 액세스 키를 활용하기 때문에 암호 말고 액세스 키를 선택해줍니다.
[ 4. 권한 입력 ]
권한은 AmazoneS3FullAccess를 부여하면 됩니다.
저는 사용자에게만 권한을 부여하고 있지만 상황에 따라 S3 사용 권한을 가진 사용자 그룹을 만들어서 사용하는 것도 좋은 방법이니 참고해주시길 바랍니다.
[ 5. 태그 추가 ]
필요하신 분만 태그 추가해주시면 됩니다.
저는 따로 입력하지 않았습니다.
[ 6. 검토 ]
지금까지 작성한 내용들을 확인하는 단계입니다.
따로 문제가 없다면 다음으로 넘어가 주시면 됩니다.
[ 7. 액세스 키 확인 ]
사용자 생성이 완료되었다면 다음과 같이 액세스 키 정보를 확인할 수 있습니다.
현재 화면에서만 확인할 수 있고 화면이 넘어가면 확인할 수 없는 정보가 있기 때문에 csv 다운을 하는 등의 방식을 통해 어디든 정보를 보관해둬야 합니다.
Springboot 설정
위에서 생성한 IAM 계정을 이용하여 S3 Bucket에 연결해보겠습니다.
[ 1. application.properties 설정 ]
# multipart 설정
spring.servlet.multipart.max-file-size: 100MB
spring.servlet.multipart.max-request-size: 100MB
# aws 설정
# 사용할 S3 bucket region 입력
cloud.aws.region.static=ap-northeast-2
cloud.aws.stack.auto=false
[ 2. dependency 추가 ]
<dependencies>
<!-- AWS -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-aws</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
</dependencies>
[ 3. AWS 설정 클래스 작성 ]
package com.spring.s3.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
@Configuration
public class AWSConfig {
/**
* Key는 중요정보이기 때문에 properties 파일에 저장한 뒤 가져와 사용하는 방법이 좋습니다.
*/
private String iamAccessKey = "IAM 생성할 때 확인했던 AccessKey 입력"; // IAM Access Key
private String iamSecretKey = "IAM 생성할 때 확인했던 SecretKey 입력"; // IAM Secret Key
private String region = "ap-northeast-2"; // Bucket Region
@Bean
public AmazonS3Client amazonS3Client() {
BasicAWSCredentials basicAWSCredentials = new BasicAWSCredentials(iamAccessKey, iamSecretKey);
return (AmazonS3Client) AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(basicAWSCredentials))
.build();
}
}
[ 4. Controller 클래스 작성 ]
package com.spring.s3.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
@RestController
public class FileController {
private String S3Bucket = "j4j-test-bucket"; // Bucket 이름
@Autowired
AmazonS3Client amazonS3Client;
@GetMapping("/upload")
public ResponseEntity<Object> upload(MultipartFile[] multipartFileList) throws Exception {
List<String> imagePathList = new ArrayList<>();
for(MultipartFile multipartFile: multipartFileList) {
String originalName = multipartFile.getOriginalFilename(); // 파일 이름
long size = multipartFile.getSize(); // 파일 크기
ObjectMetadata objectMetaData = new ObjectMetadata();
objectMetaData.setContentType(multipartFile.getContentType());
objectMetaData.setContentLength(size);
// S3에 업로드
amazonS3Client.putObject(
new PutObjectRequest(S3Bucket, originalName, multipartFile.getInputStream(), objectMetaData)
.withCannedAcl(CannedAccessControlList.PublicRead)
);
String imagePath = amazonS3Client.getUrl(S3Bucket, originalName).toString(); // 접근가능한 URL 가져오기
imagePathList.add(imagePath);
}
return new ResponseEntity<Object>(imagePathList, HttpStatus.OK);
}
}
테스트
실행해보면 다음과 같은 에러를 확인하실 수 있습니다.
com.amazonaws.SdkClientException: Failed to connect to service endpoint:
at com.amazonaws.internal.EC2ResourceFetcher.doReadResource(EC2ResourceFetcher.java:100) ~[aws-java-sdk-core-1.11.792.jar:na]
at com.amazonaws.internal.InstanceMetadataServiceResourceFetcher.getToken(InstanceMetadataServiceResourceFetcher.java:91) ~[aws-java-sdk-core-1.11.792.jar:na]
at com.amazonaws.internal.InstanceMetadataServiceResourceFetcher.readResource(InstanceMetadataServiceResourceFetcher.java:69) ~[aws-java-sdk-core-1.11.792.jar:na]
at com.amazonaws.internal.EC2ResourceFetcher.readResource(EC2ResourceFetcher.java:66) ~[aws-java-sdk-core-1.11.792.jar:na]
at com.amazonaws.util.EC2MetadataUtils.getItems(EC2MetadataUtils.java:402) ~[aws-java-sdk-core-1.11.792.jar:na]
at com.amazonaws.util.EC2MetadataUtils.getData(EC2MetadataUtils.java:371) ~[aws-java-sdk-core-1.11.792.jar:na]
EC2 메타데이터 관련 에러인 것으로 보이는데 해당 에러가 보여도 동작되는 데는 문제가 없지만 이런 에러가 보이고 싶지 않으신 분들은 로그가 안 나오게 하거나 또는 VM 옵션 설정을 통해 해결할 수 있는 것으로 보입니다.
구글에 검색하면 관련 정보들을 빠르게 확인하실 수 있습니다.
작성한 코드들을 테스트하기 위해 포스트맨을 사용해보겠습니다.
다음과 같이 관련 정보들을 입력해주고 Send를 클릭하면 Response값에 다음과 같이 업로드된 이미지 URL을 확인할 수 있습니다.
또한 S3에서도 업로드된 것이 확인 가능합니다.
마지막으로 전달받은 URL 중 하나를 선택하여 브라우저에서 접근해보면 다음과 같이 이미지도 보이는 것을 확인할 수 있습니다.
이상으로 AWS S3에 파일 업로드하는 방법에 대해 간단하게 알아보는 시간이었습니다.
읽어주셔서 감사합니다.
'Spring > SpringBoot' 카테고리의 다른 글
[SpringBoot] Found shared references to a collection 에러 (0) | 2022.06.13 |
---|---|
[SpringBoot] JPA에서 QueryDSL 사용하기 (0) | 2022.04.24 |
[SpringBoot] 환경 변수 파일 사용하기 (0) | 2022.03.28 |
[SpringBoot] GraphQL 설정 (0) | 2021.12.23 |
[SpringBoot] 파일 다운로드 (0) | 2021.06.07 |
댓글