AWS S3 Bucket 사이트에 접속한다.
해당 사이트에서 버킷 만들기를 클릭한다.
기본적인 정보를 입력한다.
나머지는 Defalut 값으로 두고 생성을 완료한다.
생성된 버킷에 들어가서 권한 → 버킷 정책 → 편집을 클릭한다.
버킷 정책 편집에 접속했다면 버킷 ARN은 copy 하고 정책 생성기를 클릭한다.
Select Type of Policy → S3 Bucket Policy
Principal → *
Action → DeleteObject, GetObject, PutObject
ARN → 위에서 복사한 값을 넣어주면 된다.
그리고 Add Statement를 누르면 지금까지의 상태가 등록된다.
밑에 Generate Policy를 클릭한다.
해당 내용을 복사한다.
위 복사한 내용을 버킷 정책에 입력한다.
AWS IAM 사이트에 접속한다.
사용자 세부 정보
- 사용자 이름 → 자기가 지정하고 싶은 이름으로 저장.
권한 설정
생성된 IAM 사용자를 클릭힌다.
@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() {
BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey, secretKey);
return (AmazonS3Client) AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.build();
}
}
cloud:
aws:
credentials:
access-key: AWS_S3_access-key
secret-key: AWS_S3_secret-key
region:
static: ap-northeast-2
s3:
bucket: AWS_S3_bucket
stack:
auto: false
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class AwsS3Service {
@Value("${cloud.aws.s3.bucket}")
private String bucket;
private final AmazonS3 amazonS3;
private final ImageRepo imageRepo;
private static final String IMAGE_URL_PREFIX = "https://나의 버킷 이름.s3.ap-northeast-2.amazonaws.com/";
@Transactional
public List<Image> uploadFile(Post post, List<MultipartFile> multipartFile) {
List<Image> images = new ArrayList<>();
// forEach 구문을 통해 multipartFile로 넘어온 파일들 하나씩 fileNameList에 추가
multipartFile.forEach(file -> {
String fileName = createFileName(file.getOriginalFilename());
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentLength(file.getSize());
objectMetadata.setContentType(file.getContentType());
// 이미지 DB 저장.
String originalFilename = file.getOriginalFilename();
String imageUrl = IMAGE_URL_PREFIX + fileName;
Image image = Image.builder()
.imageName(fileName)
.imageUrl(imageUrl)
.originalImageName(originalFilename)
.post(post)
.build();
Image saveImage = imageRepo.save(image);
images.add(saveImage);
try(InputStream inputStream = file.getInputStream()) {
amazonS3.putObject(new PutObjectRequest(bucket, fileName, inputStream, objectMetadata)
.withCannedAcl(CannedAccessControlList.PublicRead));
} catch(IOException e) {
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "파일 업로드에 실패했습니다.");
}
});
return images;
}
@Transactional
public void updateFile(Post post, List<Image> images, PostDto postDto) {
images.forEach(image -> {
amazonS3.deleteObject(new DeleteObjectRequest(bucket, image.getImageName()));
imageRepo.delete(image);
});
if (postDto.getImageFiles().size() > 0 && !Objects.equals(postDto.getImageFiles().get(0).getOriginalFilename(), "")) {
uploadFile(post, postDto.getImageFiles());
}
}
@Transactional
public void deleteFile(String fileName) {
amazonS3.deleteObject(new DeleteObjectRequest(bucket, fileName));
}
private String createFileName(String fileName) { // 먼저 파일 업로드 시, 파일명을 난수화하기 위해 random으로 돌립니다.
return UUID.randomUUID().toString().concat(getFileExtension(fileName));
}
private String getFileExtension(String fileName) { // file 형식이 잘못된 경우를 확인하기 위해 만들어진 로직이며, 파일 타입과 상관없이 업로드할 수 있게 하기 위해 .의 존재 유무만 판단하였습니다.
try {
return fileName.substring(fileName.lastIndexOf("."));
} catch (StringIndexOutOfBoundsException e) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "잘못된 형식의 파일(" + fileName + ") 입니다.");
}
}
}