[SpringBoot] AWS S3 이미지 업로드 - 1Spring2023. 5. 26. 06:29
Table of Contents
728x90
728x90
토이 프로젝트를 하면서 기록 남겨놓으면 좋을것 같아서 포스팅
AWS 가입, AWS S3 BUCKET 생성과 IAM KEY 발급 과정은 생략하겠음.
트러블 슈팅
개발 환경
SpringBoot3.0.6
build.gradle DI
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
aplication.properties
# S3
cloud.aws.credentials.accessKey=YourKey
cloud.aws.credentials.secretKey=YourKey
cloud.aws.s3.bucket=YourBucket
cloud.aws.s3.domain=YourDomain
cloud.aws.region.static=ap-northeast-2
cloud.aws.stack.auto=false
Config 생성
package com.uu.uni.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
@Configuration
public class S3Config {
@Value("${cloud.aws.credentials.accessKey}")
private String accessKey;
@Value("${cloud.aws.credentials.secretKey}")
private String secretKey;
@Value("${cloud.aws.region.static}")
private String region;
@Bean
public AmazonS3 amazonS3Client() {
AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
return AmazonS3ClientBuilder
.standard()
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.withRegion(region)
.build();
}
}
Uploader 객체 생성
로컬에 생성되는 이미지 파일은 삭제된다.(MultipartFile을 File로 전환하는 과정에서 파일이 생성된다.)
AmazonS3Client가 deprecated되어, AmazonS3을 사용했다 (필드)
package com.uu.uni.user.service;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.PutObjectRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Optional;
@Slf4j
@RequiredArgsConstructor
@Component
@Service
public class S3Uploader {
private final AmazonS3 amazonS3Client;
@Value("${cloud.aws.s3.bucket}")
private String bucket;
public String upload(MultipartFile multipartFile, String dirName) throws IOException {
File uploadFile = convert(multipartFile)
.orElseThrow(() -> new IllegalArgumentException("MultipartFile -> File change fail"));
return upload(uploadFile, dirName);
}
private String upload(File uploadFile, String dirName) {
String fileName = dirName + "/" + uploadFile.getName();
String uploadImageUrl = putS3(uploadFile, fileName);
removeNewFile(uploadFile);
return uploadImageUrl;
}
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()) {
log.info("delete success.");
}else {
log.info("delete fail.");
}
}
private Optional<File> convert(MultipartFile file) throws IOException {
File convertFile = new File(file.getOriginalFilename());
if(convertFile.createNewFile()) {
try (FileOutputStream fos = new FileOutputStream(convertFile)) {
fos.write(file.getBytes());
}
return Optional.of(convertFile);
}
return Optional.empty();
}
}
View, Controller, Service 작성
1. View + JS (파일 보내기)
<form th:method="post" th:action="@{|/users/img/${idx}|}" name="imgchange" enctype="multipart/form-data">
<input type="file" name="imgfile" style="display : none;">
<input type="hidden" name="idx" th:value="${idx}">
<input type="hidden" name="img">
</form>
const img_upload = document.querySelector(".img_upload");
const input_file = document.querySelector("input[type='file']");
const filename = document.querySelector("input[name='img']");
function imgUpload(){
input_file.click();
}
img_upload.addEventListener('click', function(){
imgUpload();
});
input_file.addEventListener('change', function(){
filename.value = this.files[0];
document.imgchange.submit();
});
2. Controller, Service
@ResponseBody
@PostMapping("/img/{idx}")
public String img_modify(@PathVariable int idx, @RequestParam("imgfile") MultipartFile imgfile, UserDTO dto) throws IOException {
if(userService.img_modify(imgfile, dto)) return "성공";
else return "실패";
}
컨트롤러에서, 성공 실패 여부를 확인하기 위해 ResponseBody로 걍 Text를 찍어보려고 했다.
public boolean img_modify(MultipartFile imgfile, UserDTO dto) throws IOException;
@Transactional
@Override
public boolean img_modify(MultipartFile imgfile, UserDTO dto) throws IOException {
if(!imgfile.isEmpty()) {
String uuid = UUID.randomUUID().toString();
String serverFileName = s3Uploader.upload(imgfile, dto.getId()+uuid);
System.out.println(imgfile + " : " + dto.getId()+uuid);
System.out.println("serverFileName : " + serverFileName);
dto.setImg(serverFileName);
Optional<UserEntity> User = userRepository.findByIdx(dto.getIdx());
User.get().setImg(serverFileName);
return true;
}
else return false;
}
서비스에서 위의 S3Uploader를 통해 AWS S3에 업로드 된다.
결과
잘 들어오지만, 업로드 할 때마다 디렉토리가 생성되어, 이를 수정할 생각이다.
728x90
300x250
@mag1c :: 꾸준히 재밌게
2023.04 ~ 백엔드 개발자의 기록
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!