사진 업로드를 할 수 있는 외주 작업을 맡게 되어 S3를 이용한 이미지 업로드 로직을 작성했습니다.
요구사항
- 게시물에 이미지는 필수값이 아니다.
- 하나의 게시물에 올릴 수 있는 파일 수는 최대 3개이다.
위 요구사항에 맞춰 먼저, S3를 사용하기 위한 코드를 작성해보도록 하겠습니다.
1. AWS S3에 bucket을 생성
2. bucket, accessKey, secretKey 정보를 application.yml에 추가
cloud:
aws:
s3:
bucket: 버킷이름
stack.auto: false
region.static: ap-northeast-2
credentials:
accessKey: 본인 키 입력
secretKey: 본인 키 입력
3. S3Config 파일 작성
package com.example.pet.file;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class S3Config {
@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 awsCredentials = new BasicAWSCredentials(accessKey, secretKey);
return (AmazonS3Client) AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
.build();
}
}
4. S3Service 파일에 파일 업로드 로직 작성
단일 파일 업로드
@Service
@RequiredArgsConstructor
@Slf4j
public class S3Service {
private final AmazonS3Client amazonS3Client;
@Value("${cloud.aws.s3.bucket}")
private String bucket;
@Value("${cloud.aws.region.static}")
private String region;
// 단일 파일 업로드 로직
public String uploadFile(MultipartFile file) throws IOException {
try {
String URL = "https://" + bucket + ".s3." + region + ".amazonaws.com/";
String folderDir = bucket;
String savedName = createSaveName(file.getOriginalFilename());
String fileUrl = URL + savedName;
ObjectMetadata metaData = new ObjectMetadata();
metaData.setContentType(file.getContentType());
metaData.setContentLength(file.getSize());
amazonS3Client.putObject(folderDir, savedName, file.getInputStream(), metaData);
return fileUrl;
} catch (IOException e) {
throw new BusinessException(FILE_UPLOAD_FAILED);
}
}
// UUID를 사용하여 unique한 파일명 만들기
private String createSaveName(String originalName) {
String ext = extractExt(originalName);
String uuid = UUID.randomUUID().toString();
return uuid + "." + ext;
}
// 파일 확장명 추출
private String extractExt(String originalName) {
int pos = originalName.lastIndexOf(".");
return originalName.substring(pos + 1);
}
}
하나의 파일을 업로드 하는 로직입니다.
저는 파일 확장명을 UUID로 만들어진 파일명 뒤에 붙여 파일명을 만들어줬고, 버킷 폴더 안에 파일을 저장하도록 했습니다.
여러 파일 업로드
public FileDto uploadFiles(List<MultipartFile> files) {
// 파일 개수 검증 (의뢰자의 요구사항)
validateFileSize(files);
// 이미지를 올리지 않았을 경우 빈 리스트 return
if (files == null) {
return FileDto.toDto(new ArrayList<>());
}
// 여러 파일 업로드
List<String> urls = files.stream().map(file -> {
try {
return uploadFile(file);
} catch (IOException e) {
throw new BusinessException(FILE_UPLOAD_FAILED);
}
}).collect(Collectors.toList());
return FileDto.toDto(urls);
}
private void validateFileSize(List<MultipartFile> files) {
if (files != null && files.size() > 3) {
throw new BusinessException(TOO_MANY_FILES);
}
}
파일이 3장을 초과하는지 먼저 검증하였으며, 이미지를 올리지 않았을 경우 빈 리스트를 반환했습니다.
그리고 map을 사용하여 List 에 들어있는 파일들을 uploadFile에 적용하였습니다.
☝️ MultipartFile
여기서 사용한 MultipartFile은 여러 파일을 쉽게 처리할 수 있게 해주는 것입니다. 파일 내용은 메모리나 디스크에 일시적으로 저장되며, 요청이 끝나면 지워집니다. 해당 파일은 DB나 세션으로 저장할 수 있습니다.
5. Controller 작성
이미지를 포함하여 게시물을 작성하는 방법에는 2가지 방법이 있습니다.
1) 이미지 업로드 API와 글쓰기 API 따로 생성하기
2024.06.13 - [서버 공부] - [스프링] 글 작성 API : 이미지 업로드 API와 글쓰기 API 따로 생성하기
[스프링] 글 작성 API : 이미지 업로드 API와 글쓰기 API 따로 생성하기
보통 한 페이지에 하나의 API를 요청하는 게 좋지만, 그럴 경우 form-data로 List과 JSON 데이터를 한 번에 받아야 합니다. 플러터 같은 경우, form-data에 두 가지 타입의 데이터를 받는 게 어렵다고 하
hy5sun.tistory.com
2) 글쓰기 API 하나로 진행하기\
2024.06.25 - [서버 공부] - [스프링] 이미지와 함께 게시물 작성하기
[스프링] 이미지와 함께 게시물 작성하기
이번에는 이미지 업로드와 json 타입의 Request Dto 데이터 값을 동시에 받아 글을 작성하는 API 코드를 소개하겠습니다. S3를 사용하여 이미지를 업로드하는 코드는 이전 게시물에 올려뒀습니다! 먼
hy5sun.tistory.com
글이 길어질 것 같아, 위 2가지 방법은 따로 글을 올리겠습니다!
글 읽어주셔서 감사합니다.
아직 부족한 부분이 많으니, 피드백 주시면 정말 감사하겠습니다!
'서버 공부' 카테고리의 다른 글
| [스프링] 이미지와 함께 게시물 작성하기 (0) | 2024.06.25 |
|---|---|
| [스프링] 글 작성 API : 이미지 업로드 API와 글쓰기 API 따로 생성하기 (0) | 2024.06.13 |
| [스프링] org.springframework.web.multipart.MultipartException: Failed to parse multipart servlet request 해결 방법 (0) | 2024.06.13 |
| [스프링] @NoArgsConstructor & @AllArgsConstructor & @RequiredArgsConstructor (3) | 2024.06.02 |
| Access Token & Refresh Token (0) | 2024.05.30 |