프로젝트를 진행하던 도중, 프로필 사진을 업로드하는 기능을 구현하게 되었다.
사진은 AWS의 S3에 저장시켜야 한다.
스프링부트에서 S3에 사진을 업로드하고 저장된 사진의 URI를 가져오며 삭제까지 구현해보는 시간을 가져본다.
Resource
부분의 맨 끝에는 /*
을 달아줘야 데이터에 접근할 수 있다.AmazonS3
빈을 등록한다.AmazonS3Client
이다.@Configuration
public class AwsS3Config {
@Value("${cloud.aws.credentials.access-key}")
private String accessKey;
@Value("${cloud.aws.credentials.secret-key}")
private String secretKey;
@Bean
public AmazonS3 amazonS3() {
return AmazonS3ClientBuilder
.standard()
.withRegion(Regions.AP_NORTHEAST_2)
.withCredentials(awsStaticCredentialsProvider())
.build();
}
@Bean
public AWSStaticCredentialsProvider awsStaticCredentialsProvider() {
BasicAWSCredentials basicAWSCredentials = new BasicAWSCredentials(accessKey, secretKey);
return new AWSStaticCredentialsProvider(basicAWSCredentials);
}
}
MultipartFile
이 이미지 타입인지 확인한다.유저네임_UUID
으로 설정한다.ObjectMetadata
를 통해 해당 사진의 메타데이터를 생성한다.AmazonS3.putObject()
메소드를 통해 S3 버킷 이름과 파일 이름, 파일 데이터, 메타데이터를 보낸다.AmazonS3.deleteImage()
를 통해 삭제한다.AmazonS3.getUrl(bucketName, fileName)
로 가져온 이미지의 URI를 가져와 저장한다.@RequiredArgsConstructor
@Service
public class UserImageServiceImpl implements UserImageService {
private final AmazonS3 amazonS3;
private final UserRepository userRepository;
@Value("${cloud.aws.s3.bucket}")
private String bucketName;
private final static String IMAGE_JPG = "image/jpeg";
private final static String IMAGE_PNG = "image/png";
@Override
@Transactional
public void uploadImage(final MultipartFile multipartFile, final User user) {
User findUser = userRepository.findById(user.getId())
.orElseThrow(NotFoundUserException::new);
if (!isImageType(multipartFile)) {
throw new NoImageFileException();
}
String fileName = findUser.getUsername() + "_" + UUID.randomUUID();
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(multipartFile.getSize());
metadata.setContentType(multipartFile.getContentType());
try {
if (amazonS3.doesObjectExist(bucketName, user.getImageName())) {
deleteImage(bucketName, user.getImageName());
}
amazonS3.putObject(bucketName, fileName, multipartFile.getInputStream(), metadata);
} catch (IOException e) {
throw new FailUploadImageException();
}
findUser.uploadImage(fileName, amazonS3.getUrl(bucketName, fileName).toString());
}
}
AmazonS3.doesObjectExist()
를 통해 확인한다.AmazonS3.deleteObject()
를 통해 삭제시킨다. @Override
@Transactional
public void deleteImage(final User user) {
User findUser = userRepository.findById(user.getId())
.orElseThrow(NotFoundUserException::new);
if(!amazonS3.doesObjectExist(bucketName, user.getImageName())){
return;
}
deleteImage(bucketName, user.getImageName());
findUser.deleteImage();
}
private void deleteImage(String bucketName, String imageName){
try {
amazonS3.deleteObject(bucketName, imageName);
} catch (Exception e) {
throw new FailDeleteImageException();
}
}
스프링을 통해 S3로 파일을 업로드하는 것이 처음이여서 보안적으로 허술한 부분이 있을 것이다. S3를 생성할 때, 보안 요소를 좀 더 살펴보고 설정해 줄 필요가 있을 것 같다.
특히, ACL이 무엇인지, 정책은 어떠한 종류가 있는지 알아보고 세세하게 설정해주면 더 좋을 듯 하다.