From 105e28db54de3064b09853f5d0c96fa321908217 Mon Sep 17 00:00:00 2001 From: yeonjy Date: Wed, 20 Mar 2024 14:53:25 +0900 Subject: [PATCH 1/7] =?UTF-8?q?feat:=20NewsMapper=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/core/build.gradle | 6 +++--- .../backend/domain/news/mapper/NewsMapper.java | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 backend/core/src/main/java/com/rollthedice/backend/domain/news/mapper/NewsMapper.java diff --git a/backend/core/build.gradle b/backend/core/build.gradle index b04a3634..b7f74397 100644 --- a/backend/core/build.gradle +++ b/backend/core/build.gradle @@ -33,11 +33,11 @@ dependencies { runtimeOnly 'com.h2database:h2' runtimeOnly 'com.mysql:mysql-connector-j' implementation 'org.springframework.boot:spring-boot-starter-amqp' + implementation 'org.mapstruct:mapstruct:1.5.5.Final' + implementation 'org.jsoup:jsoup:1.15.3' annotationProcessor 'org.projectlombok:lombok' - - // jsoup 의존성 추가 - implementation 'org.jsoup:jsoup:1.15.3' + annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/news/mapper/NewsMapper.java b/backend/core/src/main/java/com/rollthedice/backend/domain/news/mapper/NewsMapper.java new file mode 100644 index 00000000..1c29d5d9 --- /dev/null +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/news/mapper/NewsMapper.java @@ -0,0 +1,12 @@ +package com.rollthedice.backend.domain.news.mapper; + +import com.rollthedice.backend.domain.news.dto.response.NewsResponse; +import com.rollthedice.backend.domain.news.entity.News; +import org.mapstruct.Mapper; +import org.mapstruct.MappingConstants.ComponentModel; + +@Mapper(componentModel = ComponentModel.SPRING) +public interface NewsMapper { + + NewsResponse toResponse(final News news, boolean isBookmarked); +} From b5d7bcccde0361b0c13dfdb549daa1a4ba00881e Mon Sep 17 00:00:00 2001 From: yeonjy Date: Wed, 20 Mar 2024 14:57:39 +0900 Subject: [PATCH 2/7] =?UTF-8?q?feat:=20NewsController=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../news/controller/NewsController.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 backend/core/src/main/java/com/rollthedice/backend/domain/news/controller/NewsController.java diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/news/controller/NewsController.java b/backend/core/src/main/java/com/rollthedice/backend/domain/news/controller/NewsController.java new file mode 100644 index 00000000..f62ac8bb --- /dev/null +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/news/controller/NewsController.java @@ -0,0 +1,24 @@ +package com.rollthedice.backend.domain.news.controller; + +import com.rollthedice.backend.domain.crawling.NewsCrawlingService; +import com.rollthedice.backend.domain.news.dto.response.NewsResponse; +import com.rollthedice.backend.domain.news.service.NewsService; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequiredArgsConstructor +@RequestMapping("news") +public class NewsController { + private final NewsService newsService; + + @ResponseStatus(HttpStatus.OK) + @GetMapping("") + public List getNews(final Pageable pageable) { + return newsService.getNews(pageable); + } +} From ce97f1be9f75fadf56157b60f68733e6868d7963 Mon Sep 17 00:00:00 2001 From: yeonjy Date: Wed, 20 Mar 2024 15:00:17 +0900 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20=EC=9A=94=EC=95=BD=EB=90=9C=20?= =?UTF-8?q?=EB=89=B4=EC=8A=A4=20=EC=A1=B0=ED=9A=8C=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20&=20News=20=EC=A1=B0=ED=9A=8C=EC=88=98=20?= =?UTF-8?q?=EC=BB=AC=EB=9F=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../news/dto/response/NewsResponse.java | 23 ++++++++++++++++ .../backend/domain/news/entity/News.java | 10 +++++++ .../domain/news/service/NewsService.java | 27 ++++++++++++++++--- 3 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 backend/core/src/main/java/com/rollthedice/backend/domain/news/dto/response/NewsResponse.java diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/news/dto/response/NewsResponse.java b/backend/core/src/main/java/com/rollthedice/backend/domain/news/dto/response/NewsResponse.java new file mode 100644 index 00000000..538aec9a --- /dev/null +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/news/dto/response/NewsResponse.java @@ -0,0 +1,23 @@ +package com.rollthedice.backend.domain.news.dto.response; + +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Lob; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class NewsResponse { + private Long id; + private String title; + private String content; + private String thumbnail; + private String postDate; + private Boolean isBookmarked; +} diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/news/entity/News.java b/backend/core/src/main/java/com/rollthedice/backend/domain/news/entity/News.java index 09fe35a3..5a69e036 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/news/entity/News.java +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/news/entity/News.java @@ -6,7 +6,10 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.hibernate.annotations.ColumnDefault; +@Slf4j @Getter @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) @@ -24,6 +27,9 @@ public class News extends BaseTimeEntity { private String category; private String postDate; + @ColumnDefault("0L") + private long views; + @Builder public News(String url, String thumbnailUrl) { this.url = url; @@ -31,6 +37,7 @@ public News(String url, String thumbnailUrl) { } public void addNewsBody(String title, String content, String category, String postDate) { + log.info("now category name: {}", category); this.title = title; this.content = content; this.category = category; @@ -41,4 +48,7 @@ public void updateSummarizedContent(String content) { this.content = content; } + public void increaseView() { + views++; + } } diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/news/service/NewsService.java b/backend/core/src/main/java/com/rollthedice/backend/domain/news/service/NewsService.java index d92bc0f7..29099278 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/news/service/NewsService.java +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/news/service/NewsService.java @@ -1,25 +1,37 @@ package com.rollthedice.backend.domain.news.service; +import com.rollthedice.backend.domain.bookmark.entity.Bookmark; +import com.rollthedice.backend.domain.bookmark.service.BookmarkService; +import com.rollthedice.backend.domain.member.entity.Member; +import com.rollthedice.backend.domain.member.query.AuthService; import com.rollthedice.backend.domain.news.contentqueue.ContentProducer; import com.rollthedice.backend.domain.news.dto.ContentMessageDto; import com.rollthedice.backend.domain.news.dto.NewsUrlDto; +import com.rollthedice.backend.domain.news.dto.response.NewsResponse; import com.rollthedice.backend.domain.news.entity.News; +import com.rollthedice.backend.domain.news.mapper.NewsMapper; import com.rollthedice.backend.domain.news.repository.NewsRepository; import jakarta.persistence.EntityNotFoundException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; @Slf4j @Service @RequiredArgsConstructor public class NewsService { - private final NewsRepository newsRepository; + private final AuthService authService; private final ContentProducer contentProducer; + private final NewsRepository newsRepository; + private final NewsMapper newsMapper; + private final BookmarkService bookmarkService; + @Transactional public void addNews(NewsUrlDto dto) { @@ -27,8 +39,8 @@ public void addNews(NewsUrlDto dto) { } @Transactional(readOnly = true) - public List getAllNews() { - return newsRepository.findAll(); + public List getNotCrawled() { + return newsRepository.findAllByContentIsNull(); } @Transactional @@ -45,4 +57,13 @@ public void summarizeNewsContent() { messages.add(new ContentMessageDto(n.getId(), n.getContent()))); messages.forEach(contentProducer::sendMessage); } + + @Transactional(readOnly = true) + public List getNews(final Pageable pageable) { + Member member = authService.getMember(); + return newsRepository.findAllByOrderByViewsDescCreatedAtDesc(pageable).stream() + .map(news -> newsMapper.toResponse( + news, bookmarkService.isBookmarked(member, news))) + .collect(Collectors.toList()); + } } From a222a7d7e252e51eda797f5cfaca3a5807002d2c Mon Sep 17 00:00:00 2001 From: yeonjy Date: Wed, 20 Mar 2024 15:04:32 +0900 Subject: [PATCH 4/7] =?UTF-8?q?fix:=20=ED=81=AC=EB=A1=A4=EB=A7=81=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20@Transactional=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/domain/crawling/NewsCrawlingService.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/crawling/NewsCrawlingService.java b/backend/core/src/main/java/com/rollthedice/backend/domain/crawling/NewsCrawlingService.java index a0daaa44..461267c5 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/crawling/NewsCrawlingService.java +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/crawling/NewsCrawlingService.java @@ -12,6 +12,7 @@ import org.jsoup.select.Elements; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.io.IOException; import java.util.Objects; @@ -26,6 +27,7 @@ public class NewsCrawlingService { private final NewsService newsService; + @Transactional @Scheduled(cron = CRON, zone = ZONE) public void scrap() throws IOException { for (NewsCategory category : NewsCategory.values()) { @@ -33,7 +35,7 @@ public void scrap() throws IOException { String categoryName = category.getName(); scrapNewsUrls(categoryUrl); - for (final News news : newsService.getAllNews()) { + for (final News news : newsService.getNotCrawled()) { scrapNewsContentsAndUpdate(categoryName, news); } } @@ -61,7 +63,8 @@ private String scrapThumbnailUrl(final Element news) { } } - private void scrapNewsContentsAndUpdate(String categoryName, News news) throws IOException { + @Transactional + public void scrapNewsContentsAndUpdate(String categoryName, News news) throws IOException { Document doc = Jsoup.connect(news.getUrl()).get(); String title = scrapTitle(doc); From 4be8b1a0a228df787d0feeca34c787bdd3b372f0 Mon Sep 17 00:00:00 2001 From: yeonjy Date: Wed, 20 Mar 2024 15:05:41 +0900 Subject: [PATCH 5/7] =?UTF-8?q?feat:=20=EB=B6=81=EB=A7=88=ED=81=AC?= =?UTF-8?q?=EB=90=9C=20=EB=89=B4=EC=8A=A4=20=EC=A1=B0=ED=9A=8C=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20&=20Bookmark=20=EB=8F=84=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/BookmarkController.java | 27 +++++++++++++++++++ .../{news => bookmark}/entity/Bookmark.java | 3 ++- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 backend/core/src/main/java/com/rollthedice/backend/domain/bookmark/controller/BookmarkController.java rename backend/core/src/main/java/com/rollthedice/backend/domain/{news => bookmark}/entity/Bookmark.java (85%) diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/bookmark/controller/BookmarkController.java b/backend/core/src/main/java/com/rollthedice/backend/domain/bookmark/controller/BookmarkController.java new file mode 100644 index 00000000..eaa46e34 --- /dev/null +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/bookmark/controller/BookmarkController.java @@ -0,0 +1,27 @@ +package com.rollthedice.backend.domain.bookmark.controller; + +import com.rollthedice.backend.domain.bookmark.service.BookmarkService; +import com.rollthedice.backend.domain.news.dto.response.NewsResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequiredArgsConstructor +@RequestMapping("bookmark") +public class BookmarkController { + private final BookmarkService bookmarkService; + + @ResponseStatus(HttpStatus.OK) + @GetMapping("") + public List getBookmarked(final Pageable pageable) { + return bookmarkService.getBookmarkedNews(pageable); + } + +} diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/news/entity/Bookmark.java b/backend/core/src/main/java/com/rollthedice/backend/domain/bookmark/entity/Bookmark.java similarity index 85% rename from backend/core/src/main/java/com/rollthedice/backend/domain/news/entity/Bookmark.java rename to backend/core/src/main/java/com/rollthedice/backend/domain/bookmark/entity/Bookmark.java index 2d9e8f68..d0314627 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/news/entity/Bookmark.java +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/bookmark/entity/Bookmark.java @@ -1,6 +1,7 @@ -package com.rollthedice.backend.domain.news.entity; +package com.rollthedice.backend.domain.bookmark.entity; import com.rollthedice.backend.domain.member.entity.Member; +import com.rollthedice.backend.domain.news.entity.News; import com.rollthedice.backend.global.config.BaseTimeEntity; import jakarta.persistence.*; import lombok.AccessLevel; From 4061cb5f778d853215275626e0022c29dcd9f1c4 Mon Sep 17 00:00:00 2001 From: yeonjy Date: Wed, 20 Mar 2024 15:11:04 +0900 Subject: [PATCH 6/7] =?UTF-8?q?feat:=20BookmarkService=20&=20Repository=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/BookmarkRepository.java | 17 ++++++++ .../bookmark/service/BookmarkService.java | 39 +++++++++++++++++++ .../news/repository/NewsRepository.java | 8 ++++ 3 files changed, 64 insertions(+) create mode 100644 backend/core/src/main/java/com/rollthedice/backend/domain/bookmark/repository/BookmarkRepository.java create mode 100644 backend/core/src/main/java/com/rollthedice/backend/domain/bookmark/service/BookmarkService.java diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/bookmark/repository/BookmarkRepository.java b/backend/core/src/main/java/com/rollthedice/backend/domain/bookmark/repository/BookmarkRepository.java new file mode 100644 index 00000000..76773a78 --- /dev/null +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/bookmark/repository/BookmarkRepository.java @@ -0,0 +1,17 @@ +package com.rollthedice.backend.domain.bookmark.repository; + +import com.rollthedice.backend.domain.member.entity.Member; +import com.rollthedice.backend.domain.bookmark.entity.Bookmark; +import com.rollthedice.backend.domain.news.entity.News; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface BookmarkRepository extends JpaRepository { + Boolean existsBookmarkByMemberAndNews(Member member, News news); + + List findAllByMemberOrderByCreatedAt(Member member, Pageable pageable); +} diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/bookmark/service/BookmarkService.java b/backend/core/src/main/java/com/rollthedice/backend/domain/bookmark/service/BookmarkService.java new file mode 100644 index 00000000..2a938a13 --- /dev/null +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/bookmark/service/BookmarkService.java @@ -0,0 +1,39 @@ +package com.rollthedice.backend.domain.bookmark.service; + +import com.rollthedice.backend.domain.bookmark.repository.BookmarkRepository; +import com.rollthedice.backend.domain.member.entity.Member; +import com.rollthedice.backend.domain.member.query.AuthService; +import com.rollthedice.backend.domain.news.dto.response.NewsResponse; +import com.rollthedice.backend.domain.news.entity.News; +import com.rollthedice.backend.domain.news.mapper.NewsMapper; +import com.rollthedice.backend.domain.news.service.NewsService; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +@Service +public class BookmarkService { + private final AuthService authService; + private final BookmarkRepository bookmarkRepository; + private final NewsMapper newsMapper; + + + public boolean isBookmarked(Member member, News news) { + return bookmarkRepository.existsBookmarkByMemberAndNews(member, news); + } + + @Transactional(readOnly = true) + public List getBookmarkedNews(Pageable pageable) { + Member member = authService.getMember(); + return bookmarkRepository.findAllByMemberOrderByCreatedAt(member, pageable).stream() + .map(bookmark -> newsMapper.toResponse(bookmark.getNews(), true)) + .collect(Collectors.toList()); + + } +} + diff --git a/backend/core/src/main/java/com/rollthedice/backend/domain/news/repository/NewsRepository.java b/backend/core/src/main/java/com/rollthedice/backend/domain/news/repository/NewsRepository.java index a3fc0151..b70a295a 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/domain/news/repository/NewsRepository.java +++ b/backend/core/src/main/java/com/rollthedice/backend/domain/news/repository/NewsRepository.java @@ -1,7 +1,15 @@ package com.rollthedice.backend.domain.news.repository; import com.rollthedice.backend.domain.news.entity.News; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.List; + +@Repository public interface NewsRepository extends JpaRepository { + List findAllByContentIsNull(); + List findAllByOrderByViewsDescCreatedAtDesc( + final Pageable pageable); } From 8c6031a35896de5ea6972dcd4c1b7f7dfc78b08d Mon Sep 17 00:00:00 2001 From: yeonjy Date: Wed, 20 Mar 2024 15:12:01 +0900 Subject: [PATCH 7/7] =?UTF-8?q?refactor:=20login=20page=20=EC=A7=81?= =?UTF-8?q?=EC=A0=91=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/rollthedice/backend/global/config/SecurityConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/core/src/main/java/com/rollthedice/backend/global/config/SecurityConfig.java b/backend/core/src/main/java/com/rollthedice/backend/global/config/SecurityConfig.java index a5f5cd65..c006cc78 100644 --- a/backend/core/src/main/java/com/rollthedice/backend/global/config/SecurityConfig.java +++ b/backend/core/src/main/java/com/rollthedice/backend/global/config/SecurityConfig.java @@ -53,6 +53,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { -> authorizeRequests .anyRequest().permitAll()) .oauth2Login(oauth2 -> oauth2 + .loginPage("/login") .successHandler(oAuth2LoginSuccessHandler) .failureHandler(oAuth2LoginFailureHandler) .userInfoEndpoint(userInfo -> userInfo.userService(customOAuth2UserService)) //customUserService 설정