Skip to content

Commit

Permalink
#196 refactor: storageService 리팩터링
Browse files Browse the repository at this point in the history
- S3Service를 직접 주입받는 대신 StorageService 인터페이스로 대체
  • Loading branch information
jeongyun1206 committed Dec 18, 2024
1 parent c76607f commit 9b3c710
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 142 deletions.
60 changes: 0 additions & 60 deletions src/main/java/com/drinkeg/drinkeg/S3/AmazonS3Manager.java

This file was deleted.

47 changes: 47 additions & 0 deletions src/main/java/com/drinkeg/drinkeg/S3/S3Manager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.drinkeg.drinkeg.S3;

import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.DeleteObjectRequest;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.drinkeg.drinkeg.apipayLoad.code.status.ErrorStatus;
import com.drinkeg.drinkeg.config.S3Config;
import com.drinkeg.drinkeg.exception.GeneralException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

@Component
@RequiredArgsConstructor
public class S3Manager implements StorageManager {
private final AmazonS3 amazonS3;
private final S3Config s3Config;

@Override
public String uploadFile(MultipartFile file, String keyPath) {
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(file.getSize());

try {
amazonS3.putObject(
new PutObjectRequest(s3Config.getBucket(),
keyPath,
file.getInputStream(),
metadata)
);
} catch (IOException e) {
// 로깅 필요
throw new GeneralException(ErrorStatus.FILE_UPLOAD_FAILED);
}

return amazonS3.getUrl(s3Config.getBucket(), keyPath)
.toString();
}

@Override
public void deleteFile(String keyPath) {
amazonS3.deleteObject(new DeleteObjectRequest(s3Config.getBucket(), keyPath));
}
}
83 changes: 57 additions & 26 deletions src/main/java/com/drinkeg/drinkeg/S3/S3Service.java
Original file line number Diff line number Diff line change
@@ -1,58 +1,89 @@
package com.drinkeg.drinkeg.S3;


import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.DeleteObjectRequest;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.drinkeg.drinkeg.apipayLoad.code.status.ErrorStatus;
import com.drinkeg.drinkeg.config.S3Config;
import com.drinkeg.drinkeg.domain.Uuid;
import com.drinkeg.drinkeg.exception.GeneralException;
import com.drinkeg.drinkeg.repository.UuidRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.extern.slf4j.XSlf4j;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Service
@Transactional
@RequiredArgsConstructor
public class S3Service {


private final AmazonS3Manager s3Manager;
@Slf4j
public class S3Service implements StorageService {
private final UuidRepository uuidRepository;
private final S3Manager s3Manager;

public String SaveImage(MultipartFile image){ //이미지 한개 저장할 때


String uuid = UUID.randomUUID().toString();
Uuid savedUuid = uuidRepository.save(Uuid.builder()
.uuid(uuid).build());

String pictureUrl = s3Manager.uploadFile(s3Manager.generateWineNewsKeyName(savedUuid), image);


return pictureUrl;
private String generateKeyPath(Uuid uuid, String path) {
return path + '/' + uuid.getUuid();
}

public void deleteFile(String pictureUrl){ // 사진 삭제

String savedUuid = pictureUrl.substring(pictureUrl.lastIndexOf("/wineNews/") + "/wineNews/".length());
Uuid uuid = uuidRepository.findByUuid(savedUuid);
public String uploadFile(MultipartFile file, String path) {
try {
Uuid uuid = uuidRepository.save(Uuid.builder()
.uuid(UUID.randomUUID().toString())
.build());

s3Manager.deleteFile(s3Manager.generateWineNewsKeyName(uuid));
String url = s3Manager.uploadFile(file, generateKeyPath(uuid, path));

return url;
} catch (DataIntegrityViolationException e) { // 유니크 제약조건 위반시 발생
throw new GeneralException(ErrorStatus.FILE_UPLOAD_FAILED);
}
}

public void SaveImages(List<MultipartFile> pictureList){ // List로 들어온 multipartFile 이미지 저장
@Transactional
public List<String> uploadFiles(List<MultipartFile> files, String path) {
List<String> FileUrls = new ArrayList<>();
for (MultipartFile file : files) {
try {
Uuid uuid = uuidRepository.save(Uuid.builder()
.uuid(UUID.randomUUID().toString())
.build());

String url = s3Manager.uploadFile(file, generateKeyPath(uuid, path));

FileUrls.add(url);
} catch (DataIntegrityViolationException e) { // 유니크 제약조건 위반시 발생
throw new GeneralException(ErrorStatus.FILE_UPLOAD_FAILED);
}
}
return FileUrls;
}

for(MultipartFile picture : pictureList){ // picture마다 유일한 URL 값 생성
String uuid = UUID.randomUUID().toString();
Uuid savedUuid = uuidRepository.save(Uuid.builder().uuid(uuid).build());
public void deleteFile(String url) {
String keyPath = URI.create(url)
.getPath()
.replaceFirst("^/", "");

String pictureUrl = s3Manager.uploadFile(s3Manager.generateWineNewsKeyName(savedUuid), picture);
String uuid = keyPath.substring(keyPath.lastIndexOf('/') + 1);

try {
uuidRepository.deleteByUuid(uuid);
} catch (RuntimeException e) {
throw new GeneralException(ErrorStatus.FILE_DELETE_FAILED);
}

s3Manager.deleteFile(keyPath);
}
}
}
31 changes: 0 additions & 31 deletions src/main/java/com/drinkeg/drinkeg/S3/S3TestController.java

This file was deleted.

21 changes: 0 additions & 21 deletions src/main/java/com/drinkeg/drinkeg/S3/S3TestUploadDTO.java

This file was deleted.

8 changes: 8 additions & 0 deletions src/main/java/com/drinkeg/drinkeg/S3/StorageManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.drinkeg.drinkeg.S3;

import org.springframework.web.multipart.MultipartFile;

public interface StorageManager {
public String uploadFile(MultipartFile file, String keyPath);
public void deleteFile(String keyPath);
}
11 changes: 11 additions & 0 deletions src/main/java/com/drinkeg/drinkeg/S3/StorageService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.drinkeg.drinkeg.S3;

import org.springframework.web.multipart.MultipartFile;

import java.util.List;

public interface StorageService {
public String uploadFile(MultipartFile file, String path);
public List<String> uploadFiles(List<MultipartFile> files, String path);
public void deleteFile(String fileName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,11 @@ public enum ErrorStatus implements BaseCode {
// WineWishlist Error
WINE_WISHLIST_NOT_FOUND(HttpStatus.BAD_REQUEST, "WINE_WISHLIST4001", "와인 위시리스트가 없습니다."),
WINE_WISHLIST_UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "WINE_WISHLIST4002", "권한이 없는 위시리스트입니다."),
WINE_WISHLIST_ALREADY_EXISTS(HttpStatus.BAD_REQUEST, "WINE_WISHLIST4003", "이미 존재하는 위시리스트입니다.");
WINE_WISHLIST_ALREADY_EXISTS(HttpStatus.BAD_REQUEST, "WINE_WISHLIST4003", "이미 존재하는 위시리스트입니다."),

// Uplodat Error
FILE_UPLOAD_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, "FILE_UPLOAD5001", "파일 업로드에 실패했습니다."),
FILE_DELETE_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, "FILE_UPLOAD5002", "파일 삭제에 실패했습니다.");



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import com.drinkeg.drinkeg.domain.Uuid;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface UuidRepository extends JpaRepository<Uuid,Long> {

Uuid findByUuid(String savedUuid);
Optional<Uuid> findByUuid(String savedUuid);

void deleteByUuid(String savedUuid);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.drinkeg.drinkeg.wine.service;

import com.drinkeg.drinkeg.S3.S3Service;
import com.drinkeg.drinkeg.S3.StorageService;
import com.drinkeg.drinkeg.apipayLoad.code.status.ErrorStatus;
import com.drinkeg.drinkeg.domain.Member;
import com.drinkeg.drinkeg.repository.MemberRepository;
Expand Down Expand Up @@ -30,7 +31,7 @@ public class WineServiceImpl implements WineService {
private final WineRepository wineRepository;
private final MemberRepository memberRepository;

private final S3Service s3Service;
private final StorageService storageService;

@Override
public List<SearchWineResponseDTO> searchWinesByName(String searchName, PrincipalDetail principalDetail) {
Expand Down Expand Up @@ -81,7 +82,7 @@ public void uploadWineImage() throws IOException {

if (imageFile.exists()) {
MultipartFile multipartFile = new CustomMultipartFile(imageFile);
String imageUrl = s3Service.SaveImage(multipartFile);
String imageUrl = storageService.uploadFile(multipartFile, "wine");
wine.updateImageUrl(imageUrl);
wineRepository.save(wine);
}
Expand Down

0 comments on commit 9b3c710

Please sign in to comment.