안녕하세요. 아주 오랜만에 포스팅 글을 남겨보네요.
이번에 사이드 프로젝트를 진행하면서 이미지 업로드 API가 필요한 일이 생겨서 공부할 겸 글로 남겨봅니다.
Spring Boot 버전은 3.x 버전이고, AWS 버킷에 파일을 업로드 한 후 파일의 공개 url을 가져오는 API 개발을 연습했어요.
AWS
S3
우선 AWS의 S3 서비스에서 버킷을 만들어주어야 합니다.
업로드한 파일을 public하게 접근할 수 있어야 하기 때문에 버킷을 생성할 때 퍼블랙 액세스 차단 설정만 해제해줍니다.
버킷을 생성했으면 정책 설정이 추가로 필요합니다. 버킷으로 들어가 권한 옵션의 버킷 정책에서 편집을 클릭해주세요. 그러면 위 이미지처럼 가장 오른쪽 버튼의 정책 생성기를 확인할 수 있는데 버튼 눌러주면 됩니다.
Effect: Allow
Principal: *
Aws Service: Amazon S3
Actions: GetObject (저는 객체 조회만 필요하기 때문에 하나만 선택했습니다. 읽어보시고 더 필요한 기능이 있다면 추가로 선택해주세요.)
ARN: 버킷 정책 편집 이미지를 보면 아래 쪽에 버킷 ARN이 있습니다. 그 밑에 있는 ARN 복사해주시고, /* 추가로 붙여주시면 됩니다.
설정이 끝났으면 Add Statment 클릭 후, Step3에서 설정한 정책 확인 및 생성하면 됩니다. 그러면 JSON 형식의 텍스트가 나올텐데 내용 전체 복사해서 버킷 정책 아래의 내용에 똑같이 붙여넣고, 변경 사항 저장해주시면 됩니다.
그럼 버킷 준비는 끝났습니다.
IAM
다음은 S3에 접근할 수 있는 사용자를 통해 API 내에서 파일을 버킷에 업로드 할 수 있도록 IAM 서비스에서 접근 가능한 사용자를 추가해주어야 합니다. 이 부분은 이미지 첨부 생략하겠습니다.
IAM 서비스 > 사용자 > 사용자 추가로 접근해주세요.
사용자 이름 입력하고(Ex. s3-user) 직접 정책 연결 옵션을 선택하여 AmazonS3FullAccess 권한을 추가하고 사용자를 추가해주세요.
생성된 사용자로 들어가서 보안 자격 증명 탭의 액세스 키 만들기로 들어가줍니다.
사용 사례는 아무거나(저는 배포를 생각해서 CLI를 선택했어요) 선택하면 됩니다. 넘어가서 설명 태그 달아주고 액세스키 만들기 해주면 됩니다. 만들자마자 받을 수 있는 CSV 파일을 꼭 저장해주세요. 액세스 키와 시크릿 키가 필요합니다.
Spring Boot
이제 파일을 업로드할 수 있는 API를 만들어보겠습니다.
aws:
s3:
bucket: {생성한 버킷 이름}
stack.auto: false
region.static: ap-northeast-2
credentials:
accessKey: {발급받은 액세스 키}
secretKey: {발급받은 시크릿 키}
먼저 application.yml 같은 .gitignore 되는 파일에 위와 같이 버킷과 사용자 정보를 입력해주세요.
@Configuration
public class S3Config {
@Value("${aws.credentials.access-key}")
private String accessKey;
@Value("${aws.credentials.secret-key}")
private String secretKey;
@Value("${aws.region.static}")
private String region;
@Bean
public AmazonS3Client amazonS3Client() {
BasicAWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey);
return (AmazonS3Client)AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
.build();
}
}
Config 파일을 만들어 위 내용도 입력해주세요. 그럼 Spring Boot에서 버킷에 접근할 준비는 다 되었습니다 :)
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/file")
public class FileController {
private final AmazonS3Client amazonS3Client;
@Value("${cloud.aws.s3.bucket}")
private String bucket;
@PostMapping
public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
try {
String fileName = getRandomFileName(file.getOriginalFilename()); // 파일 이름
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType(file.getContentType());
metadata.setContentLength(file.getSize());
amazonS3Client.putObject(bucket, fileName, file.getInputStream(), metadata); // 파일 업로드
String url = amazonS3Client.getUrl(bucket, fileName).toString(); // 업로드한 파일 공개 url
return ResponseEntity.ok(url);
} catch (IOException e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
private String getRandomFileName(String fileName) {
return "test" + ":" + LocalDateTime.now() + ":" + UUID.randomUUID() + ":" + fileName;
}
}
이제 파일을 업로드할 수 있는 API를 간단하게 만들어보겠습니다. AmazoneS3Client와 Bucket 정보를 통해 file 이름의 데이터로 받은 파일을 업로드하고 공개 url을 응답 값으로 보냅니다.
@RequestParmam("name")
Request Body로 받을 것이라고 생각했는데 Param 값으로 받더라구요. 잘 기억해두어야겠습니다.
AmazonS3Client.putObject(..)
버킷에 파일을 지정한 버킷에, 지정한 이름 값으로 업로드합니다.
AmazonS3Client.getUrl(..)
지정한 버킷의 특정 이름을 가진 파일의 public한 url을 가져옵니다.
getRandomFileName(String fileName)
파일의 이름을 고유성으로 가지기 때문에 각각의 파일명을 고유하게 만들 수 있는 메소드를 작성했습니다. 현재 시간과 UUID, 기존 파일명을 이용하여 임의의 파일명을 지정했습니다. (test는 프로젝트 이름이라고 생각해주면 좋을 것 같습니다.)
API를 테스트해보면 성공적으로 응답하는 것을 확인할 수 있고, 응답 값의 url로 접속하면 public하게 업로드한 파일을 조회할 수 있습니다.
References
https://jungkeung.tistory.com/45
'Server > Spring' 카테고리의 다른 글
[Spring] 스프링에서 Slack에 에러 로그 보내기 (0) | 2024.03.18 |
---|---|
[우당탕탕 개발 일지] Spring Security 트러블 슈팅: AntPathRequestMatcher (1) | 2023.10.23 |
[우당탕탕 개발 일지] com.querydsl.core.types.ExpressionException 에러: 기본 생성자 필요 (0) | 2023.03.22 |
[우당탕탕 개발일지] Querydsl 초기 세팅: 버전 5 기준 (0) | 2023.03.19 |
[우당탕탕 개발 일지] @Builder의 잘못된 사용 예시, List 필드가 있으면 Builder를 신중하게 사용하자! (0) | 2023.02.20 |