사실 원래 계획에도 없던 S3와 CloudFront를 이용한 image CDN 구현이여서 조바심에 미리 구현해봤다.
사전 지식이 전무했기때문에 코드를 하나하나 chatGPT에 물어봐가며 주석처리하며 공부한 간단한 일지
참고한 블로그
AWS S3 이미지 업로드 Spring으로 사용해보기 (tistory.com)
AWS S3 이미지 업로드 Spring으로 사용해보기
대부분의 이미지 서버를 구축할 때는 AWS S3를 보편적으로 사용합니다. 저희 또한, S3를 애플리케이션 이미지 업로드 및 다운로드 서버로 선택하게 되었습니다. 큰 이유가 있기 보다는.. 서버를 사
jane514.tistory.com
코드를 완전히 똑같이 가져와서 나중에 기회가 된다면 멘토님과 코드리뷰를 해봤으면 좋겠다.
S3 버킷 생성
이미 전 실습 때 S3 버킷을 생성해 놨으므로 이 부분은 넘어갔다.
IAM 사용자 추가
[Spring boot] AWS S3 를 이용한 파일 업로드 :: gaeggu's blog (tistory.com)
[Spring boot] AWS S3 를 이용한 파일 업로드
개인 프로젝트를 하며 이미지 서버로 사용하기 위해 AWS S3 버킷을 만들고 Spring 을 연동하는 방법을 정리해보았다. [1] AWS S3 개요 AWS S3 란? S3는 Simple Storage Service 의 약자로 주로 파일 서버로 사용
gaeggu.tistory.com
IAM 사용자 추가 및 accessKey,SecretKey 생성은 이 포스트를 참고하였다.(S3 생성도 자세히 적혀져있다.)
의존성 추가
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
S3와 프로그램을 연동하기 위한 의존성 추가(2023/03/06 기준 문제 X)
yml 파일에 추가해야 할 부분
cloud:
aws:
s3:
bucket: 버켓 이름
stack.auto: false
region.static: 지역 정보
credentials:
accessKey: IAM accessKey
secretKey: IAM secretKey
연동을 위한 정보를 yml 파일에 넣어준다.
AWS S3 Config
package main_project_025.I6E1.aws;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AwsS3Config {
@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;
@Bean
public AmazonS3Client amazonS3Client() {//AWS S3 서비스와 상호작용할 수 있는 클라이언트 객체
BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey, secretKey);//accessKey와 secretKey를 사용하여 AWS 인증정보 생성 -> AWS S3 서비스에 연결할 때 사용
return (AmazonS3Client) AmazonS3ClientBuilder.standard()//AmazonS3ClientBuilder를 통해 AWS S3 클라이언트 객체를 생성한다.
.withRegion(region)//클라이언트 객체가 사용할 AWS 지역 설정
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))//AWS 인증 정보를 설정
.build();//클라이언트 객체 생성하고 반환
}
}
AwsS3Service(upload와 delete만 구현)
@Service
@RequiredArgsConstructor
public class AwsS3Service {
@Value("${cloud.aws.s3.bucket}")
private String bucket;
private final AmazonS3 amazonS3;
public List<String> uploadImage(List<MultipartFile> multipartFile) {//multipartFile 인터페이스 사용해 업로드
List<String> fileNameList = new ArrayList<>();//여러개의 파일을 업로드 할 수 있기때문에 리스트 이용
multipartFile.forEach(file -> {//forEach 메소드를 사용해 multipartFile에 담긴 파일을 하나씩 처리
String fileName = createFileName(file.getOriginalFilename());//UUID를 통해 랜덤한 id를 생성, concat을 통해 확장자 명을 붙여줘 고유한 파일 이름 생성
ObjectMetadata objectMetadata = new ObjectMetadata();//ObjectMetadata 객체를 생성
objectMetadata.setContentLength(file.getSize());//파일의 크기 설정
objectMetadata.setContentType(file.getContentType());//MIME 타입 정보 설정
try(InputStream inputStream = file.getInputStream()) {//inputStream은 바이트 단위로 데이터를 읽어들이는 스트림으로, getInputStream() 메소드를 통해 file의 내용을 읽어들인다.
amazonS3.putObject(new PutObjectRequest(bucket, fileName, inputStream, objectMetadata)//PutObjectRequest 객체를 생성하여 '업로드할 bucket', '업로드할 fileName', '업로드할 파일 내용', '메타데이터' 설정 후 putObject()를 통해 버킷에 파일 업로드를 한다.
.withCannedAcl(CannedAccessControlList.PublicRead));//withCannedAcl()메서드를 사용 해 S3에서 해당 파일에 대한 공개 권한 설정,여기선 공개적으로 접근하도록 설정
} catch(IOException e) {
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "이미지 업로드에 실패했습니다.");
}
fileNameList.add(fileName);//fileNameList에 업로드된 파일의 이름을 추가
});
return fileNameList;//리스트 반환!
}
public void deleteImage(String fileName) {
amazonS3.deleteObject(new DeleteObjectRequest(bucket, fileName));
//deleteObject() = S3 버킷에 있는 fileName을 삭제
//DeleteObjectRequest() = 삭제하려는 객체의 위치를 식별하는 메소드
}
private String createFileName(String fileName) {
return UUID.randomUUID().toString().concat(getFileExtension(fileName));
//UUID를 통해 랜덤한 id를 생성, concat을 통해 확장자 명을 붙여준다.
}
private String getFileExtension(String fileName) {
try {
return fileName.substring(fileName.lastIndexOf("."));//lastIndexOf(".")호출 시 파일 이름의 '.' 문자의 인덱스 반환,즉 substring()으로 인해 '.' 문자를 포함한 문자열의 끝부분부터 끝까지 추출
//ex) test.txt의 경우 fileName.substring(5)가 되고 ".txt"를 반환
} catch (StringIndexOutOfBoundsException e) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "잘못된 형식의 파일 (" + fileName + ") 입니다.");
}
}
}
AwsS3Controller
@RestController
@RequiredArgsConstructor
@RequestMapping("/s3")
public class AmazonS3Controller {
private final AwsS3Service awsS3Service;
@ApiOperation(value = "Amazon S3에 이미지 업로드", notes = "Amazon S3에 이미지 업로드 ")//API에 대한 설명을 추가할 때 사용(value 속성은 API에 대한 간단한 설명, notes 속성은 API에 대한 상세한 설명)
@PostMapping("/image")//업로드 시 PostMapping을 사용하여 업로드
public ResponseEntity<List<String>> uploadImage(@ApiParam(value="img 파일들(여러 파일 업로드 가능)", required = true) @RequestPart List<MultipartFile> multipartFile) {//@RequestPart는 멀티파트 요청에서 파일 데이터를 읽어올 때 사용
return ApiResponse.success(awsS3Service.uploadImage(multipartFile));//ApiResponse.success 메서드는 API 요청을 성공적으로 처리한 경우, ResponseEntity 객체를 반환하고 이 리스트를 클라이언트에게 응답
}
@ApiOperation(value = "Amazon S3에 업로드 된 파일을 삭제", notes = "Amazon S3에 업로드된 이미지 삭제")
@DeleteMapping("/image")
public ResponseEntity<Void> deleteImage(@ApiParam(value="img 파일 하나 삭제", required = true) @RequestParam String fileName) {
awsS3Service.deleteImage(fileName);
return ApiResponse.success(null);
}
}
Postman으로 테스트해보기
Post 요청으로 form-data에 값을 넣어줘 요청하면 잘 담아진다.
Delete 요청 테스트시에도 정상 작동 확인완료.
'AWS' 카테고리의 다른 글
EC2 솔루션스 아키텍트 어소시에이트 레벨 (0) | 2024.02.07 |
---|---|
EC2 기초 (0) | 2024.02.07 |
AWS ECS, Fargate, ECR, EKS (0) | 2024.01.29 |
AWS IAM (0) | 2024.01.29 |
CDN(Contents Delivery Network) (0) | 2023.03.05 |