Day 48
1. S3
오늘은 S3를 이용해서 이미지를 업로드하고 DB에는 이미지URL을 저장하는 방법을 공부했다.
파일을 저장하는 서비스. Simple Storage Service
사전 준비
- S3 버킷 만들기
- 사용자 추가해서 S3에 등록
- accessKey랑 secretKey 받기
에러
- 환경변수 추가
- Edit Configuration -> build and run에 아래 문구 추가
- Dcom.amazonaws.sdk.disableEc2Metadata=true
- 스프링 부트 용량 제한
스프링 부트는 용량제한이 1MB다. 그래서 1MB 이상의 파일이 들어오면FileSizeLimitExceededException발생
그래서 application.properties에 추가설정 필요
# 파일 용량 제한 해제
spring.servlet.multipart.max-file-size=128MB
spring.servlet.multipart.max-request-size=128MB
spring.servlet.multipart.enabled=true
spring
- build.gradle
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
- application.properties
// access key
cloud.aws.credentials.accessKey=access key값
// secret key
cloud.aws.credentials.secretKey=secret key값
// 버킷 이름
cloud.aws.s3.bucket=버킷 이름
cloud.aws.region.static=ap-northeast-2
cloud.aws.stack.auto-=false
- S3Config
@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();
}
}
- TestController
@RestController
@RequestMapping
@RequiredArgsConstructor
public class TestController {
private final TestService testService;
@PostMapping("/test")
public Long saveFile(@RequestParam(value = "image") MultipartFile image) {
Long testId = testService.keepDiary(image);
return testId;
}
}
- TestService
@Service
@RequiredArgsConstructor
public class TestService {
private final ImageRepository imageRepository;
private final S3Uploader s3Uploader;
@Transactional
public Long keepDiary(MultipartFile image) {
if (!image.isEmpty()) {
String storedFileName = s3Uploader.upload(image, "image");
System.out.println("storedFileName = " + storedFileName);
Image savedImage = imageRepository.save(new Image(storedFileName));
return savedImage.getId();
}
return null;
}
}
- S3Uploader
private final AmazonS3Client amazonS3Client;
@Value("${cloud.aws.s3.bucket}")
private String bucket;
// MultipartFile을 전달받아 File로 전환한 후 S3에 업로드
public String upload(MultipartFile multipartFile, String dirName) {
// multipartFile : 이미지, dirName : image
try {
// 1. mulipartFile을 File로 변환
File uploadFile = convert(multipartFile)
.orElseThrow(() -> new IllegalArgumentException("MultipartFile -> File 전환 실패"));
return upload(uploadFile, dirName);
} catch (IOException e) {
throw new IllegalArgumentException("MultipartFile -> File 전환 실패");
}
}
private Optional<File> convert(MultipartFile file) throws IOException {
// 1-1.multiFile의 이름을 가져와서 새로운 File객체에 입력
File convertFile = new File(file.getOriginalFilename());
// 1-2. convertFile.createNewFile() : convertFile과 같은 이름을 가진 파일이 없으면 생성 후 true반환, 있으면 false반환
if(convertFile.createNewFile()) {
// 1-3. FileOutputStram : byte단위로 파일을 기록하는 클래스 / 파일 생성됨
try (FileOutputStream fos = new FileOutputStream(convertFile)) {
// 1-4.file의 내용을 바이트로 변환해서 반환
fos.write(file.getBytes());
}
return Optional.of(convertFile);
}
return Optional.empty();
}
// 2. uploadFile : File로 변환된 multipartFile, dirName : "image" private String upload(File uploadFile, String dirName) {
// 2-1. fileName(S3 URI)
String fileName = dirName + "/" + uploadFile.getName();
log.info("key : " + fileName);
// 3. uploadImageUrl에 image_url저장, S3에 파일 저장
String uploadImageUrl = putS3(uploadFile, fileName);
log.info("image_url : " + uploadImageUrl);
// 4. 로컬에 생성된 File 삭제 (MultipartFile -> File 전환 하며 로컬에 파일 생성됨)
removeNewFile(uploadFile);
// 5. 업로드된 파일의 S3 URL 주소 반환
return uploadImageUrl;
}
// 3-1. uploadFile : File로 변환된 multipartFile, FileName : key private String putS3(File uploadFile, String fileName) {
amazonS3Client.putObject(
new PutObjectRequest(bucket, fileName, uploadFile)
.withCannedAcl(CannedAccessControlList.PublicRead) // PublicRead 권한으로 업로드 됨
);
// 3-2. S3에 저장 후 URL을 가져와서 반환
return amazonS3Client.getUrl(bucket, fileName).toString();
}
// 4.
private void removeNewFile(File targetFile) {
if(targetFile.delete()) {
log.info("파일이 삭제되었습니다.");
}else {
log.info("파일이 삭제되지 못했습니다.");
}
}
}
/**
== S3Uploader ==
MultipartFile을 전달받아 File로 전환한 후 S3에 업로드
mulipartFile을 File로 변환
1-1. multiFile의 이름을 가져와서 새로운 File객체에 입력
1-2. convertFile.createNewFile() : convertFile과 같은 이름을 가진 파일이 없으면 생성 후 true반환, 있으면 false반환
1-3. FileOutputStram : byte단위로 파일을 기록하는 클래스 / 파일 생성됨
uploadFile : File로 변환된 multipartFile, dirName : "image"
2-1. fileName(S3 URI) * 3. uploadImageUrl(객체URL)에 image_url저장, S3에 파일 저장
3-1. uploadFile : File로 변환된 multipartFile, FileName : key
3-2. S3에 저장 후 URL을 가져와서 반환
로컬에 생성된 File 삭제 (MultipartFile -> File 전환 하며 로컬에 파일 생성됨)
업로드된 파일의 S3 URL 주소 반환
/
'항해99 > TIL | WIL' 카테고리의 다른 글
| 2023.02.27 (49일) (0) | 2023.02.27 |
|---|---|
| WIL (6주) (0) | 2023.02.26 |
| 2023.02.24 (47일) (0) | 2023.02.25 |
| 2023.02.23 (46일) (0) | 2023.02.23 |
| 2023.02.22 (45일) (0) | 2023.02.23 |