미니 프로젝트 진행 중 이미지를 업로드 하는 기능을 구현하기로 했다.
이미지는 s3서버에 저장하고 url을 받아 DB에 저장하는 형식으로 진행되는 것 같았다.
가장먼저 AWS에서 버킷 (S3서버인스턴스) 을 생성해 주었다.
그리고 나서 이 버킷을 사용할 수 있는 계정 (IAM)을 생성해 주었다.
IAM의 권한과 버킷의 접근권한등을 설정해주었다.
다음은 그와 관련된 코드소스들이다.
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
cloud.aws.region.static='리전' (서울의 경우 ap-northeast-2)
cloud.aws.stack.auto=false
cloud.aws.s3.bucket='버킷이름'
cloud.aws.credentials.access-key='IAM 키'
cloud.aws.credentials.secret-key='IAM PW'
spring.servlet.multipart.max-file-size: 10MB
spring.servlet.multipart.max-request-size: 10MB
@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();
}
}
@Component
@RequiredArgsConstructor
public class S3Uploader {
private final AmazonS3Client amazonS3Client;
@Value("${cloud.aws.s3.bucket}")
private String bucket;
public String uploadFiles(MultipartFile multipartFile, String dirName) throws IOException {
File uploadFile = convert(multipartFile) // 파일 변환할 수 없으면 에러
.orElseThrow(() -> new IllegalArgumentException("error: MultipartFile -> File convert fail"));
return upload(uploadFile, dirName);
}
public String upload(File uploadFile, String filePath) {
String fileName = filePath + "/" + UUID.randomUUID() + uploadFile.getName(); // S3에 저장된 파일 이름
String uploadImageUrl = putS3(uploadFile, fileName); // s3로 업로드
removeNewFile(uploadFile);
return uploadImageUrl;
}
// S3로 업로드
private String putS3(File uploadFile, String fileName) {
amazonS3Client.putObject(new PutObjectRequest(bucket, fileName, uploadFile).withCannedAcl(CannedAccessControlList.PublicRead));
return amazonS3Client.getUrl(bucket, fileName).toString();
}
// 로컬에 저장된 이미지 지우기
private void removeNewFile(File targetFile) {
if (targetFile.delete()) {
System.out.println("File delete success");
return;
}
System.out.println("File delete fail");
}
// 로컬에 파일 업로드 하기
private Optional<File> convert(MultipartFile file) throws IOException {
File convertFile = new File(System.getProperty("user.dir") + "/" + file.getOriginalFilename());
if (convertFile.createNewFile()) { // 바로 위에서 지정한 경로에 File이 생성됨 (경로가 잘못되었다면 생성 불가능)
try (FileOutputStream fos = new FileOutputStream(convertFile)) { // FileOutputStream 데이터를 파일에 바이트 스트림으로 저장하기 위함
fos.write(file.getBytes());
}
return Optional.of(convertFile);
}
return Optional.empty();
}
}
이미지를 MultipartFile 타입으로 받아오고 S3에 업로드 하기 위해 로컬에 저장했다가 삭제하는 로직등이 들어있다.
@PostMapping("/posts")
public GlobalResponseDto createPost(@RequestPart(value = "img", required = false) MultipartFile multipartFile,
@RequestPart(value = "post") @Valid PostRequestDto postRequestDto,
@AuthenticationPrincipal UserDetailsImpl userDetails) throws IOException {
if (userDetails==null){
throw new CustomException(ErrorCode.NotFoundToken);
}
return postService.createPost(multipartFile, postRequestDto, userDetails.getAccount());
}
String img = s3Uploader.uploadFiles(multipartFile, "testdir1");
급하게 구현하는데는 성공했지만 request를 formData형식으로 받을 때 Json을 따로받는것 보다 항목 하나하나를 key:value로 받는 것이 일반적이라고 한다.
이러한 부분들에 대해 조금더 구현해봐야겠다.
다음을 참고하여 진행하였다.
https://velog.io/@_koiil/Springboot-AWS-S3%EB%A1%9C-%ED%8C%8C%EC%9D%BC-%EC%A0%80%EC%9E%A5%EC%86%8C-%EC%97%B0%EB%8F%99%ED%95%98%EA%B8%B0
https://studyandwrite.tistory.com/498