본문 바로가기

Server/Spring

[우당탕탕 개발일지] Spring Boot와 AWS S3을 이용하여 파일 업로드하기

반응형
SMALL

안녕하세요. 아주 오랜만에 포스팅 글을 남겨보네요.

이번에 사이드 프로젝트를 진행하면서 이미지 업로드 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하게 업로드한 파일을 조회할 수 있습니다.

 

 

연습 레포지토리(리팩토링한 코드)

 

GitHub - thguss/spring-file-playground: 스프링 파일 업로드 연습 공간

스프링 파일 업로드 연습 공간. Contribute to thguss/spring-file-playground development by creating an account on GitHub.

github.com

 

 

References

https://jungkeung.tistory.com/45

https://kim-jong-hyun.tistory.com/78

https://gaeggu.tistory.com/33

https://velog.io/@chaeri93/SpringBoot-AWS-S3%EB%A1%9C-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%97%85%EB%A1%9C%EB%93%9C%ED%95%98%EA%B8%B0

반응형
LIST