S3 버킷 생성 > IAM 사용자 생성
Spring Boot 연결
build.gradle
// aws s3
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
application.properties
: 배포하지 않을 예정이기 때문에 application.properties에 한꺼번에 적어둠
: IAM 사용자의 access key를 발급받아 붙이기
#S3
cloud.aws.credentials.accessKey={IAM-access-key}
cloud.aws.credentials.secretKey={IAM-secret-key}
cloud.aws.s3.bucket={bucket-name}
cloud.aws.region.static={region}
cloud.aws.s3.bucket.url=https://s3.ap-northeast-2.amazonaws.com/{bucket-name}
cloud.aws.stack.auto=false
AmazonS3Config.java
@Configuration
public class AmazonS3Config {
@Value("${cloud.aws.credentials.accessKey}")
private String accessKey;
@Value("${cloud.aws.credentials.secretKey}")
private String secretKey;
@Value("${cloud.aws.region.static}")
private String region;
// S3 버킷에 접근할 수 있는 client 객체
@Bean
public AmazonS3Client amazonS3Client() {
BasicAWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey);
return (AmazonS3Client) AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
.build();
}
}
AwsS3FileUpload.java
@Slf4j(topic = "AwsS3Service")
@RequiredArgsConstructor
@Component
public class AwsS3FileUploadImpl implements AwsS3FileUpload {
@Value("${cloud.aws.s3.bucket}")
private String bucket;
private final AmazonS3Client amazonS3Client;
@Override
public String upload(MultipartFile multipartFile, String dirName) throws IOException {
File uploadFile = convert(multipartFile)
.orElseThrow(() -> new IllegalArgumentException("MultipartFile -> File로 전환이 실패했습니다."));
// 현재 dirName 은 profile 만 받을 예정
String fileName = dirName + "/" + uploadFile.getName();
String uploadImageUrl = putS3(uploadFile, fileName);
removeNewFile(uploadFile);
return uploadImageUrl;
}
@Override
public String putS3(File uploadFile, String fileName) {
// bucket 권한때 설정한 것 중 하나
amazonS3Client.putObject(
new PutObjectRequest(bucket, fileName, uploadFile)
.withCannedAcl(CannedAccessControlList.PublicRead)
);
return amazonS3Client.getUrl(bucket, fileName).toString();
}
@Override
public void removeNewFile(File localSavedFile) {
if (localSavedFile.delete()) {
log.info("로컬에 저장된 파일 삭제");
} else {
log.info("로컬에 저장된 파일 삭제 실패");
}
}
@Override
public Optional<File> convert(MultipartFile file) throws IOException {
File convertFile = new File(file.getOriginalFilename());
log.info("convertFile = " + convertFile);
if (convertFile.createNewFile()) {
try (FileOutputStream fos = new FileOutputStream(convertFile)) {
fos.write(file.getBytes());
}
return Optional.of(convertFile);
}
return Optional.empty();
}
}
UserService.java
@Override
public void uploadProfileImage(MultipartFile multipartFile, User user) throws IOException {
fileUpload.upload(multipartFile, "profile");
}
UserController.java
@PostMapping("/profileImg")
public ResponseEntity<ApiResponseDto> uploadProfileImage(
@RequestPart (required = false) MultipartFile multipartFile,
@AuthenticationPrincipal UserDetailsImpl userDetails
) throws IOException {
userService.uploadProfileImage(multipartFile, userDetails.getUser());
return ResponseEntity.status(201).body(new ApiResponseDto("프로필 사진이 업로드 되었습니다.", HttpStatus.CREATED.value()));
}
프로필 이미지를 변경할 때 이미지 파일과 요청한 사용자 정보만 필요하기 때문에 위와 같이 작성함
API 에서 content type을 Image/{확장자명} 으로 설정해야함
-> 설정하지 않는다면 415 Unsupported MediaType ERROR 발생
profile 폴더에 들어간 것을 확인할 수 있음