diff --git a/src/main/java/com/NewsJam/NewsJam/domain/news/converter/NewsConvertor.java b/src/main/java/com/NewsJam/NewsJam/domain/news/converter/NewsConvertor.java index b3d0767..5e0dcb1 100644 --- a/src/main/java/com/NewsJam/NewsJam/domain/news/converter/NewsConvertor.java +++ b/src/main/java/com/NewsJam/NewsJam/domain/news/converter/NewsConvertor.java @@ -43,6 +43,7 @@ public static NewsResponseDTO.NewsViewData toNewsViewData(News news) { .content(news.getNewsContent()) .url(news.getOriginalLink()) .publish_date(news.getPubDate()) + .image_url(news.getImageUrl()) .build(); } @@ -63,7 +64,8 @@ public static NewsResponseDTO.CategoryNewsPage toCategoryNewsPage(Page new .build(); } - public static PickNewsData toPickNewsData(String keyword, NewsViewData pickNews, List recommendNewsData){ + public static PickNewsData toPickNewsData(String keyword, NewsViewData pickNews, + List recommendNewsData) { return PickNewsData.builder() .keyword(keyword) .pickNews(pickNews) @@ -71,8 +73,9 @@ public static PickNewsData toPickNewsData(String keyword, NewsViewData pickNews, .build(); } - public static PickNewsPage toPickNewsPage(List pickNewsDataList, Integer listSize, Long totalElements, Integer totalPage, - Boolean isFirst, Boolean isLast){ + public static PickNewsPage toPickNewsPage(List pickNewsDataList, Integer listSize, Long totalElements, + Integer totalPage, + Boolean isFirst, Boolean isLast) { return PickNewsPage.builder() .pickNewsDataList(pickNewsDataList) .listSize(listSize) diff --git a/src/main/java/com/NewsJam/NewsJam/domain/news/entity/News.java b/src/main/java/com/NewsJam/NewsJam/domain/news/entity/News.java index c27fbae..8ec2392 100644 --- a/src/main/java/com/NewsJam/NewsJam/domain/news/entity/News.java +++ b/src/main/java/com/NewsJam/NewsJam/domain/news/entity/News.java @@ -1,9 +1,6 @@ package com.NewsJam.NewsJam.domain.news.entity; import com.NewsJam.NewsJam.domain.news.enums.NewsCategory; - -import jakarta.persistence.*; - import com.NewsJam.NewsJam.global.entity.BaseEntity; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; @@ -15,14 +12,12 @@ import jakarta.persistence.Id; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; - +import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import java.util.List; - @Entity @Builder @Getter @@ -57,6 +52,9 @@ public class News extends BaseEntity { @OneToMany(mappedBy = "news", cascade = CascadeType.ALL, orphanRemoval = true) List keywordList; + @Column(name = "image_url") + private String imageUrl; + @Column(name = "viewCnt") private Long viewCnt; @@ -67,7 +65,7 @@ public void addKeyword(Keyword keyword) { } public void increaseViewCnt() { - System.out.println("viewCnt = "+viewCnt); + System.out.println("viewCnt = " + viewCnt); this.viewCnt++; } diff --git a/src/main/java/com/NewsJam/NewsJam/domain/news/service/ImageCrawlingService.java b/src/main/java/com/NewsJam/NewsJam/domain/news/service/ImageCrawlingService.java new file mode 100644 index 0000000..d90754b --- /dev/null +++ b/src/main/java/com/NewsJam/NewsJam/domain/news/service/ImageCrawlingService.java @@ -0,0 +1,50 @@ +package com.NewsJam.NewsJam.domain.news.service; + +import com.NewsJam.NewsJam.domain.news.service.dto.NewImageDTO.NewsImageRequestDTO; +import com.NewsJam.NewsJam.domain.news.service.dto.NewImageDTO.NewsImageResponseDTO; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.client.reactive.ReactorClientHttpConnector; +import org.springframework.stereotype.Service; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.netty.http.client.HttpClient; + +@Slf4j +@Service +@RequiredArgsConstructor +public class ImageCrawlingService implements NewsImageService { + @Value("${ai.server.base_url}") + private String baseUrl; + private static WebClient webClient; + + + @Override + public String getImageUrl(String newsUrl) { + if (webClient == null) { + webClient = initWebClient(); + } + + NewsImageRequestDTO request = NewsImageRequestDTO.builder() + .news_url(newsUrl) + .build(); + + return webClient.post() + .uri(baseUrl + "/api/image") + .bodyValue(request) + .retrieve() + .bodyToMono(NewsImageResponseDTO.class) + .block() + .getImageUrl(); + } + + public WebClient initWebClient() { + return WebClient.builder() + .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .clientConnector(new ReactorClientHttpConnector(HttpClient.create())) + .build(); + } + +} diff --git a/src/main/java/com/NewsJam/NewsJam/domain/news/service/NewsImageService.java b/src/main/java/com/NewsJam/NewsJam/domain/news/service/NewsImageService.java new file mode 100644 index 0000000..9d345de --- /dev/null +++ b/src/main/java/com/NewsJam/NewsJam/domain/news/service/NewsImageService.java @@ -0,0 +1,6 @@ +package com.NewsJam.NewsJam.domain.news.service; + +public interface NewsImageService { + + String getImageUrl(String newsUrl); +} diff --git a/src/main/java/com/NewsJam/NewsJam/domain/news/service/dto/NewImageDTO.java b/src/main/java/com/NewsJam/NewsJam/domain/news/service/dto/NewImageDTO.java new file mode 100644 index 0000000..36db75f --- /dev/null +++ b/src/main/java/com/NewsJam/NewsJam/domain/news/service/dto/NewImageDTO.java @@ -0,0 +1,25 @@ +package com.NewsJam.NewsJam.domain.news.service.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; + +public class NewImageDTO { + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class NewsImageRequestDTO { + private String news_url; + } + + @Data + public static class NewsImageResponseDTO { + @JsonProperty("image_url") + private String imageUrl; + } + +} diff --git a/src/main/java/com/NewsJam/NewsJam/domain/news/service/scheduler/NewsSchedulerService.java b/src/main/java/com/NewsJam/NewsJam/domain/news/service/scheduler/NewsSchedulerService.java index d57dd3f..d0e1de3 100644 --- a/src/main/java/com/NewsJam/NewsJam/domain/news/service/scheduler/NewsSchedulerService.java +++ b/src/main/java/com/NewsJam/NewsJam/domain/news/service/scheduler/NewsSchedulerService.java @@ -6,6 +6,7 @@ import com.NewsJam.NewsJam.domain.news.entity.News; import com.NewsJam.NewsJam.domain.news.enums.NewsCategory; import com.NewsJam.NewsJam.domain.news.repository.NewsRepository; +import com.NewsJam.NewsJam.domain.news.service.NewsImageService; import com.NewsJam.NewsJam.domain.news.service.NewsService; import com.NewsJam.NewsJam.domain.news.service.NewsVectorService; import com.NewsJam.NewsJam.domain.news.service.TrendKeywordService; @@ -37,6 +38,7 @@ public class NewsSchedulerService { private final NewsVectorService newsVectorService; private final NewsRepository newsRepository; private final ChatBotService chatBotService; + private final NewsImageService newsImageService; private static Queue newsIdQueue = new LinkedList<>(); private static List wordList = new ArrayList<>(); @@ -92,9 +94,11 @@ private void saveNews(List news) { NewsCategory category = chatBotService.getNewsCategory(newsData.getTitle()); + String image_url = newsImageService.getImageUrl(newsData.getOriginalLink()); + VectorizeResponseDTO vectorizeResponseDTO = vectorizeNews(newsData, category); - News saved = saveNewsEntity(newsData, vectorizeResponseDTO, category); + News saved = saveNewsEntity(newsData, vectorizeResponseDTO, category, image_url); newsIdQueue.offer(saved.getId()); @@ -129,7 +133,7 @@ private VectorizeResponseDTO vectorizeNews(NewsData newsData, NewsCategory categ } private News saveNewsEntity(NewsData newsData, VectorizeResponseDTO vectorizeResponseDTO, - NewsCategory newsCategory) { + NewsCategory newsCategory, String imageUrl) { News newsCreate = News.builder() .newsTitle(newsData.getTitle()) .newsContent(newsData.getDescription()) @@ -138,6 +142,7 @@ private News saveNewsEntity(NewsData newsData, VectorizeResponseDTO vectorizeRes .pubDate(newsData.getPubDate()) .vectorIdx(vectorizeResponseDTO.getVectorIdx()) .viewCnt(0L) + .imageUrl(imageUrl) .keywordList(new ArrayList<>()) .build(); diff --git a/src/main/java/com/NewsJam/NewsJam/domain/news/web/dto/NewsAPIResponseDto.java b/src/main/java/com/NewsJam/NewsJam/domain/news/web/dto/NewsAPIResponseDto.java index 42446b1..1df9224 100644 --- a/src/main/java/com/NewsJam/NewsJam/domain/news/web/dto/NewsAPIResponseDto.java +++ b/src/main/java/com/NewsJam/NewsJam/domain/news/web/dto/NewsAPIResponseDto.java @@ -11,7 +11,7 @@ public class NewsAPIResponseDto { @AllArgsConstructor @NoArgsConstructor @Builder - public static class NewsData{ + public static class NewsData { String Description; String title; String pubDate; diff --git a/src/main/java/com/NewsJam/NewsJam/domain/news/web/dto/NewsResponseDTO.java b/src/main/java/com/NewsJam/NewsJam/domain/news/web/dto/NewsResponseDTO.java index dcacd19..0fdaf83 100644 --- a/src/main/java/com/NewsJam/NewsJam/domain/news/web/dto/NewsResponseDTO.java +++ b/src/main/java/com/NewsJam/NewsJam/domain/news/web/dto/NewsResponseDTO.java @@ -5,10 +5,8 @@ import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; -import lombok.Data; import lombok.Getter; import lombok.NoArgsConstructor; -import org.springframework.scheduling.annotation.Scheduled; @Schema(title = "NewsResponseDTO", description = "뉴스 데이터 응답 DTO") public class NewsResponseDTO { @@ -68,6 +66,8 @@ public static class NewsViewData { private String publish_date; @Schema(description = "뉴스 원본 링크", example = "https://www.pressian.com/pages/articles/2024110113442365418?utm_source=naver&utm_medium=search") private String url; + @Schema(description = "뉴스 메인 이미지 URL, 없을 경우 null", example = "https://www.elle.co.kr/resources/online/thumbnail/hf/2024/11/05/04bb9006-d171-4609-8d45-425f00870c9a.jpg") + private String image_url; } @Builder @@ -96,7 +96,7 @@ public static class CategoryNewsPage { @Getter @NoArgsConstructor @AllArgsConstructor - public static class PickNewsPage{ + public static class PickNewsPage { @Schema(description = "Pick 뉴스 데이터 목록") private List pickNewsDataList; @Schema(description = "페이지 내 데이터 수", example = "3") @@ -115,7 +115,7 @@ public static class PickNewsPage{ @Getter @NoArgsConstructor @AllArgsConstructor - public static class PickNewsData{ + public static class PickNewsData { @Schema(description = "뉴스 키워드") public String keyword;