https://grogrammer.tistory.com/66
Spring boot_s3 이미지 업로드 구현(초안)
🏕️기존 상황 이미 S3 버킷은 만들어져 있는 상황이었고 모든 권한을 가진 iam 유저도 1명 있는 상태였다. 그 상황에서 더 추가적으로 필요한 것들을 추가해서 개발하였다. 🔺S3연동을 위해 해
grogrammer.tistory.com
🏕️상황
- 위에 있는 블로그에 쓰여있듯이 지난번에는 이미지가 S3 버킷에 잘 올라가는지 확인하는 용도였다.
(아직 남은 개발 사항이 있는 상태) - 현재 우리 프로젝트에서 이미지를 다루는 부분은 게시판 부분인데, 게시판 쪽 코드와 합쳐서 게시글과 이미지가 하나가 되도록 만들어야 했다. 🔜 현재 완료
- 이미지 1개만 업로드가 가능했는데 다중 이미지 업로드 기능을 구현해야 했다. 언젠가 이미지 1개만으로는 해결이 안 되는 날이 올 거 같아서 하는 김에 한 번에 다중 업로드까지 가능하도록 하였다. 🔜 현재 완료
🧡핵심 코드
public class imageService {
private final AmazonS3Client amazonS3Client;
private final imageRepository repository;
@Value("${cloud.aws.s3.bucket}")
private String bucket;
// MultipartFile을 전달받아 File로 전환한 후 S3에 업로드
public void upload(List<MultipartFile> multipartFileList, Long boardId) throws IOException {
for(MultipartFile multipartFile : multipartFileList) {
if(!multipartFile.isEmpty()){
// 메타데이터 설정
File uploadFile = convert(multipartFile)
.orElseThrow(() -> new IllegalArgumentException("MultipartFile -> File 전환 실패"));
log.info("변환된 이미지 파일 이름: " + uploadFile.getName());
String url = upload(uploadFile, "static");
Image img = new Image(boardId, url);
repository.save(img);
}
}
}
private String upload(File uploadFile, String dirName) {
String fileName = dirName + "/" + UUID.randomUUID() + "." + 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) // PublicRead 권한으로 업로드 됨
);
return amazonS3Client.getUrl(bucket, fileName).toString();
}
private void removeNewFile(File targetFile) {
if(targetFile.delete()) {
log.info("파일이 삭제되었습니다.");
}else {
log.info("파일이 삭제되지 못했습니다.");
}
}
private Optional<File> convert(MultipartFile file) {
File convertFile = new File(file.getOriginalFilename());
try (FileOutputStream fos = new FileOutputStream(convertFile)) {
fos.write(file.getBytes());
} catch (IOException e) {
// 변환에 실패하면 예외 처리
convertFile.delete();
// 예외 메시지와 스택 트레이스를 로그로 출력
log.error("MultipartFile 변환에 실패했습니다: {}", e.getMessage(), e);
return Optional.empty();
}
return Optional.of(convertFile);
}
public void deleteFile(String fileName) {
DeleteObjectRequest request = new DeleteObjectRequest(bucket, fileName);
amazonS3Client.deleteObject(request);
}
public class BoardService {
private final BoardRepository boardRepository;
private final imageService imageService;
// insert
public ResponseDTO<?> create(final Board entity, final List<MultipartFile> imageList) {
try {
validate(entity);
boardRepository.save(entity);
if(imageList.size() != 0){
imageService.upload(imageList, entity.getId());
}
return ResponseDTO.success(boardRepository.findById(entity.getId()));
} catch (Exception e) {
String error = e.getMessage();
return ResponseDTO.fail("Error", error);
}
}
💘후기
- 원래 board 쪽은 다른 팀원이 코드를 개발했다. 내가 맡은 코드를 개발하느라 board 쪽 코드를 들여다보지 못했는데 이번 기회를 통해 board 쪽 코드도 분석하고, 그 코드에 내가 새로 만든 Image 코드를 덧붙였다.
- 그렇게 만들고 나니 뿌듯했다. 이렇게 성공했을 때의 순간을 보고 개발하는 게 아닌가~~ 싶다.
- 이제 업로드 부분은 다 완성했으니 나머지 기능들도 멋지게 완성하고 싶다.
- 코드라는 것도 확실히 보다 보니까 이해가 안 되고, 굉장히 낯선 코드들도 여러 번 반복해서 보니 확 친해진 느낌이 든다.
'개발일지 > 2023_한이음' 카테고리의 다른 글
[spring boot] aws 백엔드 배포하기(1. jar파일로 빌드) (0) | 2023.08.03 |
---|---|
list null(empty)체크하기 (0) | 2023.08.02 |
🤦🏻♀️고민하기 - 어떤 Join 메소드를 사용해야 할까? (0) | 2023.08.01 |
[개발외] 이제부터 완전히 혼자 개발 시작~~ (0) | 2023.07.31 |
@PathVariable, @RequestParam의 차이점 (0) | 2023.07.31 |