diff --git a/src/main/java/com/newzet/api/article/business/service/ArticleService.java b/src/main/java/com/newzet/api/article/business/service/ArticleService.java index 71ce088f..691924c4 100644 --- a/src/main/java/com/newzet/api/article/business/service/ArticleService.java +++ b/src/main/java/com/newzet/api/article/business/service/ArticleService.java @@ -5,7 +5,6 @@ import java.util.UUID; import java.util.stream.Collectors; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -18,29 +17,20 @@ import com.newzet.api.article.domain.Article; import com.newzet.api.article.exception.ShareForbiddenException; import com.newzet.api.article.repository.dto.ArticleWithImageProjection; -import com.newzet.api.common.s3.S3Service; import com.newzet.api.common.util.UuidConverter; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @Slf4j @Service @Transactional(readOnly = true) +@RequiredArgsConstructor public class ArticleService { private final static String ARTICLE_SHARE_PREFIX = "https://app.newzet.me/article"; private final ArticleBatchProducer batchProducer; private final ArticleRepository articleRepository; - private final S3Service s3Service; - private final String contentBucketName; - - public ArticleService(ArticleBatchProducer batchProducer, ArticleRepository articleRepository, - S3Service s3Service, @Value("s3.content-bucket") String contentBucketName) { - this.batchProducer = batchProducer; - this.articleRepository = articleRepository; - this.s3Service = s3Service; - this.contentBucketName = contentBucketName; - } public void saveArticleBatch(UUID userId, String fromName, String fromDomain, String mailingList, String imageUrl, String htmlLink, String title) { @@ -132,10 +122,4 @@ public Article getSharedArticle(UUID articleId) { } throw new ShareForbiddenException("공유가 허용되지 않은 아티클입니다."); } - - public String getContentUrl() { - //TODO(S3에서 Article 조회) - //TODO(getArticle도 바꿔주야함) - return ""; - } } diff --git a/src/main/java/com/newzet/api/article/orchestrator/ArticleOrchestrator.java b/src/main/java/com/newzet/api/article/orchestrator/ArticleOrchestrator.java index f5a7ebad..25fb22eb 100644 --- a/src/main/java/com/newzet/api/article/orchestrator/ArticleOrchestrator.java +++ b/src/main/java/com/newzet/api/article/orchestrator/ArticleOrchestrator.java @@ -9,7 +9,6 @@ import com.newzet.api.article.controller.dto.ArticleContentResponse; import com.newzet.api.article.domain.Article; import com.newzet.api.common.s3.S3Service; -import com.newzet.api.config.s3.S3Config; import lombok.RequiredArgsConstructor; @@ -20,26 +19,18 @@ public class ArticleOrchestrator { private final ArticleService articleService; private final S3Service s3Service; - private final S3Config s3Config; public ArticleContentResponse getSharedArticle(UUID articleId) { Article sharedArticle = articleService.getSharedArticle(articleId); - String articleContent = articleService.getContentUrl(); - return new ArticleContentResponse(sharedArticle.getTitle(), articleContent, + String content = s3Service.getContentAsString(sharedArticle.getContentUrl()); + return new ArticleContentResponse(sharedArticle.getTitle(), content, sharedArticle.isLike()); } public ArticleContentResponse getArticle(UUID articleId) { Article article = articleService.getArticle(articleId); - // S3로부터 본문 HTML를 받아옴 - // contentUrl.html 형태로 접근해서 가져와, content 필드에 주입 - String content = getContentFromS3(article.getContentUrl()); - + String content = s3Service.getContentAsString(article.getContentUrl()); return ArticleContentResponse.of(article.getTitle(), content, article.isLike()); } - - private String getContentFromS3(String key) { - return s3Service.getContentAsString(s3Config.getContentBucketName(), key); - } } diff --git a/src/main/java/com/newzet/api/common/response/ResponseCode.java b/src/main/java/com/newzet/api/common/response/ResponseCode.java index 943e8bb6..0fe62353 100644 --- a/src/main/java/com/newzet/api/common/response/ResponseCode.java +++ b/src/main/java/com/newzet/api/common/response/ResponseCode.java @@ -5,7 +5,6 @@ @Getter @RequiredArgsConstructor -//TODO: 코드 잘못 던지고 있는 부분 수정 public enum ResponseCode { SUCCESS(20000), INVALID_ARGUMENTS(40000), diff --git a/src/main/java/com/newzet/api/common/s3/S3Service.java b/src/main/java/com/newzet/api/common/s3/S3Service.java index dfff0830..8634dd79 100644 --- a/src/main/java/com/newzet/api/common/s3/S3Service.java +++ b/src/main/java/com/newzet/api/common/s3/S3Service.java @@ -11,6 +11,7 @@ import com.amazonaws.services.s3.model.S3Object; import com.amazonaws.services.s3.model.S3ObjectInputStream; import com.newzet.api.common.exception.InternalErrorException; +import com.newzet.api.config.s3.S3Config; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -20,9 +21,10 @@ @Slf4j public class S3Service { private final AmazonS3 amazonS3; + private final S3Config s3Config; - public String getContentAsString(String bucketName, String key) { - GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key); + public String getContentAsString(String key) { + GetObjectRequest getObjectRequest = new GetObjectRequest(s3Config.getContentBucketName(), key); try (S3Object s3Object = amazonS3.getObject(getObjectRequest); S3ObjectInputStream inputStream = s3Object.getObjectContent()) { diff --git a/src/test/java/com/newzet/api/common/s3/S3ServiceTest.java b/src/test/java/com/newzet/api/common/s3/S3ServiceTest.java index 0db24113..81f686b1 100644 --- a/src/test/java/com/newzet/api/common/s3/S3ServiceTest.java +++ b/src/test/java/com/newzet/api/common/s3/S3ServiceTest.java @@ -21,6 +21,7 @@ import com.amazonaws.services.s3.model.S3Object; import com.amazonaws.services.s3.model.S3ObjectInputStream; import com.newzet.api.common.exception.InternalErrorException; +import com.newzet.api.config.s3.S3Config; @ExtendWith(MockitoExtension.class) class S3ServiceTest { @@ -31,6 +32,8 @@ class S3ServiceTest { private S3Service s3Service; @Mock private AmazonS3 amazonS3; // S3Service가 사용하는 SDK v1 클라이언트 + @Mock + private S3Config s3Config; @Nested @DisplayName("성공 케이스") @@ -42,16 +45,16 @@ void getContentAsString_Success() { String expectedContent = "S3 Object Content"; byte[] contentBytes = expectedContent.getBytes(StandardCharsets.UTF_8); - // S3Object와 그 내용을 Mocking S3Object mockS3Object = new S3Object(); S3ObjectInputStream inputStream = new S3ObjectInputStream( new ByteArrayInputStream(contentBytes), null); mockS3Object.setObjectContent(inputStream); + when(s3Config.getContentBucketName()).thenReturn(BUCKET_NAME); when(amazonS3.getObject(any(GetObjectRequest.class))).thenReturn(mockS3Object); // when - String actualContent = s3Service.getContentAsString(BUCKET_NAME, OBJECT_KEY); + String actualContent = s3Service.getContentAsString(OBJECT_KEY); // then assertEquals(expectedContent, actualContent); @@ -65,12 +68,13 @@ class FailureCases { @DisplayName("S3에 해당 Key의 객체가 없으면 InternalErrorException을 던진다") void getContentAsString_ThrowsNoSuchKeyException() { // given + when(s3Config.getContentBucketName()).thenReturn(BUCKET_NAME); when(amazonS3.getObject(any(GetObjectRequest.class))) .thenThrow(new AmazonS3Exception("The specified key does not exist.")); // when & then assertThrows(InternalErrorException.class, () -> { - s3Service.getContentAsString(BUCKET_NAME, OBJECT_KEY); + s3Service.getContentAsString(OBJECT_KEY); }); } @@ -78,20 +82,19 @@ void getContentAsString_ThrowsNoSuchKeyException() { @DisplayName("스트림을 읽는 중 IOException이 발생하면 InternalErrorException을 던진다") void getContentAsString_ThrowsIOException() throws IOException { // given - // S3Object와 InputStream을 각각 Mocking하여 InputStream의 동작을 제어 S3Object mockS3Object = mock(S3Object.class); S3ObjectInputStream mockInputStream = mock(S3ObjectInputStream.class); + when(s3Config.getContentBucketName()).thenReturn(BUCKET_NAME); when(amazonS3.getObject(any(GetObjectRequest.class))).thenReturn(mockS3Object); when(mockS3Object.getObjectContent()).thenReturn(mockInputStream); - // 핵심: InputStream에서 readAllBytes() 호출 시 강제로 IOException 발생 when(mockInputStream.readAllBytes()).thenThrow(new IOException("스트림 읽기 실패")); // when & then assertThrows(InternalErrorException.class, () -> { - s3Service.getContentAsString(BUCKET_NAME, OBJECT_KEY); + s3Service.getContentAsString(OBJECT_KEY); }); } } -} \ No newline at end of file +}