728x90
반응형
1. 버킷 생성
2. build.gradle 의존성 추가
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
3. application.properties 추가
중요한 내용을 담기 때문에 .gitignore에 설정 파일을 추가해준다.
4. S3Config
backend/aws/S3Config
package mobile.backend.aws;
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;
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.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();
}
}
5. WebConfig
Config 파일을 한 곳에서 관리한다면 Class를 추가해준다.
package mobile.backend;
...
@Configuration
@Import({AopConfig.class, RedisConfig.class, S3Config.class})
public class WebConfig implements WebMvcConfigurer {
...
6. S3Uploader
backend/aws/S3Uploader
package mobile.backend.aws;
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.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 // final 멤버변수가 있으면 생성자 항목에 포함시킴
@Service
public class S3Uploader {
private final AmazonS3Client amazonS3Client;
@Value("${cloud.aws.s3.bucket}")
private String bucket;
// MultipartFile을 전달받아 File로 전환한 후 S3에 업로드
public String upload(MultipartFile multipartFile, String dirName) throws IOException {
File uploadFile = convert(multipartFile)
.orElseThrow(() -> new IllegalArgumentException("MultipartFile -> File 전환 실패"));
return upload(uploadFile, dirName);
}
private String upload(File uploadFile, String dirName) {
String fileName = dirName + "/" + uploadFile.getName();
String uploadImageUrl = putS3(uploadFile, fileName);
removeNewFile(uploadFile); // 로컬에 생성된 File 삭제 (MultipartFile -> File 전환 하며 로컬에 파일 생성됨)
return uploadImageUrl; // 업로드된 파일의 S3 URL 주소 반환
}
// 1. 로컬에 파일생성
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();
}
// 2. S3에 파일업로드
private String putS3(File uploadFile, String fileName) {
amazonS3Client.putObject(
new PutObjectRequest(bucket, fileName, uploadFile)
.withCannedAcl(CannedAccessControlList.PublicRead) // PublicRead 권한으로 업로드 됨
);
return amazonS3Client.getUrl(bucket, fileName).toString();
}
// 3. 로컬에 생성된 파일삭제
private void removeNewFile(File targetFile) {
if(targetFile.delete()) {
log.info("파일이 삭제되었습니다.");
}else {
log.info("파일이 삭제되지 못했습니다.");
}
}
// s3 파일 삭제
public void delete(String fileName) {
log.info("File Delete : " + fileName);
amazonS3Client.deleteObject(bucket, fileName);
}
}
7. Controller
클라이언트(React) 에서 보낸 데이터입니다.
const config = {
headers: {
"content-type": "multipart/form-data",
},
};
const formData = new FormData();
formData.append("file_object", fileObject);
await axios.post('/java/file/upload', formData, config)
backend/module/file/FileController
...
@PostMapping("/upload")
public CommonResponse<String> upload(
@RequestParam("file_object") MultipartFile fileObject
) throws IOException {
log.info("multipartFile={}", fileObject);
return new CommonResponse<String>(
true,
service.upload(
fileObject
));
}
...
8. Service
backend/module/file/FileService
...
@Autowired
private S3Uploader s3Uploader;
...
public String upload( MultipartFile fileObject ) throws IOException {
if(fileObject.isEmpty()) {
}
else {
String storedFileName = s3Uploader.upload(fileObject,"images");
log.info("fileName={}", storedFileName);
}
return "ok";
}
9. main 함수 파일에 다음을 추가해준다.
@SpringBootApplication
public class BackendApplication {
static {
System.setProperty("com.amazonaws.sdk.disableEc2Metadata", "true");
}
public static void main(String[] args) {
SpringApplication.run(BackendApplication.class, args);
}
}
서버를 키고 파일 저장을 시도해보면 아래와 같이 성공한 것을 볼 수 있다.
728x90
반응형
'Back-End > Spring Boot' 카테고리의 다른 글
Spring Boot | MockMvc with Spring Security and RestDocs (0) | 2023.02.21 |
---|---|
Spring Boot | Mysql 연동하는 방법 (0) | 2022.11.03 |
Sping Boot | Backend Project | File Upload (0) | 2022.11.01 |
Sping Boot | Backend Project | JWT in Cookie (0) | 2022.10.05 |
Sping Boot | Backend Project | Snake,Camel in Request, Response에 대한 고찰, 섞어서 쓰면 안되는 이유 ( with 사용자 설정 표기법 ) (0) | 2022.09.30 |