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