From fa455af42ffa9f36dce0701c1c63c1bae35566aa Mon Sep 17 00:00:00 2001 From: shin2012649 Date: Fri, 15 Sep 2023 20:20:48 +0900 Subject: [PATCH 1/6] =?UTF-8?q?*feat=20:=20redis=20=EB=9E=AD=ED=82=B9,=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20=EA=B5=AC=ED=98=84=20=EC=A2=8B=EC=95=84?= =?UTF-8?q?=EC=9A=94,=20=EC=A1=B0=ED=9A=8C=EC=88=98=20=EB=B3=84=20?= =?UTF-8?q?=EB=9E=AD=ED=82=B9=20=EB=A1=9C=EC=A7=81=20=EC=9E=91=EC=84=B1=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20api=20=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Api/src/main/java/ranking/MainController.java | 30 ++++++++ .../java/ranking/MainPageRankingInfoVo.java | 22 ++++++ Api/src/main/java/ranking/RankedPost.java | 31 ++++++++ Api/src/main/java/ranking/RankedPostVo.java | 18 +++++ Api/src/main/java/ranking/Ranking.java | 35 +++++++++ Api/src/main/java/ranking/RankingAdaptor.java | 14 ++++ .../main/java/ranking/RankingRepository.java | 7 ++ Api/src/main/java/ranking/RankingService.java | 72 +++++++++++++++++++ Api/src/main/java/ranking/RankingType.java | 18 +++++ Api/src/main/java/search/SearchAdapter.java | 15 ++++ .../main/java/search/SearchController.java | 37 ++++++++++ Api/src/main/java/search/SearchEntity.java | 52 ++++++++++++++ .../main/java/search/SearchRepository.java | 16 +++++ Api/src/main/java/search/SearchService.java | 38 ++++++++++ Api/src/main/java/search/SearchVo.java | 40 +++++++++++ 15 files changed, 445 insertions(+) create mode 100644 Api/src/main/java/ranking/MainController.java create mode 100644 Api/src/main/java/ranking/MainPageRankingInfoVo.java create mode 100644 Api/src/main/java/ranking/RankedPost.java create mode 100644 Api/src/main/java/ranking/RankedPostVo.java create mode 100644 Api/src/main/java/ranking/Ranking.java create mode 100644 Api/src/main/java/ranking/RankingAdaptor.java create mode 100644 Api/src/main/java/ranking/RankingRepository.java create mode 100644 Api/src/main/java/ranking/RankingService.java create mode 100644 Api/src/main/java/ranking/RankingType.java create mode 100644 Api/src/main/java/search/SearchAdapter.java create mode 100644 Api/src/main/java/search/SearchController.java create mode 100644 Api/src/main/java/search/SearchEntity.java create mode 100644 Api/src/main/java/search/SearchRepository.java create mode 100644 Api/src/main/java/search/SearchService.java create mode 100644 Api/src/main/java/search/SearchVo.java diff --git a/Api/src/main/java/ranking/MainController.java b/Api/src/main/java/ranking/MainController.java new file mode 100644 index 0000000..24ea7a1 --- /dev/null +++ b/Api/src/main/java/ranking/MainController.java @@ -0,0 +1,30 @@ +package ranking; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/main") +@RequiredArgsConstructor +@Tag(name = "1. [메인 페이지]") +public class MainController { + private final RankingService rankingService; + + @Operation(summary = "일간/주간/월간 랭킹을 조회합니다.") + @GetMapping("/ranking") + public ResponseEntity getRanking(@RequestParam RankingType rankingType) { + MainPageRankingInfoVo rankingInfo = rankingService.getRankingInfo(rankingType); + + if (rankingInfo == null) { + return ResponseEntity.notFound().build(); + } + + return ResponseEntity.ok(rankingInfo); + } +} diff --git a/Api/src/main/java/ranking/MainPageRankingInfoVo.java b/Api/src/main/java/ranking/MainPageRankingInfoVo.java new file mode 100644 index 0000000..1d8a640 --- /dev/null +++ b/Api/src/main/java/ranking/MainPageRankingInfoVo.java @@ -0,0 +1,22 @@ +package ranking; + +import lombok.Builder; +import lombok.Getter; + +import java.util.List; + +@Getter +@Builder +public class MainPageRankingInfoVo { + private final RankingType rankingType; + private final List rankedPosts; + + public static MainPageRankingInfoVo from(Ranking ranking) { + return MainPageRankingInfoVo.builder() + .rankingType(ranking.getRankingType()) + .rankedPosts(ranking.getRankedPosts().stream() + .map(RankedPostVo::from) + .toList()) + .build(); + } +} diff --git a/Api/src/main/java/ranking/RankedPost.java b/Api/src/main/java/ranking/RankedPost.java new file mode 100644 index 0000000..2653208 --- /dev/null +++ b/Api/src/main/java/ranking/RankedPost.java @@ -0,0 +1,31 @@ +package ranking; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@Table(name = "tbl_ranked_post") +@NoArgsConstructor +public class RankedPost { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne + @JoinColumn(name = "post_id") + private Post post; + // 랭킹에 속한 게시물 + + private int rank; + // 게시물의 랭킹 순위 + + // 생성자, 게터, 세터 등 필요한 메서드 추가 +} diff --git a/Api/src/main/java/ranking/RankedPostVo.java b/Api/src/main/java/ranking/RankedPostVo.java new file mode 100644 index 0000000..511a681 --- /dev/null +++ b/Api/src/main/java/ranking/RankedPostVo.java @@ -0,0 +1,18 @@ +package ranking; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class RankedPostVo { + private final Long postId; + private final int rank; + + public static RankedPostVo from(RankedPost rankedPost) { + return RankedPostVo.builder() + .postId(rankedPost.getPost().getId()) + .rank(rankedPost.getRank()) + .build(); + } +} diff --git a/Api/src/main/java/ranking/Ranking.java b/Api/src/main/java/ranking/Ranking.java new file mode 100644 index 0000000..e0c3310 --- /dev/null +++ b/Api/src/main/java/ranking/Ranking.java @@ -0,0 +1,35 @@ +package ranking; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +@Entity +@Getter +@Table(name = "tbl_ranking") +@NoArgsConstructor +public class Ranking { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Enumerated(EnumType.STRING) + private RankingType rankingType; + // 일간, 주간, 월간 중 하나를 나타냄 + @OneToMany(mappedBy = "ranking", cascade = CascadeType.ALL) + private List rankedPosts = new ArrayList<>(); + // 랭킹에 속한 게시물 목록 + + // 생성자, 게터, 세터 등 필요한 메서드를 추가 +} diff --git a/Api/src/main/java/ranking/RankingAdaptor.java b/Api/src/main/java/ranking/RankingAdaptor.java new file mode 100644 index 0000000..8cfe6ad --- /dev/null +++ b/Api/src/main/java/ranking/RankingAdaptor.java @@ -0,0 +1,14 @@ +package ranking; + +import lombok.RequiredArgsConstructor; +import playlist.server.annotation.Adaptor; + +@Adaptor +@RequiredArgsConstructor +public class RankingAdaptor { + private final RankingRepository rankingRepository; + + public Ranking queryByRankingType(RankingType rankingType) { + return rankingRepository.findByRankingType(rankingType); + } +} \ No newline at end of file diff --git a/Api/src/main/java/ranking/RankingRepository.java b/Api/src/main/java/ranking/RankingRepository.java new file mode 100644 index 0000000..912a5d2 --- /dev/null +++ b/Api/src/main/java/ranking/RankingRepository.java @@ -0,0 +1,7 @@ +package ranking; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RankingRepository extends JpaRepository { + Ranking findByRankingType(RankingType rankingType); +} diff --git a/Api/src/main/java/ranking/RankingService.java b/Api/src/main/java/ranking/RankingService.java new file mode 100644 index 0000000..ea4b795 --- /dev/null +++ b/Api/src/main/java/ranking/RankingService.java @@ -0,0 +1,72 @@ +package ranking; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +@Service +public class RankingService { + + private final RedisTemplate redisTemplate; + + @Autowired + public RankingService(RedisTemplate redisTemplate) { + this.redisTemplate = redisTemplate; + } + + // 좋아요증가, 랭킹 업데이트 (일간) + public void incrementDailyLikes(String boardId) { + redisTemplate.opsForHash().increment("like_daily_counts", boardId, 1L); + redisTemplate.opsForZSet().add("like_daily_ranking", boardId, (double) getCurrentLikes("like_daily_counts", boardId)); + } + + // // 좋아요증가, 랭킹 업데이트 (주간) + public void incrementWeeklyLikes(String boardId) { + redisTemplate.opsForHash().increment("like_weekly_counts", boardId, 1L); + redisTemplate.opsForZSet().add("like_weekly_ranking", boardId, (double) getCurrentLikes("like_weekly_counts", boardId)); + } + + // // 좋아요증가, 랭킹 업데이트 (월간) + public void incrementMonthlyLikes(String boardId) { + redisTemplate.opsForHash().increment("like_monthly_counts", boardId, 1L); + redisTemplate.opsForZSet().add("like_monthly_ranking", boardId, (double) getCurrentLikes("like_monthly_counts", boardId)); + } + + // 조회수 증가, 랭킹 업데이트 (일간) + public void incrementDailyViews(String boardId) { + redisTemplate.opsForHash().increment("view_daily_counts", boardId, 1L); + redisTemplate.opsForZSet().add("view_daily_ranking", boardId, (double) getCurrentViews("view_daily_counts", boardId)); + } + + // 조회수 증가, 랭킹 업데이트 (주간) + public void incrementWeeklyViews(String boardId) { + redisTemplate.opsForHash().increment("view_weekly_counts", boardId, 1L); + redisTemplate.opsForZSet().add("view_weekly_ranking", boardId, (double) getCurrentViews("view_weekly_counts", boardId)); + } + + // 조회수 증가, 랭킹 업데이트 (월간) + public void incrementMonthlyViews(String boardId) { + redisTemplate.opsForHash().increment("view_monthly_counts", boardId, 1L); + redisTemplate.opsForZSet().add("view_monthly_ranking", boardId, (double) getCurrentViews("view_monthly_counts", boardId)); + } + + // 현재 게시물의 좋아요를 가져오는 메서드 + private long getCurrentLikes(String hash, String boardId) { + Object likes = redisTemplate.opsForHash().get(hash, boardId); + if (likes != null) { + return (long) likes; + } else { + return 0L; + } + } + + // 현재 게시물의 조회수를 가져오는 메서드 + private long getCurrentViews(String hash, String boardId) { + Object views = redisTemplate.opsForHash().get(hash, boardId); + if (views != null) { + return (long) views; + } else { + return 0L; + } + } +} diff --git a/Api/src/main/java/ranking/RankingType.java b/Api/src/main/java/ranking/RankingType.java new file mode 100644 index 0000000..91b0ab9 --- /dev/null +++ b/Api/src/main/java/ranking/RankingType.java @@ -0,0 +1,18 @@ +package ranking; + +public enum RankingType { + DAILY("일간"), + WEEKLY("주간"), + MONTHLY("월간"); + + private final String description; + + RankingType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } +} + diff --git a/Api/src/main/java/search/SearchAdapter.java b/Api/src/main/java/search/SearchAdapter.java new file mode 100644 index 0000000..e133e40 --- /dev/null +++ b/Api/src/main/java/search/SearchAdapter.java @@ -0,0 +1,15 @@ +package search; + +import org.springframework.stereotype.Component; + +import javax.naming.directory.SearchResult; +import java.util.List; + +@Component +public class SearchAdapter { + + public List adaptSearchResults() { + + } +} + diff --git a/Api/src/main/java/search/SearchController.java b/Api/src/main/java/search/SearchController.java new file mode 100644 index 0000000..efa18ca --- /dev/null +++ b/Api/src/main/java/search/SearchController.java @@ -0,0 +1,37 @@ +package search; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/search") +public class SearchController { + + @Autowired + private SearchService searchService; + + @GetMapping("/tag") + public ResponseEntity> searchByTag(@RequestParam("tag") String tag) { + List searchResults = searchService.searchByTag(tag); + + if (searchResults.isEmpty()) { + return ResponseEntity.notFound().build(); + } + + return ResponseEntity.ok(searchResults); + } + + @GetMapping("/autocomplete") + public ResponseEntity> autoComplete(@RequestParam("query") String query) { + List suggestions = searchService.autoComplete(query); + + if (suggestions.isEmpty()) { + return ResponseEntity.notFound().build(); + } + + return ResponseEntity.ok(suggestions); + } +} diff --git a/Api/src/main/java/search/SearchEntity.java b/Api/src/main/java/search/SearchEntity.java new file mode 100644 index 0000000..2341e5e --- /dev/null +++ b/Api/src/main/java/search/SearchEntity.java @@ -0,0 +1,52 @@ +package search; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; + +@Entity +public class SearchEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String title; + private String description; + private String tag; + + // Getter와 Setter 메서드 + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } +} + diff --git a/Api/src/main/java/search/SearchRepository.java b/Api/src/main/java/search/SearchRepository.java new file mode 100644 index 0000000..9fa06e4 --- /dev/null +++ b/Api/src/main/java/search/SearchRepository.java @@ -0,0 +1,16 @@ +package search; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface SearchRepository extends JpaRepository { + + // 태그를 기반으로 검색하기 위한 사용자 정의 메서드 + List findByTag(String tag); + + // 자동완성을 위한 사용자 정의 메서드 + List findByTitleStartingWith(String query); +} diff --git a/Api/src/main/java/search/SearchService.java b/Api/src/main/java/search/SearchService.java new file mode 100644 index 0000000..ea718a3 --- /dev/null +++ b/Api/src/main/java/search/SearchService.java @@ -0,0 +1,38 @@ +package search; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class SearchService { + + @Autowired + private SearchRepository searchRepository; + + @Autowired + private SearchAdapter searchAdapter; + + public List searchByTag(String tag) { + // 태그를 기반으로 검색 결과를 데이터베이스에서 조회 + List searchEntities = searchRepository.findByTag(tag); + + // 검색 결과를 SearchAdapter를 사용하여 SearchResult로 변환 + List searchResults = searchAdapter.adaptSearchResults(searchEntities); + + return searchResults; + } + + public List autoComplete(String query) { + // 자동완성을 위해 데이터베이스에서 검색 + List searchEntities = searchRepository.findByTitleStartingWith(query); + + // 검색 결과 중 타이틀만 추출하여 자동완성 제안 목록 생성 + List suggestions = searchEntities.stream() + .map(SearchEntity::getTitle) + .toList(); + + return suggestions; + } +} diff --git a/Api/src/main/java/search/SearchVo.java b/Api/src/main/java/search/SearchVo.java new file mode 100644 index 0000000..6bdae83 --- /dev/null +++ b/Api/src/main/java/search/SearchVo.java @@ -0,0 +1,40 @@ +package search; + +public class SearchVo { + + private String title; + private String description; + + public SearchVo() { + // 기본 생성자 + } + + public SearchVo(String title, String description) { + this.title = title; + this.description = description; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String toString() { + return "SearchVo{" + + "title='" + title + '\'' + + ", description='" + description + '\'' + + '}'; + } +} From d8b812c40f0401c40fc434b8f2b3b07c880c692b Mon Sep 17 00:00:00 2001 From: shin2012649 Date: Mon, 18 Sep 2023 12:38:10 +0900 Subject: [PATCH 2/6] =?UTF-8?q?*feat=20:=20redis=20=EB=9E=AD=ED=82=B9,=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/ranking/MainPageRankingInfoVo.java | 20 +++ .../ranking/controller/RankingController.java | 115 ++++++++++++++++++ .../ranking/service/RankingAdaptor.java | 17 +++ .../ranking/service/RankingLikeService.java | 33 +++++ .../ranking/service/RankingViewService.java | 33 +++++ .../search/controller/SearchController.java | 34 ++++++ .../server/search/service/SearchService.java | 31 +++++ .../playlist/server/search/vo/SearchVo.java | 18 +++ Api/src/main/java/ranking/MainController.java | 30 ----- .../java/ranking/MainPageRankingInfoVo.java | 22 ---- Api/src/main/java/ranking/RankedPost.java | 31 ----- Api/src/main/java/ranking/RankedPostVo.java | 18 --- Api/src/main/java/ranking/RankingAdaptor.java | 14 --- .../main/java/ranking/RankingRepository.java | 7 -- Api/src/main/java/ranking/RankingService.java | 72 ----------- Api/src/main/java/ranking/RankingType.java | 18 --- Api/src/main/java/search/SearchAdapter.java | 15 --- .../main/java/search/SearchController.java | 37 ------ Api/src/main/java/search/SearchEntity.java | 52 -------- .../main/java/search/SearchRepository.java | 16 --- Api/src/main/java/search/SearchService.java | 38 ------ Api/src/main/java/search/SearchVo.java | 40 ------ .../domains/ranking/domain}/Ranking.java | 16 +-- .../domains/ranking/domain/RankingInfo.java | 23 ++++ .../domains/ranking/domain/RankingType.java | 16 +++ .../ranking/repository/RankingRepository.java | 10 ++ .../domain/domains/search/domain/Search.java | 24 ++++ .../search/repository/SearchRepository.java | 9 ++ 28 files changed, 386 insertions(+), 423 deletions(-) create mode 100644 Api/src/main/java/playlist/server/ranking/MainPageRankingInfoVo.java create mode 100644 Api/src/main/java/playlist/server/ranking/controller/RankingController.java create mode 100644 Api/src/main/java/playlist/server/ranking/service/RankingAdaptor.java create mode 100644 Api/src/main/java/playlist/server/ranking/service/RankingLikeService.java create mode 100644 Api/src/main/java/playlist/server/ranking/service/RankingViewService.java create mode 100644 Api/src/main/java/playlist/server/search/controller/SearchController.java create mode 100644 Api/src/main/java/playlist/server/search/service/SearchService.java create mode 100644 Api/src/main/java/playlist/server/search/vo/SearchVo.java delete mode 100644 Api/src/main/java/ranking/MainController.java delete mode 100644 Api/src/main/java/ranking/MainPageRankingInfoVo.java delete mode 100644 Api/src/main/java/ranking/RankedPost.java delete mode 100644 Api/src/main/java/ranking/RankedPostVo.java delete mode 100644 Api/src/main/java/ranking/RankingAdaptor.java delete mode 100644 Api/src/main/java/ranking/RankingRepository.java delete mode 100644 Api/src/main/java/ranking/RankingService.java delete mode 100644 Api/src/main/java/ranking/RankingType.java delete mode 100644 Api/src/main/java/search/SearchAdapter.java delete mode 100644 Api/src/main/java/search/SearchController.java delete mode 100644 Api/src/main/java/search/SearchEntity.java delete mode 100644 Api/src/main/java/search/SearchRepository.java delete mode 100644 Api/src/main/java/search/SearchService.java delete mode 100644 Api/src/main/java/search/SearchVo.java rename {Api/src/main/java/ranking => Domain/src/main/java/playlist/server/domain/domains/ranking/domain}/Ranking.java (52%) create mode 100644 Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingInfo.java create mode 100644 Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingType.java create mode 100644 Domain/src/main/java/playlist/server/domain/domains/ranking/repository/RankingRepository.java create mode 100644 Domain/src/main/java/playlist/server/domain/domains/search/domain/Search.java create mode 100644 Domain/src/main/java/playlist/server/domain/domains/search/repository/SearchRepository.java diff --git a/Api/src/main/java/playlist/server/ranking/MainPageRankingInfoVo.java b/Api/src/main/java/playlist/server/ranking/MainPageRankingInfoVo.java new file mode 100644 index 0000000..20abc30 --- /dev/null +++ b/Api/src/main/java/playlist/server/ranking/MainPageRankingInfoVo.java @@ -0,0 +1,20 @@ +package playlist.server.ranking; + +import lombok.Builder; +import lombok.Getter; +import playlist.server.domain.domains.ranking.domain.RankingInfo; +import playlist.server.domain.domains.ranking.domain.RankingType; + +@Getter +@Builder +public class MainPageRankingInfoVo { + private final RankingInfo rankingInfo; + private final RankingType rankingType; + + public static MainPageRankingInfoVo from(RankingInfo rankingInfo, RankingType rankingType) { + return MainPageRankingInfoVo.builder() + .rankingInfo(rankingInfo) + .rankingType(rankingType) + .build(); + } +} diff --git a/Api/src/main/java/playlist/server/ranking/controller/RankingController.java b/Api/src/main/java/playlist/server/ranking/controller/RankingController.java new file mode 100644 index 0000000..f1a5da6 --- /dev/null +++ b/Api/src/main/java/playlist/server/ranking/controller/RankingController.java @@ -0,0 +1,115 @@ +package playlist.server.ranking.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import playlist.server.domain.domains.ranking.domain.RankingType; +import playlist.server.ranking.MainPageRankingInfoVo; +import playlist.server.ranking.service.RankingLikeService; +import playlist.server.ranking.service.RankingViewService; +import playlist.server.domain.domains.ranking.domain.RankingInfo; // RankingInfo enum 추가 + +@RestController +@RequestMapping("/ranking") +@RequiredArgsConstructor +@Tag(name = "1. [랭킹]") +public class RankingController { + + private final RankingLikeService rankingLikeService; + private final RankingViewService rankingViewService; + + @Operation(summary = "일간 랭킹을 조회합니다.") + @GetMapping("/daily") + public ResponseEntity getDailyRanking( + @RequestParam(name = "rankingType", required = false, defaultValue = "DAILY") RankingType rankingType) { + RankingInfo rankingInfo = RankingInfo.DAILY; + rankingLikeService.incrementLikes(rankingType.name(), rankingInfo); + MainPageRankingInfoVo rankingInfoVo = MainPageRankingInfoVo.from(rankingInfo, rankingType); + + if (rankingInfoVo == null) { + return ResponseEntity.notFound().build(); + } + + return ResponseEntity.ok(rankingInfoVo); + } + + @Operation(summary = "주간 랭킹을 조회합니다.") + @GetMapping("/weekly") + public ResponseEntity getWeeklyRanking( + @RequestParam(name = "rankingType", required = false, defaultValue = "WEEKLY") RankingType rankingType) { + RankingInfo rankingInfo = RankingInfo.WEEKLY; + rankingLikeService.incrementLikes(rankingType.name(), rankingInfo); + MainPageRankingInfoVo rankingInfoVo = MainPageRankingInfoVo.from(rankingInfo, rankingType); + + if (rankingInfoVo == null) { + return ResponseEntity.notFound().build(); + } + + return ResponseEntity.ok(rankingInfoVo); + } + + @Operation(summary = "월간 랭킹을 조회합니다.") + @GetMapping("/monthly") + public ResponseEntity getMonthlyRanking( + @RequestParam(name = "rankingType", required = false, defaultValue = "MONTHLY") RankingType rankingType) { + RankingInfo rankingInfo = RankingInfo.MONTHLY; + rankingLikeService.incrementLikes(rankingType.name(), rankingInfo); + MainPageRankingInfoVo rankingInfoVo = MainPageRankingInfoVo.from(rankingInfo, rankingType); + + if (rankingInfoVo == null) { + return ResponseEntity.notFound().build(); + } + + return ResponseEntity.ok(rankingInfoVo); + } + + @Operation(summary = "일간 조회수 랭킹을 조회합니다.") + @GetMapping("/daily-views") + public ResponseEntity getDailyViewsRanking( + @RequestParam(name = "rankingType", required = false, defaultValue = "DAILY") RankingType rankingType) { + RankingInfo rankingInfo = RankingInfo.DAILY; + rankingViewService.incrementViews(rankingType.name(), rankingInfo); + MainPageRankingInfoVo rankingInfoVo = MainPageRankingInfoVo.from(rankingInfo, rankingType); + + if (rankingInfoVo == null) { + return ResponseEntity.notFound().build(); + } + + return ResponseEntity.ok(rankingInfoVo); + } + + @Operation(summary = "주간 조회수 랭킹을 조회합니다.") + @GetMapping("/weekly-views") + public ResponseEntity getWeeklyViewsRanking( + @RequestParam(name = "rankingType", required = false, defaultValue = "WEEKLY") RankingType rankingType) { + RankingInfo rankingInfo = RankingInfo.WEEKLY; + rankingViewService.incrementViews(rankingType.name(), rankingInfo); + MainPageRankingInfoVo rankingInfoVo = MainPageRankingInfoVo.from(rankingInfo, rankingType); + + if (rankingInfoVo == null) { + return ResponseEntity.notFound().build(); + } + + return ResponseEntity.ok(rankingInfoVo); + } + + @Operation(summary = "월간 조회수 랭킹을 조회합니다.") + @GetMapping("/monthly-views") + public ResponseEntity getMonthlyViewsRanking( + @RequestParam(name = "rankingType", required = false, defaultValue = "MONTHLY") RankingType rankingType) { + RankingInfo rankingInfo = RankingInfo.MONTHLY; + rankingViewService.incrementViews(rankingType.name(), rankingInfo); + MainPageRankingInfoVo rankingInfoVo = MainPageRankingInfoVo.from(rankingInfo, rankingType); + + if (rankingInfoVo == null) { + return ResponseEntity.notFound().build(); + } + + return ResponseEntity.ok(rankingInfoVo); + } +} \ No newline at end of file diff --git a/Api/src/main/java/playlist/server/ranking/service/RankingAdaptor.java b/Api/src/main/java/playlist/server/ranking/service/RankingAdaptor.java new file mode 100644 index 0000000..c695bd5 --- /dev/null +++ b/Api/src/main/java/playlist/server/ranking/service/RankingAdaptor.java @@ -0,0 +1,17 @@ +package playlist.server.ranking.service; + +import lombok.RequiredArgsConstructor; +import playlist.server.annotation.Adaptor; +import playlist.server.domain.domains.ranking.domain.Ranking; +import playlist.server.domain.domains.ranking.domain.RankingInfo; +import playlist.server.domain.domains.ranking.repository.RankingRepository; + +@Adaptor +@RequiredArgsConstructor +public class RankingAdaptor { + private final RankingRepository rankingRepository; + + public Ranking queryByRankingInfo(RankingInfo rankingInfo) { + return rankingRepository.findByRankingInfo(rankingInfo); + } +} diff --git a/Api/src/main/java/playlist/server/ranking/service/RankingLikeService.java b/Api/src/main/java/playlist/server/ranking/service/RankingLikeService.java new file mode 100644 index 0000000..a12e2bd --- /dev/null +++ b/Api/src/main/java/playlist/server/ranking/service/RankingLikeService.java @@ -0,0 +1,33 @@ +package playlist.server.ranking.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; +import playlist.server.domain.domains.ranking.domain.RankingInfo; // RankingInfo enum 추가 + +@Service +public class RankingLikeService { + + private final RedisTemplate redisTemplate; + + @Autowired + public RankingLikeService(RedisTemplate redisTemplate) { + this.redisTemplate = redisTemplate; + } + + // 좋아요 증가, 랭킹 업데이트 (일간) + public void incrementLikes(String boardId, RankingInfo rankingInfo) { + redisTemplate.opsForHash().increment(rankingInfo.getCountsKey(), boardId, 1L); + redisTemplate.opsForZSet().add(rankingInfo.getRankingKey(), boardId, (double) getCurrentLikes(rankingInfo.getCountsKey(), boardId)); + } + + // 현재 게시물의 좋아요를 가져오는 메서드 + private long getCurrentLikes(String hash, String boardId) { + Object likes = redisTemplate.opsForHash().get(hash, boardId); + if (likes != null) { + return (long) likes; + } else { + return 0L; + } + } +} diff --git a/Api/src/main/java/playlist/server/ranking/service/RankingViewService.java b/Api/src/main/java/playlist/server/ranking/service/RankingViewService.java new file mode 100644 index 0000000..74d757d --- /dev/null +++ b/Api/src/main/java/playlist/server/ranking/service/RankingViewService.java @@ -0,0 +1,33 @@ +package playlist.server.ranking.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; +import playlist.server.domain.domains.ranking.domain.RankingInfo; // RankingInfo enum 추가 + +@Service +public class RankingViewService { + + private final RedisTemplate redisTemplate; + + @Autowired + public RankingViewService(RedisTemplate redisTemplate) { + this.redisTemplate = redisTemplate; + } + + // 조회수 증가, 랭킹 업데이트 (일간) + public void incrementViews(String boardId, RankingInfo rankingInfo) { + redisTemplate.opsForHash().increment(rankingInfo.getCountsKey(), boardId, 1L); + redisTemplate.opsForZSet().add(rankingInfo.getRankingKey(), boardId, (double) getCurrentViews(rankingInfo.getCountsKey(), boardId)); + } + + // 현재 게시물의 조회수를 가져오는 메서드 + private long getCurrentViews(String hash, String boardId) { + Object views = redisTemplate.opsForHash().get(hash, boardId); + if (views != null) { + return (long) views; + } else { + return 0L; + } + } +} diff --git a/Api/src/main/java/playlist/server/search/controller/SearchController.java b/Api/src/main/java/playlist/server/search/controller/SearchController.java new file mode 100644 index 0000000..751d83e --- /dev/null +++ b/Api/src/main/java/playlist/server/search/controller/SearchController.java @@ -0,0 +1,34 @@ +package playlist.server.search.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import playlist.server.search.service.SearchService; +import playlist.server.search.vo.SearchVo; + +import java.util.List; + +@RestController +@RequestMapping("/playlist/server/search") +public class SearchController { + + private final SearchService searchService; + + public SearchController(SearchService searchService) { + this.searchService = searchService; + } + + // 태그 기반으로 검색 + @GetMapping("/tag") + public ResponseEntity> searchByTag(@RequestParam("tag") String tag) { + List searchResults = searchService.searchByTag(tag); + + if (searchResults.isEmpty()) { + return ResponseEntity.notFound().build(); + } + + return ResponseEntity.ok(searchResults); + } +} diff --git a/Api/src/main/java/playlist/server/search/service/SearchService.java b/Api/src/main/java/playlist/server/search/service/SearchService.java new file mode 100644 index 0000000..81b2b7c --- /dev/null +++ b/Api/src/main/java/playlist/server/search/service/SearchService.java @@ -0,0 +1,31 @@ +package playlist.server.search.service; + +import org.springframework.stereotype.Service; +import playlist.server.domain.domains.search.domain.Search; +import playlist.server.domain.domains.search.repository.SearchRepository; +import playlist.server.search.vo.SearchVo; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class SearchService { + + private final SearchRepository searchRepository; + + public SearchService(SearchRepository searchRepository) { + this.searchRepository = searchRepository; + } + + public List searchByTag(String tag) { + // 태그를 기반으로 검색 결과를 데이터베이스에서 조회 + List searchEntities = searchRepository.findByTag(tag); + + // 검색 결과를 SearchVo로 변환 + List searchResults = searchEntities.stream() + .map(search -> new SearchVo(search.getTitle(), search.getDescription())) + .collect(Collectors.toList()); + + return searchResults; + } +} diff --git a/Api/src/main/java/playlist/server/search/vo/SearchVo.java b/Api/src/main/java/playlist/server/search/vo/SearchVo.java new file mode 100644 index 0000000..8e0bfb2 --- /dev/null +++ b/Api/src/main/java/playlist/server/search/vo/SearchVo.java @@ -0,0 +1,18 @@ +package playlist.server.search.vo; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@NoArgsConstructor +@AllArgsConstructor +@ToString +@Getter +@Setter +public class SearchVo { + + private String title; + private String description; +} diff --git a/Api/src/main/java/ranking/MainController.java b/Api/src/main/java/ranking/MainController.java deleted file mode 100644 index 24ea7a1..0000000 --- a/Api/src/main/java/ranking/MainController.java +++ /dev/null @@ -1,30 +0,0 @@ -package ranking; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/main") -@RequiredArgsConstructor -@Tag(name = "1. [메인 페이지]") -public class MainController { - private final RankingService rankingService; - - @Operation(summary = "일간/주간/월간 랭킹을 조회합니다.") - @GetMapping("/ranking") - public ResponseEntity getRanking(@RequestParam RankingType rankingType) { - MainPageRankingInfoVo rankingInfo = rankingService.getRankingInfo(rankingType); - - if (rankingInfo == null) { - return ResponseEntity.notFound().build(); - } - - return ResponseEntity.ok(rankingInfo); - } -} diff --git a/Api/src/main/java/ranking/MainPageRankingInfoVo.java b/Api/src/main/java/ranking/MainPageRankingInfoVo.java deleted file mode 100644 index 1d8a640..0000000 --- a/Api/src/main/java/ranking/MainPageRankingInfoVo.java +++ /dev/null @@ -1,22 +0,0 @@ -package ranking; - -import lombok.Builder; -import lombok.Getter; - -import java.util.List; - -@Getter -@Builder -public class MainPageRankingInfoVo { - private final RankingType rankingType; - private final List rankedPosts; - - public static MainPageRankingInfoVo from(Ranking ranking) { - return MainPageRankingInfoVo.builder() - .rankingType(ranking.getRankingType()) - .rankedPosts(ranking.getRankedPosts().stream() - .map(RankedPostVo::from) - .toList()) - .build(); - } -} diff --git a/Api/src/main/java/ranking/RankedPost.java b/Api/src/main/java/ranking/RankedPost.java deleted file mode 100644 index 2653208..0000000 --- a/Api/src/main/java/ranking/RankedPost.java +++ /dev/null @@ -1,31 +0,0 @@ -package ranking; - -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.Table; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Entity -@Getter -@Table(name = "tbl_ranked_post") -@NoArgsConstructor -public class RankedPost { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @ManyToOne - @JoinColumn(name = "post_id") - private Post post; - // 랭킹에 속한 게시물 - - private int rank; - // 게시물의 랭킹 순위 - - // 생성자, 게터, 세터 등 필요한 메서드 추가 -} diff --git a/Api/src/main/java/ranking/RankedPostVo.java b/Api/src/main/java/ranking/RankedPostVo.java deleted file mode 100644 index 511a681..0000000 --- a/Api/src/main/java/ranking/RankedPostVo.java +++ /dev/null @@ -1,18 +0,0 @@ -package ranking; - -import lombok.Builder; -import lombok.Getter; - -@Getter -@Builder -public class RankedPostVo { - private final Long postId; - private final int rank; - - public static RankedPostVo from(RankedPost rankedPost) { - return RankedPostVo.builder() - .postId(rankedPost.getPost().getId()) - .rank(rankedPost.getRank()) - .build(); - } -} diff --git a/Api/src/main/java/ranking/RankingAdaptor.java b/Api/src/main/java/ranking/RankingAdaptor.java deleted file mode 100644 index 8cfe6ad..0000000 --- a/Api/src/main/java/ranking/RankingAdaptor.java +++ /dev/null @@ -1,14 +0,0 @@ -package ranking; - -import lombok.RequiredArgsConstructor; -import playlist.server.annotation.Adaptor; - -@Adaptor -@RequiredArgsConstructor -public class RankingAdaptor { - private final RankingRepository rankingRepository; - - public Ranking queryByRankingType(RankingType rankingType) { - return rankingRepository.findByRankingType(rankingType); - } -} \ No newline at end of file diff --git a/Api/src/main/java/ranking/RankingRepository.java b/Api/src/main/java/ranking/RankingRepository.java deleted file mode 100644 index 912a5d2..0000000 --- a/Api/src/main/java/ranking/RankingRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package ranking; - -import org.springframework.data.jpa.repository.JpaRepository; - -public interface RankingRepository extends JpaRepository { - Ranking findByRankingType(RankingType rankingType); -} diff --git a/Api/src/main/java/ranking/RankingService.java b/Api/src/main/java/ranking/RankingService.java deleted file mode 100644 index ea4b795..0000000 --- a/Api/src/main/java/ranking/RankingService.java +++ /dev/null @@ -1,72 +0,0 @@ -package ranking; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Service; - -@Service -public class RankingService { - - private final RedisTemplate redisTemplate; - - @Autowired - public RankingService(RedisTemplate redisTemplate) { - this.redisTemplate = redisTemplate; - } - - // 좋아요증가, 랭킹 업데이트 (일간) - public void incrementDailyLikes(String boardId) { - redisTemplate.opsForHash().increment("like_daily_counts", boardId, 1L); - redisTemplate.opsForZSet().add("like_daily_ranking", boardId, (double) getCurrentLikes("like_daily_counts", boardId)); - } - - // // 좋아요증가, 랭킹 업데이트 (주간) - public void incrementWeeklyLikes(String boardId) { - redisTemplate.opsForHash().increment("like_weekly_counts", boardId, 1L); - redisTemplate.opsForZSet().add("like_weekly_ranking", boardId, (double) getCurrentLikes("like_weekly_counts", boardId)); - } - - // // 좋아요증가, 랭킹 업데이트 (월간) - public void incrementMonthlyLikes(String boardId) { - redisTemplate.opsForHash().increment("like_monthly_counts", boardId, 1L); - redisTemplate.opsForZSet().add("like_monthly_ranking", boardId, (double) getCurrentLikes("like_monthly_counts", boardId)); - } - - // 조회수 증가, 랭킹 업데이트 (일간) - public void incrementDailyViews(String boardId) { - redisTemplate.opsForHash().increment("view_daily_counts", boardId, 1L); - redisTemplate.opsForZSet().add("view_daily_ranking", boardId, (double) getCurrentViews("view_daily_counts", boardId)); - } - - // 조회수 증가, 랭킹 업데이트 (주간) - public void incrementWeeklyViews(String boardId) { - redisTemplate.opsForHash().increment("view_weekly_counts", boardId, 1L); - redisTemplate.opsForZSet().add("view_weekly_ranking", boardId, (double) getCurrentViews("view_weekly_counts", boardId)); - } - - // 조회수 증가, 랭킹 업데이트 (월간) - public void incrementMonthlyViews(String boardId) { - redisTemplate.opsForHash().increment("view_monthly_counts", boardId, 1L); - redisTemplate.opsForZSet().add("view_monthly_ranking", boardId, (double) getCurrentViews("view_monthly_counts", boardId)); - } - - // 현재 게시물의 좋아요를 가져오는 메서드 - private long getCurrentLikes(String hash, String boardId) { - Object likes = redisTemplate.opsForHash().get(hash, boardId); - if (likes != null) { - return (long) likes; - } else { - return 0L; - } - } - - // 현재 게시물의 조회수를 가져오는 메서드 - private long getCurrentViews(String hash, String boardId) { - Object views = redisTemplate.opsForHash().get(hash, boardId); - if (views != null) { - return (long) views; - } else { - return 0L; - } - } -} diff --git a/Api/src/main/java/ranking/RankingType.java b/Api/src/main/java/ranking/RankingType.java deleted file mode 100644 index 91b0ab9..0000000 --- a/Api/src/main/java/ranking/RankingType.java +++ /dev/null @@ -1,18 +0,0 @@ -package ranking; - -public enum RankingType { - DAILY("일간"), - WEEKLY("주간"), - MONTHLY("월간"); - - private final String description; - - RankingType(String description) { - this.description = description; - } - - public String getDescription() { - return description; - } -} - diff --git a/Api/src/main/java/search/SearchAdapter.java b/Api/src/main/java/search/SearchAdapter.java deleted file mode 100644 index e133e40..0000000 --- a/Api/src/main/java/search/SearchAdapter.java +++ /dev/null @@ -1,15 +0,0 @@ -package search; - -import org.springframework.stereotype.Component; - -import javax.naming.directory.SearchResult; -import java.util.List; - -@Component -public class SearchAdapter { - - public List adaptSearchResults() { - - } -} - diff --git a/Api/src/main/java/search/SearchController.java b/Api/src/main/java/search/SearchController.java deleted file mode 100644 index efa18ca..0000000 --- a/Api/src/main/java/search/SearchController.java +++ /dev/null @@ -1,37 +0,0 @@ -package search; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -@RestController -@RequestMapping("/search") -public class SearchController { - - @Autowired - private SearchService searchService; - - @GetMapping("/tag") - public ResponseEntity> searchByTag(@RequestParam("tag") String tag) { - List searchResults = searchService.searchByTag(tag); - - if (searchResults.isEmpty()) { - return ResponseEntity.notFound().build(); - } - - return ResponseEntity.ok(searchResults); - } - - @GetMapping("/autocomplete") - public ResponseEntity> autoComplete(@RequestParam("query") String query) { - List suggestions = searchService.autoComplete(query); - - if (suggestions.isEmpty()) { - return ResponseEntity.notFound().build(); - } - - return ResponseEntity.ok(suggestions); - } -} diff --git a/Api/src/main/java/search/SearchEntity.java b/Api/src/main/java/search/SearchEntity.java deleted file mode 100644 index 2341e5e..0000000 --- a/Api/src/main/java/search/SearchEntity.java +++ /dev/null @@ -1,52 +0,0 @@ -package search; - -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; - -@Entity -public class SearchEntity { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - private String title; - private String description; - private String tag; - - // Getter와 Setter 메서드 - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getTag() { - return tag; - } - - public void setTag(String tag) { - this.tag = tag; - } -} - diff --git a/Api/src/main/java/search/SearchRepository.java b/Api/src/main/java/search/SearchRepository.java deleted file mode 100644 index 9fa06e4..0000000 --- a/Api/src/main/java/search/SearchRepository.java +++ /dev/null @@ -1,16 +0,0 @@ -package search; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import java.util.List; - -@Repository -public interface SearchRepository extends JpaRepository { - - // 태그를 기반으로 검색하기 위한 사용자 정의 메서드 - List findByTag(String tag); - - // 자동완성을 위한 사용자 정의 메서드 - List findByTitleStartingWith(String query); -} diff --git a/Api/src/main/java/search/SearchService.java b/Api/src/main/java/search/SearchService.java deleted file mode 100644 index ea718a3..0000000 --- a/Api/src/main/java/search/SearchService.java +++ /dev/null @@ -1,38 +0,0 @@ -package search; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -public class SearchService { - - @Autowired - private SearchRepository searchRepository; - - @Autowired - private SearchAdapter searchAdapter; - - public List searchByTag(String tag) { - // 태그를 기반으로 검색 결과를 데이터베이스에서 조회 - List searchEntities = searchRepository.findByTag(tag); - - // 검색 결과를 SearchAdapter를 사용하여 SearchResult로 변환 - List searchResults = searchAdapter.adaptSearchResults(searchEntities); - - return searchResults; - } - - public List autoComplete(String query) { - // 자동완성을 위해 데이터베이스에서 검색 - List searchEntities = searchRepository.findByTitleStartingWith(query); - - // 검색 결과 중 타이틀만 추출하여 자동완성 제안 목록 생성 - List suggestions = searchEntities.stream() - .map(SearchEntity::getTitle) - .toList(); - - return suggestions; - } -} diff --git a/Api/src/main/java/search/SearchVo.java b/Api/src/main/java/search/SearchVo.java deleted file mode 100644 index 6bdae83..0000000 --- a/Api/src/main/java/search/SearchVo.java +++ /dev/null @@ -1,40 +0,0 @@ -package search; - -public class SearchVo { - - private String title; - private String description; - - public SearchVo() { - // 기본 생성자 - } - - public SearchVo(String title, String description) { - this.title = title; - this.description = description; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - @Override - public String toString() { - return "SearchVo{" + - "title='" + title + '\'' + - ", description='" + description + '\'' + - '}'; - } -} diff --git a/Api/src/main/java/ranking/Ranking.java b/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/Ranking.java similarity index 52% rename from Api/src/main/java/ranking/Ranking.java rename to Domain/src/main/java/playlist/server/domain/domains/ranking/domain/Ranking.java index e0c3310..dc71c60 100644 --- a/Api/src/main/java/ranking/Ranking.java +++ b/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/Ranking.java @@ -1,35 +1,25 @@ -package ranking; +package playlist.server.domain.domains.ranking.domain; -import jakarta.persistence.CascadeType; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.OneToMany; + import jakarta.persistence.Table; import lombok.Getter; import lombok.NoArgsConstructor; -import java.util.ArrayList; -import java.util.List; - @Entity @Getter @Table(name = "tbl_ranking") @NoArgsConstructor public class Ranking { - @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Enumerated(EnumType.STRING) private RankingType rankingType; - // 일간, 주간, 월간 중 하나를 나타냄 - @OneToMany(mappedBy = "ranking", cascade = CascadeType.ALL) - private List rankedPosts = new ArrayList<>(); - // 랭킹에 속한 게시물 목록 - // 생성자, 게터, 세터 등 필요한 메서드를 추가 + } diff --git a/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingInfo.java b/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingInfo.java new file mode 100644 index 0000000..2323907 --- /dev/null +++ b/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingInfo.java @@ -0,0 +1,23 @@ +package playlist.server.domain.domains.ranking.domain; + +public enum RankingInfo { + DAILY("like_daily_counts", "like_daily_ranking"), + WEEKLY("like_weekly_counts", "like_weekly_ranking"), + MONTHLY("like_monthly_counts", "like_monthly_ranking"); + + private final String countsKey; + private final String rankingKey; + + RankingInfo(String countsKey, String rankingKey) { + this.countsKey = countsKey; + this.rankingKey = rankingKey; + } + + public String getCountsKey() { + return countsKey; + } + + public String getRankingKey() { + return rankingKey; + } +} diff --git a/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingType.java b/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingType.java new file mode 100644 index 0000000..22b7411 --- /dev/null +++ b/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingType.java @@ -0,0 +1,16 @@ +package playlist.server.domain.domains.ranking.domain; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public enum RankingType { + DAILY("일간"), + WEEKLY("주간"), + MONTHLY("월간"); + + private final String description; + +} + diff --git a/Domain/src/main/java/playlist/server/domain/domains/ranking/repository/RankingRepository.java b/Domain/src/main/java/playlist/server/domain/domains/ranking/repository/RankingRepository.java new file mode 100644 index 0000000..c0cacc5 --- /dev/null +++ b/Domain/src/main/java/playlist/server/domain/domains/ranking/repository/RankingRepository.java @@ -0,0 +1,10 @@ +package playlist.server.domain.domains.ranking.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import playlist.server.domain.domains.ranking.domain.Ranking; +import playlist.server.domain.domains.ranking.domain.RankingInfo; + + +public interface RankingRepository extends JpaRepository { + Ranking findByRankingInfo(RankingInfo rankingInfo); +} diff --git a/Domain/src/main/java/playlist/server/domain/domains/search/domain/Search.java b/Domain/src/main/java/playlist/server/domain/domains/search/domain/Search.java new file mode 100644 index 0000000..9ce2021 --- /dev/null +++ b/Domain/src/main/java/playlist/server/domain/domains/search/domain/Search.java @@ -0,0 +1,24 @@ +package playlist.server.domain.domains.search.domain; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.Getter; +import lombok.Setter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@Setter +@NoArgsConstructor +public class Search { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String title; + private String description; + private String tag; +} diff --git a/Domain/src/main/java/playlist/server/domain/domains/search/repository/SearchRepository.java b/Domain/src/main/java/playlist/server/domain/domains/search/repository/SearchRepository.java new file mode 100644 index 0000000..7511142 --- /dev/null +++ b/Domain/src/main/java/playlist/server/domain/domains/search/repository/SearchRepository.java @@ -0,0 +1,9 @@ +package playlist.server.domain.domains.search.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import playlist.server.domain.domains.search.domain.Search; +import java.util.List; + +public interface SearchRepository extends JpaRepository { + List findByTag(String tag); +} From cbb7f7b25cff8eb553468aad9f7c96e7436c2b7b Mon Sep 17 00:00:00 2001 From: shin2012649 Date: Tue, 19 Sep 2023 14:00:58 +0900 Subject: [PATCH 3/6] =?UTF-8?q?*feat=20:=20redis=20=EB=9E=AD=ED=82=B9,=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=EC=88=98?= =?UTF-8?q?=EC=A0=952?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vo}/MainPageRankingInfoVo.java | 2 +- .../ranking/controller/RankingController.java | 116 ++++++------------ .../ranking/service/RankingAdaptor.java | 17 --- .../ranking/service/RankingLikeService.java | 28 ++--- .../ranking/service/RankingService.java | 42 +++++++ .../ranking/service/RankingViewService.java | 27 ++-- .../search/controller/SearchController.java | 10 +- .../server/search/service/SearchService.java | 16 +-- .../playlist/server/search/vo/SearchVo.java | 11 +- .../domains/ranking/domain/Ranking.java | 25 ---- .../domains/ranking/domain/RankingInfo.java | 18 +-- .../ranking/repository/RankingRepository.java | 10 -- 12 files changed, 110 insertions(+), 212 deletions(-) rename Api/src/main/java/playlist/server/{ranking => mainpagerankingInfo/vo}/MainPageRankingInfoVo.java (92%) delete mode 100644 Api/src/main/java/playlist/server/ranking/service/RankingAdaptor.java create mode 100644 Api/src/main/java/playlist/server/ranking/service/RankingService.java delete mode 100644 Domain/src/main/java/playlist/server/domain/domains/ranking/domain/Ranking.java delete mode 100644 Domain/src/main/java/playlist/server/domain/domains/ranking/repository/RankingRepository.java diff --git a/Api/src/main/java/playlist/server/ranking/MainPageRankingInfoVo.java b/Api/src/main/java/playlist/server/mainpagerankingInfo/vo/MainPageRankingInfoVo.java similarity index 92% rename from Api/src/main/java/playlist/server/ranking/MainPageRankingInfoVo.java rename to Api/src/main/java/playlist/server/mainpagerankingInfo/vo/MainPageRankingInfoVo.java index 20abc30..e0d0297 100644 --- a/Api/src/main/java/playlist/server/ranking/MainPageRankingInfoVo.java +++ b/Api/src/main/java/playlist/server/mainpagerankingInfo/vo/MainPageRankingInfoVo.java @@ -1,4 +1,4 @@ -package playlist.server.ranking; +package playlist.server.mainpagerankingInfo.vo; import lombok.Builder; import lombok.Getter; diff --git a/Api/src/main/java/playlist/server/ranking/controller/RankingController.java b/Api/src/main/java/playlist/server/ranking/controller/RankingController.java index f1a5da6..4a89d6d 100644 --- a/Api/src/main/java/playlist/server/ranking/controller/RankingController.java +++ b/Api/src/main/java/playlist/server/ranking/controller/RankingController.java @@ -8,11 +8,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import playlist.server.domain.domains.ranking.domain.RankingType; -import playlist.server.ranking.MainPageRankingInfoVo; -import playlist.server.ranking.service.RankingLikeService; -import playlist.server.ranking.service.RankingViewService; -import playlist.server.domain.domains.ranking.domain.RankingInfo; // RankingInfo enum 추가 +import playlist.server.mainpagerankingInfo.vo.MainPageRankingInfoVo; +import playlist.server.ranking.service.RankingService; @RestController @RequestMapping("/ranking") @@ -20,96 +17,53 @@ @Tag(name = "1. [랭킹]") public class RankingController { - private final RankingLikeService rankingLikeService; - private final RankingViewService rankingViewService; + private final RankingService rankingService; - @Operation(summary = "일간 랭킹을 조회합니다.") + @Operation(summary = "랭킹을 조회합니다.") @GetMapping("/daily") public ResponseEntity getDailyRanking( - @RequestParam(name = "rankingType", required = false, defaultValue = "DAILY") RankingType rankingType) { - RankingInfo rankingInfo = RankingInfo.DAILY; - rankingLikeService.incrementLikes(rankingType.name(), rankingInfo); - MainPageRankingInfoVo rankingInfoVo = MainPageRankingInfoVo.from(rankingInfo, rankingType); - - if (rankingInfoVo == null) { - return ResponseEntity.notFound().build(); + @RequestParam(name = "type", defaultValue = "like") String type + ) { + try { + MainPageRankingInfoVo rankingInfoVo = rankingService.getRanking("daily", type, "boardId"); + if (rankingInfoVo == null) { + return ResponseEntity.notFound().build(); + } + return ResponseEntity.ok(rankingInfoVo); + } catch (Exception e) { + return ResponseEntity.badRequest().build(); } - - return ResponseEntity.ok(rankingInfoVo); } @Operation(summary = "주간 랭킹을 조회합니다.") @GetMapping("/weekly") public ResponseEntity getWeeklyRanking( - @RequestParam(name = "rankingType", required = false, defaultValue = "WEEKLY") RankingType rankingType) { - RankingInfo rankingInfo = RankingInfo.WEEKLY; - rankingLikeService.incrementLikes(rankingType.name(), rankingInfo); - MainPageRankingInfoVo rankingInfoVo = MainPageRankingInfoVo.from(rankingInfo, rankingType); - - if (rankingInfoVo == null) { - return ResponseEntity.notFound().build(); + @RequestParam(name = "type", defaultValue = "like") String type + ) { + try { + MainPageRankingInfoVo rankingInfoVo = rankingService.getRanking("weekly", type, "boardId"); + if (rankingInfoVo == null) { + return ResponseEntity.notFound().build(); + } + return ResponseEntity.ok(rankingInfoVo); + } catch (Exception e) { + return ResponseEntity.badRequest().build(); } - - return ResponseEntity.ok(rankingInfoVo); } @Operation(summary = "월간 랭킹을 조회합니다.") @GetMapping("/monthly") public ResponseEntity getMonthlyRanking( - @RequestParam(name = "rankingType", required = false, defaultValue = "MONTHLY") RankingType rankingType) { - RankingInfo rankingInfo = RankingInfo.MONTHLY; - rankingLikeService.incrementLikes(rankingType.name(), rankingInfo); - MainPageRankingInfoVo rankingInfoVo = MainPageRankingInfoVo.from(rankingInfo, rankingType); - - if (rankingInfoVo == null) { - return ResponseEntity.notFound().build(); + @RequestParam(name = "type", defaultValue = "like") String type + ) { + try { + MainPageRankingInfoVo rankingInfoVo = rankingService.getRanking("monthly", type, "boardId"); + if (rankingInfoVo == null) { + return ResponseEntity.notFound().build(); + } + return ResponseEntity.ok(rankingInfoVo); + } catch (Exception e) { + return ResponseEntity.badRequest().build(); } - - return ResponseEntity.ok(rankingInfoVo); - } - - @Operation(summary = "일간 조회수 랭킹을 조회합니다.") - @GetMapping("/daily-views") - public ResponseEntity getDailyViewsRanking( - @RequestParam(name = "rankingType", required = false, defaultValue = "DAILY") RankingType rankingType) { - RankingInfo rankingInfo = RankingInfo.DAILY; - rankingViewService.incrementViews(rankingType.name(), rankingInfo); - MainPageRankingInfoVo rankingInfoVo = MainPageRankingInfoVo.from(rankingInfo, rankingType); - - if (rankingInfoVo == null) { - return ResponseEntity.notFound().build(); - } - - return ResponseEntity.ok(rankingInfoVo); - } - - @Operation(summary = "주간 조회수 랭킹을 조회합니다.") - @GetMapping("/weekly-views") - public ResponseEntity getWeeklyViewsRanking( - @RequestParam(name = "rankingType", required = false, defaultValue = "WEEKLY") RankingType rankingType) { - RankingInfo rankingInfo = RankingInfo.WEEKLY; - rankingViewService.incrementViews(rankingType.name(), rankingInfo); - MainPageRankingInfoVo rankingInfoVo = MainPageRankingInfoVo.from(rankingInfo, rankingType); - - if (rankingInfoVo == null) { - return ResponseEntity.notFound().build(); - } - - return ResponseEntity.ok(rankingInfoVo); - } - - @Operation(summary = "월간 조회수 랭킹을 조회합니다.") - @GetMapping("/monthly-views") - public ResponseEntity getMonthlyViewsRanking( - @RequestParam(name = "rankingType", required = false, defaultValue = "MONTHLY") RankingType rankingType) { - RankingInfo rankingInfo = RankingInfo.MONTHLY; - rankingViewService.incrementViews(rankingType.name(), rankingInfo); - MainPageRankingInfoVo rankingInfoVo = MainPageRankingInfoVo.from(rankingInfo, rankingType); - - if (rankingInfoVo == null) { - return ResponseEntity.notFound().build(); - } - - return ResponseEntity.ok(rankingInfoVo); } -} \ No newline at end of file +} diff --git a/Api/src/main/java/playlist/server/ranking/service/RankingAdaptor.java b/Api/src/main/java/playlist/server/ranking/service/RankingAdaptor.java deleted file mode 100644 index c695bd5..0000000 --- a/Api/src/main/java/playlist/server/ranking/service/RankingAdaptor.java +++ /dev/null @@ -1,17 +0,0 @@ -package playlist.server.ranking.service; - -import lombok.RequiredArgsConstructor; -import playlist.server.annotation.Adaptor; -import playlist.server.domain.domains.ranking.domain.Ranking; -import playlist.server.domain.domains.ranking.domain.RankingInfo; -import playlist.server.domain.domains.ranking.repository.RankingRepository; - -@Adaptor -@RequiredArgsConstructor -public class RankingAdaptor { - private final RankingRepository rankingRepository; - - public Ranking queryByRankingInfo(RankingInfo rankingInfo) { - return rankingRepository.findByRankingInfo(rankingInfo); - } -} diff --git a/Api/src/main/java/playlist/server/ranking/service/RankingLikeService.java b/Api/src/main/java/playlist/server/ranking/service/RankingLikeService.java index a12e2bd..c76b317 100644 --- a/Api/src/main/java/playlist/server/ranking/service/RankingLikeService.java +++ b/Api/src/main/java/playlist/server/ranking/service/RankingLikeService.java @@ -1,33 +1,21 @@ package playlist.server.ranking.service; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; -import playlist.server.domain.domains.ranking.domain.RankingInfo; // RankingInfo enum 추가 +import lombok.RequiredArgsConstructor; @Service +@RequiredArgsConstructor public class RankingLikeService { private final RedisTemplate redisTemplate; - @Autowired - public RankingLikeService(RedisTemplate redisTemplate) { - this.redisTemplate = redisTemplate; - } - - // 좋아요 증가, 랭킹 업데이트 (일간) - public void incrementLikes(String boardId, RankingInfo rankingInfo) { - redisTemplate.opsForHash().increment(rankingInfo.getCountsKey(), boardId, 1L); - redisTemplate.opsForZSet().add(rankingInfo.getRankingKey(), boardId, (double) getCurrentLikes(rankingInfo.getCountsKey(), boardId)); - } - - // 현재 게시물의 좋아요를 가져오는 메서드 - private long getCurrentLikes(String hash, String boardId) { - Object likes = redisTemplate.opsForHash().get(hash, boardId); - if (likes != null) { - return (long) likes; - } else { - return 0L; + public void incrementLikes(String rankingType, String boardId) { + try { + String countsKey = rankingType + "_LIKE_COUNTS"; + redisTemplate.opsForHash().increment(countsKey, boardId, 1L); + } catch (Exception e) { + throw new RuntimeException("좋아요 증가 실패"); } } } diff --git a/Api/src/main/java/playlist/server/ranking/service/RankingService.java b/Api/src/main/java/playlist/server/ranking/service/RankingService.java new file mode 100644 index 0000000..7153044 --- /dev/null +++ b/Api/src/main/java/playlist/server/ranking/service/RankingService.java @@ -0,0 +1,42 @@ +package playlist.server.ranking.service; + +import org.springframework.stereotype.Service; +import playlist.server.domain.domains.ranking.domain.RankingInfo; +import playlist.server.domain.domains.ranking.domain.RankingType; +import playlist.server.mainpagerankingInfo.vo.MainPageRankingInfoVo; +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class RankingService { + + private final RankingLikeService rankingLikeService; + private final RankingViewService rankingViewService; + + public MainPageRankingInfoVo getRanking(String rankingType, String type, String boardId) { + try { + RankingInfo rankingInfo; + if ("daily".equalsIgnoreCase(rankingType)) { + rankingInfo = RankingInfo.DAILY; + } else if ("weekly".equalsIgnoreCase(rankingType)) { + rankingInfo = RankingInfo.WEEKLY; + } else if ("monthly".equalsIgnoreCase(rankingType)) { + rankingInfo = RankingInfo.MONTHLY; + } else { + throw new IllegalArgumentException("유효하지 않은 랭킹 타입"); + } + + if ("like".equals(type)) { + rankingLikeService.incrementLikes(rankingType, boardId); + } else if ("view".equals(type)) { + rankingViewService.incrementViews(rankingType, boardId); + } else { + throw new IllegalArgumentException("유효하지 않은 파라미터"); + } + + return MainPageRankingInfoVo.from(rankingInfo, RankingType.valueOf(rankingType.toUpperCase())); + } catch (Exception e) { + throw new RuntimeException("데이터 가져오는거 실패"); + } + } +} diff --git a/Api/src/main/java/playlist/server/ranking/service/RankingViewService.java b/Api/src/main/java/playlist/server/ranking/service/RankingViewService.java index 74d757d..91b93b2 100644 --- a/Api/src/main/java/playlist/server/ranking/service/RankingViewService.java +++ b/Api/src/main/java/playlist/server/ranking/service/RankingViewService.java @@ -3,31 +3,20 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; -import playlist.server.domain.domains.ranking.domain.RankingInfo; // RankingInfo enum 추가 +import lombok.RequiredArgsConstructor; @Service +@RequiredArgsConstructor public class RankingViewService { private final RedisTemplate redisTemplate; - @Autowired - public RankingViewService(RedisTemplate redisTemplate) { - this.redisTemplate = redisTemplate; - } - - // 조회수 증가, 랭킹 업데이트 (일간) - public void incrementViews(String boardId, RankingInfo rankingInfo) { - redisTemplate.opsForHash().increment(rankingInfo.getCountsKey(), boardId, 1L); - redisTemplate.opsForZSet().add(rankingInfo.getRankingKey(), boardId, (double) getCurrentViews(rankingInfo.getCountsKey(), boardId)); - } - - // 현재 게시물의 조회수를 가져오는 메서드 - private long getCurrentViews(String hash, String boardId) { - Object views = redisTemplate.opsForHash().get(hash, boardId); - if (views != null) { - return (long) views; - } else { - return 0L; + public void incrementViews(String rankingType, String boardId) { + try { + String countsKey = rankingType + "_VIEW_COUNTS"; + redisTemplate.opsForHash().increment(countsKey, boardId, 1L); + } catch (Exception e) { + throw new RuntimeException("조회수 증가 실패"); } } } diff --git a/Api/src/main/java/playlist/server/search/controller/SearchController.java b/Api/src/main/java/playlist/server/search/controller/SearchController.java index 751d83e..8f32ba1 100644 --- a/Api/src/main/java/playlist/server/search/controller/SearchController.java +++ b/Api/src/main/java/playlist/server/search/controller/SearchController.java @@ -1,5 +1,6 @@ package playlist.server.search.controller; +import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -11,22 +12,19 @@ import java.util.List; @RestController -@RequestMapping("/playlist/server/search") +@RequestMapping("/search") +@RequiredArgsConstructor public class SearchController { private final SearchService searchService; - public SearchController(SearchService searchService) { - this.searchService = searchService; - } - // 태그 기반으로 검색 @GetMapping("/tag") public ResponseEntity> searchByTag(@RequestParam("tag") String tag) { List searchResults = searchService.searchByTag(tag); if (searchResults.isEmpty()) { - return ResponseEntity.notFound().build(); + throw new IllegalArgumentException("해당 태그가 없다"); } return ResponseEntity.ok(searchResults); diff --git a/Api/src/main/java/playlist/server/search/service/SearchService.java b/Api/src/main/java/playlist/server/search/service/SearchService.java index 81b2b7c..5c672e6 100644 --- a/Api/src/main/java/playlist/server/search/service/SearchService.java +++ b/Api/src/main/java/playlist/server/search/service/SearchService.java @@ -1,31 +1,23 @@ package playlist.server.search.service; import org.springframework.stereotype.Service; -import playlist.server.domain.domains.search.domain.Search; import playlist.server.domain.domains.search.repository.SearchRepository; import playlist.server.search.vo.SearchVo; import java.util.List; import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; + @Service +@RequiredArgsConstructor public class SearchService { private final SearchRepository searchRepository; - public SearchService(SearchRepository searchRepository) { - this.searchRepository = searchRepository; - } - public List searchByTag(String tag) { - // 태그를 기반으로 검색 결과를 데이터베이스에서 조회 - List searchEntities = searchRepository.findByTag(tag); - - // 검색 결과를 SearchVo로 변환 - List searchResults = searchEntities.stream() + return searchRepository.findByTag(tag).stream() .map(search -> new SearchVo(search.getTitle(), search.getDescription())) .collect(Collectors.toList()); - - return searchResults; } } diff --git a/Api/src/main/java/playlist/server/search/vo/SearchVo.java b/Api/src/main/java/playlist/server/search/vo/SearchVo.java index 8e0bfb2..06947fb 100644 --- a/Api/src/main/java/playlist/server/search/vo/SearchVo.java +++ b/Api/src/main/java/playlist/server/search/vo/SearchVo.java @@ -1,18 +1,13 @@ package playlist.server.search.vo; -import lombok.AllArgsConstructor; -import lombok.Getter; +import lombok.Data; import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; +import lombok.AllArgsConstructor; +@Data @NoArgsConstructor @AllArgsConstructor -@ToString -@Getter -@Setter public class SearchVo { - private String title; private String description; } diff --git a/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/Ranking.java b/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/Ranking.java deleted file mode 100644 index dc71c60..0000000 --- a/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/Ranking.java +++ /dev/null @@ -1,25 +0,0 @@ -package playlist.server.domain.domains.ranking.domain; - -import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; - -import jakarta.persistence.Table; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Entity -@Getter -@Table(name = "tbl_ranking") -@NoArgsConstructor -public class Ranking { - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Enumerated(EnumType.STRING) - private RankingType rankingType; - - -} diff --git a/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingInfo.java b/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingInfo.java index 2323907..0c6ce23 100644 --- a/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingInfo.java +++ b/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingInfo.java @@ -1,5 +1,10 @@ package playlist.server.domain.domains.ranking.domain; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter public enum RankingInfo { DAILY("like_daily_counts", "like_daily_ranking"), WEEKLY("like_weekly_counts", "like_weekly_ranking"), @@ -7,17 +12,4 @@ public enum RankingInfo { private final String countsKey; private final String rankingKey; - - RankingInfo(String countsKey, String rankingKey) { - this.countsKey = countsKey; - this.rankingKey = rankingKey; - } - - public String getCountsKey() { - return countsKey; - } - - public String getRankingKey() { - return rankingKey; - } } diff --git a/Domain/src/main/java/playlist/server/domain/domains/ranking/repository/RankingRepository.java b/Domain/src/main/java/playlist/server/domain/domains/ranking/repository/RankingRepository.java deleted file mode 100644 index c0cacc5..0000000 --- a/Domain/src/main/java/playlist/server/domain/domains/ranking/repository/RankingRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package playlist.server.domain.domains.ranking.repository; - -import org.springframework.data.jpa.repository.JpaRepository; -import playlist.server.domain.domains.ranking.domain.Ranking; -import playlist.server.domain.domains.ranking.domain.RankingInfo; - - -public interface RankingRepository extends JpaRepository { - Ranking findByRankingInfo(RankingInfo rankingInfo); -} From d922e1ba34ca17742c58d5bc4b4cbd87eb2b1053 Mon Sep 17 00:00:00 2001 From: shin2012649 Date: Fri, 22 Sep 2023 17:59:11 +0900 Subject: [PATCH 4/6] =?UTF-8?q?"=EB=9E=AD=ED=82=B9,=20=EA=B2=80=EC=83=89?= =?UTF-8?q?=20=EA=B4=80=EB=A0=A8=20=EC=BD=94=EB=93=9C=20=EB=A6=AC=EB=B7=B0?= =?UTF-8?q?=20=ED=9B=84=20=EC=88=98=EC=A0=95!=20"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vo/MainPageRankingInfoVo.java | 7 ++- .../ranking/controller/RankingController.java | 50 +++++++------------ .../ranking/service/RankingLikeService.java | 15 +++++- .../ranking/service/RankingService.java | 41 ++++++++------- .../ranking/service/RankingViewService.java | 17 +++++-- .../search/controller/SearchController.java | 8 +-- .../server/search/service/SearchService.java | 7 ++- .../playlist/server/search/vo/SearchVo.java | 3 +- .../server/exception/DataFetchException.java | 10 ++++ .../server/exception/GlobalException.java | 6 ++- .../exception/InvalidParameterException.java | 10 ++++ .../exception/LikeIncrementException.java | 10 ++++ .../exception/TagNotFoundException.java | 15 ++++++ .../exception/ViewIncrementException.java | 10 ++++ .../domains/ranking/domain/RankingInfo.java | 1 + .../domains/ranking/domain/RankingType.java | 12 ++++- .../domain/domains/search/domain/Search.java | 3 +- .../search/repository/SearchRepository.java | 3 +- 18 files changed, 157 insertions(+), 71 deletions(-) create mode 100644 Core/src/main/java/playlist/server/exception/DataFetchException.java create mode 100644 Core/src/main/java/playlist/server/exception/InvalidParameterException.java create mode 100644 Core/src/main/java/playlist/server/exception/LikeIncrementException.java create mode 100644 Core/src/main/java/playlist/server/exception/TagNotFoundException.java create mode 100644 Core/src/main/java/playlist/server/exception/ViewIncrementException.java diff --git a/Api/src/main/java/playlist/server/mainpagerankingInfo/vo/MainPageRankingInfoVo.java b/Api/src/main/java/playlist/server/mainpagerankingInfo/vo/MainPageRankingInfoVo.java index e0d0297..680d574 100644 --- a/Api/src/main/java/playlist/server/mainpagerankingInfo/vo/MainPageRankingInfoVo.java +++ b/Api/src/main/java/playlist/server/mainpagerankingInfo/vo/MainPageRankingInfoVo.java @@ -5,16 +5,21 @@ import playlist.server.domain.domains.ranking.domain.RankingInfo; import playlist.server.domain.domains.ranking.domain.RankingType; +import java.util.List; // 추가 + @Getter @Builder public class MainPageRankingInfoVo { private final RankingInfo rankingInfo; private final RankingType rankingType; + private final List rankingInfoList; + - public static MainPageRankingInfoVo from(RankingInfo rankingInfo, RankingType rankingType) { + public static MainPageRankingInfoVo from(RankingInfo rankingInfo, RankingType rankingType, List rankingInfoList) { return MainPageRankingInfoVo.builder() .rankingInfo(rankingInfo) .rankingType(rankingType) + .rankingInfoList(rankingInfoList) .build(); } } diff --git a/Api/src/main/java/playlist/server/ranking/controller/RankingController.java b/Api/src/main/java/playlist/server/ranking/controller/RankingController.java index 4a89d6d..7c530c5 100644 --- a/Api/src/main/java/playlist/server/ranking/controller/RankingController.java +++ b/Api/src/main/java/playlist/server/ranking/controller/RankingController.java @@ -1,5 +1,6 @@ package playlist.server.ranking.controller; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; @@ -8,6 +9,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import playlist.server.domain.domains.ranking.domain.RankingInfo; import playlist.server.mainpagerankingInfo.vo.MainPageRankingInfoVo; import playlist.server.ranking.service.RankingService; @@ -22,48 +24,34 @@ public class RankingController { @Operation(summary = "랭킹을 조회합니다.") @GetMapping("/daily") public ResponseEntity getDailyRanking( - @RequestParam(name = "type", defaultValue = "like") String type - ) { - try { - MainPageRankingInfoVo rankingInfoVo = rankingService.getRanking("daily", type, "boardId"); - if (rankingInfoVo == null) { - return ResponseEntity.notFound().build(); - } - return ResponseEntity.ok(rankingInfoVo); - } catch (Exception e) { - return ResponseEntity.badRequest().build(); + @RequestParam(name = "type", defaultValue = "like") String type) { + MainPageRankingInfoVo rankingInfoVo = rankingService.getRanking(String.valueOf((RankingInfo.DAILY)), type, "boardId"); + if (rankingInfoVo == null) { + return ResponseEntity.notFound().build(); } + return ResponseEntity.ok(rankingInfoVo); } @Operation(summary = "주간 랭킹을 조회합니다.") @GetMapping("/weekly") public ResponseEntity getWeeklyRanking( - @RequestParam(name = "type", defaultValue = "like") String type - ) { - try { - MainPageRankingInfoVo rankingInfoVo = rankingService.getRanking("weekly", type, "boardId"); - if (rankingInfoVo == null) { - return ResponseEntity.notFound().build(); - } - return ResponseEntity.ok(rankingInfoVo); - } catch (Exception e) { - return ResponseEntity.badRequest().build(); + @RequestParam(name = "type", defaultValue = "like") String type) { + MainPageRankingInfoVo rankingInfoVo = rankingService.getRanking(String.valueOf((RankingInfo.WEEKLY)), type, "boardId"); + if (rankingInfoVo == null) { + return ResponseEntity.notFound().build(); } - } + return ResponseEntity.ok(rankingInfoVo); + } + @Operation(summary = "월간 랭킹을 조회합니다.") @GetMapping("/monthly") public ResponseEntity getMonthlyRanking( - @RequestParam(name = "type", defaultValue = "like") String type - ) { - try { - MainPageRankingInfoVo rankingInfoVo = rankingService.getRanking("monthly", type, "boardId"); - if (rankingInfoVo == null) { - return ResponseEntity.notFound().build(); - } - return ResponseEntity.ok(rankingInfoVo); - } catch (Exception e) { - return ResponseEntity.badRequest().build(); + @RequestParam(name = "type", defaultValue = "like") String type) { + MainPageRankingInfoVo rankingInfoVo = rankingService.getRanking(String.valueOf((RankingInfo.MONTHLY)), type, "boardId"); + if (rankingInfoVo == null) { + return ResponseEntity.notFound().build(); } + return ResponseEntity.ok(rankingInfoVo); } } diff --git a/Api/src/main/java/playlist/server/ranking/service/RankingLikeService.java b/Api/src/main/java/playlist/server/ranking/service/RankingLikeService.java index c76b317..dfa5167 100644 --- a/Api/src/main/java/playlist/server/ranking/service/RankingLikeService.java +++ b/Api/src/main/java/playlist/server/ranking/service/RankingLikeService.java @@ -1,8 +1,14 @@ package playlist.server.ranking.service; + +import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; -import lombok.RequiredArgsConstructor; +import playlist.server.domain.domains.ranking.domain.RankingInfo; +import playlist.server.exception.LikeIncrementException; + +import java.util.Collections; +import java.util.List; @Service @RequiredArgsConstructor @@ -10,12 +16,17 @@ public class RankingLikeService { private final RedisTemplate redisTemplate; + public List getLikeRankingInfoList() { + + return Collections.emptyList(); + } + public void incrementLikes(String rankingType, String boardId) { try { String countsKey = rankingType + "_LIKE_COUNTS"; redisTemplate.opsForHash().increment(countsKey, boardId, 1L); } catch (Exception e) { - throw new RuntimeException("좋아요 증가 실패"); + throw new LikeIncrementException(); } } } diff --git a/Api/src/main/java/playlist/server/ranking/service/RankingService.java b/Api/src/main/java/playlist/server/ranking/service/RankingService.java index 7153044..828ad9a 100644 --- a/Api/src/main/java/playlist/server/ranking/service/RankingService.java +++ b/Api/src/main/java/playlist/server/ranking/service/RankingService.java @@ -1,10 +1,14 @@ package playlist.server.ranking.service; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import playlist.server.domain.domains.ranking.domain.RankingInfo; import playlist.server.domain.domains.ranking.domain.RankingType; import playlist.server.mainpagerankingInfo.vo.MainPageRankingInfoVo; -import lombok.RequiredArgsConstructor; +import playlist.server.domain.domains.ranking.domain.RankingInfo; +import playlist.server.exception.DataFetchException; +import playlist.server.exception.InvalidParameterException; + +import java.util.List; @Service @RequiredArgsConstructor @@ -13,30 +17,25 @@ public class RankingService { private final RankingLikeService rankingLikeService; private final RankingViewService rankingViewService; - public MainPageRankingInfoVo getRanking(String rankingType, String type, String boardId) { + public MainPageRankingInfoVo getRanking(RankingType rankingType, String type, List rankingInfoList) { try { - RankingInfo rankingInfo; - if ("daily".equalsIgnoreCase(rankingType)) { - rankingInfo = RankingInfo.DAILY; - } else if ("weekly".equalsIgnoreCase(rankingType)) { - rankingInfo = RankingInfo.WEEKLY; - } else if ("monthly".equalsIgnoreCase(rankingType)) { - rankingInfo = RankingInfo.MONTHLY; - } else { - throw new IllegalArgumentException("유효하지 않은 랭킹 타입"); - } + String rankingInfoKey = rankingType.getCountsKey(); - if ("like".equals(type)) { - rankingLikeService.incrementLikes(rankingType, boardId); - } else if ("view".equals(type)) { - rankingViewService.incrementViews(rankingType, boardId); + + if (RankingType.LIKE.equals(rankingType) && "like".equals(type)) { + List likeRankingInfoList = rankingLikeService.getLikeRankingInfoList(); // 랭킹 정보를 가져오는 메서드 호출 + rankingLikeService.incrementLikes(rankingInfoKey, boardId); + return MainPageRankingInfoVo.from(null, rankingType, likeRankingInfoList); + } else if (RankingType.VIEW.equals(rankingType) && "view".equals(type)) { + List viewRankingInfoList = rankingViewService.getViewRankingInfoList(); // 랭킹 정보를 가져오는 메서드 호출 + rankingViewService.incrementViews(rankingInfoKey, boardId); + return MainPageRankingInfoVo.from(null, rankingType, viewRankingInfoList); } else { - throw new IllegalArgumentException("유효하지 않은 파라미터"); + throw new InvalidParameterException(); } - - return MainPageRankingInfoVo.from(rankingInfo, RankingType.valueOf(rankingType.toUpperCase())); + return MainPageRankingInfoVo.from(null, rankingType, rankingInfoList); } catch (Exception e) { - throw new RuntimeException("데이터 가져오는거 실패"); + throw new DataFetchException(); } } } diff --git a/Api/src/main/java/playlist/server/ranking/service/RankingViewService.java b/Api/src/main/java/playlist/server/ranking/service/RankingViewService.java index 91b93b2..551abc8 100644 --- a/Api/src/main/java/playlist/server/ranking/service/RankingViewService.java +++ b/Api/src/main/java/playlist/server/ranking/service/RankingViewService.java @@ -1,9 +1,15 @@ package playlist.server.ranking.service; -import org.springframework.beans.factory.annotation.Autowired; + +import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; -import lombok.RequiredArgsConstructor; +import playlist.server.domain.domains.ranking.domain.RankingInfo; +import playlist.server.exception.LikeIncrementException; +import playlist.server.exception.ViewIncrementException; + +import java.util.Collections; +import java.util.List; @Service @RequiredArgsConstructor @@ -11,12 +17,17 @@ public class RankingViewService { private final RedisTemplate redisTemplate; + public List getViewRankingInfoList() { + + return Collections.emptyList(); + } + public void incrementViews(String rankingType, String boardId) { try { String countsKey = rankingType + "_VIEW_COUNTS"; redisTemplate.opsForHash().increment(countsKey, boardId, 1L); } catch (Exception e) { - throw new RuntimeException("조회수 증가 실패"); + throw new ViewIncrementException(); } } } diff --git a/Api/src/main/java/playlist/server/search/controller/SearchController.java b/Api/src/main/java/playlist/server/search/controller/SearchController.java index 8f32ba1..67b0c19 100644 --- a/Api/src/main/java/playlist/server/search/controller/SearchController.java +++ b/Api/src/main/java/playlist/server/search/controller/SearchController.java @@ -1,16 +1,17 @@ package playlist.server.search.controller; + +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import playlist.server.exception.TagNotFoundException; import playlist.server.search.service.SearchService; import playlist.server.search.vo.SearchVo; -import java.util.List; - @RestController @RequestMapping("/search") @RequiredArgsConstructor @@ -24,9 +25,10 @@ public ResponseEntity> searchByTag(@RequestParam("tag") String ta List searchResults = searchService.searchByTag(tag); if (searchResults.isEmpty()) { - throw new IllegalArgumentException("해당 태그가 없다"); + throw TagNotFoundException.EXCEPTION; } return ResponseEntity.ok(searchResults); } + } diff --git a/Api/src/main/java/playlist/server/search/service/SearchService.java b/Api/src/main/java/playlist/server/search/service/SearchService.java index 5c672e6..6a8f608 100644 --- a/Api/src/main/java/playlist/server/search/service/SearchService.java +++ b/Api/src/main/java/playlist/server/search/service/SearchService.java @@ -1,13 +1,12 @@ package playlist.server.search.service; -import org.springframework.stereotype.Service; -import playlist.server.domain.domains.search.repository.SearchRepository; -import playlist.server.search.vo.SearchVo; import java.util.List; import java.util.stream.Collectors; - import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import playlist.server.domain.domains.search.repository.SearchRepository; +import playlist.server.search.vo.SearchVo; @Service @RequiredArgsConstructor diff --git a/Api/src/main/java/playlist/server/search/vo/SearchVo.java b/Api/src/main/java/playlist/server/search/vo/SearchVo.java index 06947fb..3085e20 100644 --- a/Api/src/main/java/playlist/server/search/vo/SearchVo.java +++ b/Api/src/main/java/playlist/server/search/vo/SearchVo.java @@ -1,8 +1,9 @@ package playlist.server.search.vo; + +import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import lombok.AllArgsConstructor; @Data @NoArgsConstructor diff --git a/Core/src/main/java/playlist/server/exception/DataFetchException.java b/Core/src/main/java/playlist/server/exception/DataFetchException.java new file mode 100644 index 0000000..c466867 --- /dev/null +++ b/Core/src/main/java/playlist/server/exception/DataFetchException.java @@ -0,0 +1,10 @@ +package playlist.server.exception; + +public class DataFetchException extends BaseException { + + public static final BaseException EXCEPTION = new DataFetchException(); + + public DataFetchException() { + super(GlobalException.DATA_FETCH_ERROR); + } +} diff --git a/Core/src/main/java/playlist/server/exception/GlobalException.java b/Core/src/main/java/playlist/server/exception/GlobalException.java index 175cce7..e2b9e32 100644 --- a/Core/src/main/java/playlist/server/exception/GlobalException.java +++ b/Core/src/main/java/playlist/server/exception/GlobalException.java @@ -19,7 +19,11 @@ public enum GlobalException implements BaseErrorCode { EXPIRED_REFRESH_TOKEN_ERROR(UNAUTHORIZED.value(), "401-1", "리프레시 토큰이 만료되었습니다."), INVALID_TOKEN_ERROR(UNAUTHORIZED.value(), "401-2", "올바르지 않은 토큰입니다."), DATE_FORMAT_ERROR(BAD_REQUEST.value(), "400-2", "날짜 형식을 확인해주세요."), - ; + LIKE_INCREMENT_ERROR(INTERNAL_SERVER_ERROR.value(), "500-3", "좋아요 증가 실패"), + VIEW_INCREMENT_ERROR(INTERNAL_SERVER_ERROR.value(), "500-3", "조회수 증가 실패"), + TAG_NOT_FOUND(BAD_REQUEST.value(), "400-3", "태그를 찾을 수 없습니다."), + INVALID_PARAMETER_ERROR(BAD_REQUEST.value(), "400-4", "유효하지 않은 파라미터입니다."), + DATA_FETCH_ERROR(INTERNAL_SERVER_ERROR.value(), "500-4", "데이터를 가져오는데 실패하였습니다."); private final Integer statusCode; private final String errorCode; diff --git a/Core/src/main/java/playlist/server/exception/InvalidParameterException.java b/Core/src/main/java/playlist/server/exception/InvalidParameterException.java new file mode 100644 index 0000000..8a70aba --- /dev/null +++ b/Core/src/main/java/playlist/server/exception/InvalidParameterException.java @@ -0,0 +1,10 @@ +package playlist.server.exception; + +public class InvalidParameterException extends BaseException { + + public static final BaseException EXCEPTION = new InvalidParameterException(); + + public InvalidParameterException() { + super(GlobalException.INVALID_PARAMETER_ERROR); + } +} diff --git a/Core/src/main/java/playlist/server/exception/LikeIncrementException.java b/Core/src/main/java/playlist/server/exception/LikeIncrementException.java new file mode 100644 index 0000000..8cbaa3e --- /dev/null +++ b/Core/src/main/java/playlist/server/exception/LikeIncrementException.java @@ -0,0 +1,10 @@ +package playlist.server.exception; + +public class LikeIncrementException extends BaseException { + + public static final BaseException EXCEPTION = new LikeIncrementException(); + + public LikeIncrementException() { + super(GlobalException.LIKE_INCREMENT_ERROR); + } +} diff --git a/Core/src/main/java/playlist/server/exception/TagNotFoundException.java b/Core/src/main/java/playlist/server/exception/TagNotFoundException.java new file mode 100644 index 0000000..70c9729 --- /dev/null +++ b/Core/src/main/java/playlist/server/exception/TagNotFoundException.java @@ -0,0 +1,15 @@ +package playlist.server.exception; + +import playlist.server.exception.BaseErrorCode; +import playlist.server.exception.BaseException; +import static org.springframework.http.HttpStatus.NOT_FOUND; + +public class TagNotFoundException extends BaseException { + + public static final BaseException EXCEPTION = new TagNotFoundException(); + + private TagNotFoundException() { + super(GlobalException.TAG_NOT_FOUND); + } +} + diff --git a/Core/src/main/java/playlist/server/exception/ViewIncrementException.java b/Core/src/main/java/playlist/server/exception/ViewIncrementException.java new file mode 100644 index 0000000..9492715 --- /dev/null +++ b/Core/src/main/java/playlist/server/exception/ViewIncrementException.java @@ -0,0 +1,10 @@ +package playlist.server.exception; + +public class ViewIncrementException extends BaseException { + + public static final BaseException EXCEPTION = new ViewIncrementException(); + + public ViewIncrementException() { + super(GlobalException.VIEW_INCREMENT_ERROR); + } +} diff --git a/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingInfo.java b/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingInfo.java index 0c6ce23..f55a63f 100644 --- a/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingInfo.java +++ b/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingInfo.java @@ -1,5 +1,6 @@ package playlist.server.domain.domains.ranking.domain; + import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingType.java b/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingType.java index 22b7411..374813b 100644 --- a/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingType.java +++ b/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingType.java @@ -8,9 +8,17 @@ public enum RankingType { DAILY("일간"), WEEKLY("주간"), - MONTHLY("월간"); + MONTHLY("월간"), + LIKE("like"), // 좋아요 랭킹 + VIEW("view"); // 조회수 랭킹 private final String description; -} + public String getCountsKey() { + return "like_" + this.name().toLowerCase() + "_counts"; + } + public String getRankingKey() { + return "like_" + this.name().toLowerCase() + "_ranking"; + } +} diff --git a/Domain/src/main/java/playlist/server/domain/domains/search/domain/Search.java b/Domain/src/main/java/playlist/server/domain/domains/search/domain/Search.java index 9ce2021..d507d01 100644 --- a/Domain/src/main/java/playlist/server/domain/domains/search/domain/Search.java +++ b/Domain/src/main/java/playlist/server/domain/domains/search/domain/Search.java @@ -1,12 +1,13 @@ package playlist.server.domain.domains.search.domain; + import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import lombok.Getter; -import lombok.Setter; import lombok.NoArgsConstructor; +import lombok.Setter; @Entity @Getter diff --git a/Domain/src/main/java/playlist/server/domain/domains/search/repository/SearchRepository.java b/Domain/src/main/java/playlist/server/domain/domains/search/repository/SearchRepository.java index 7511142..73bb754 100644 --- a/Domain/src/main/java/playlist/server/domain/domains/search/repository/SearchRepository.java +++ b/Domain/src/main/java/playlist/server/domain/domains/search/repository/SearchRepository.java @@ -1,8 +1,9 @@ package playlist.server.domain.domains.search.repository; + +import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import playlist.server.domain.domains.search.domain.Search; -import java.util.List; public interface SearchRepository extends JpaRepository { List findByTag(String tag); From ae6df9d9634bc37e22a5091a36abdcd3a0451d99 Mon Sep 17 00:00:00 2001 From: donsonioc2010 Date: Fri, 22 Sep 2023 20:55:55 +0900 Subject: [PATCH 5/6] =?UTF-8?q?feat=20:=20Redis=20=EB=9E=AD=ED=82=B9=20?= =?UTF-8?q?=EC=8B=9C=EC=8A=A4=ED=85=9C=20=EC=B4=88=EC=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ranking/controller/RankingController.java | 40 +++---- .../ranking/service/RankingLikeService.java | 32 ------ .../ranking/service/RankingViewService.java | 33 ------ .../ranking/service/RedisRankingService.java | 100 ++++++++++++++++++ .../server/ranking/vo/ResponseRankingDto.java | 28 +++++ .../domains/ranking/domain/RankingInfo.java | 10 +- .../domains/ranking/domain/RankingType.java | 19 ++-- 7 files changed, 163 insertions(+), 99 deletions(-) delete mode 100644 Api/src/main/java/playlist/server/ranking/service/RankingLikeService.java delete mode 100644 Api/src/main/java/playlist/server/ranking/service/RankingViewService.java create mode 100644 Api/src/main/java/playlist/server/ranking/service/RedisRankingService.java create mode 100644 Api/src/main/java/playlist/server/ranking/vo/ResponseRankingDto.java diff --git a/Api/src/main/java/playlist/server/ranking/controller/RankingController.java b/Api/src/main/java/playlist/server/ranking/controller/RankingController.java index 7c530c5..50fdda8 100644 --- a/Api/src/main/java/playlist/server/ranking/controller/RankingController.java +++ b/Api/src/main/java/playlist/server/ranking/controller/RankingController.java @@ -10,8 +10,15 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import playlist.server.domain.domains.ranking.domain.RankingInfo; -import playlist.server.mainpagerankingInfo.vo.MainPageRankingInfoVo; +import playlist.server.domain.domains.ranking.domain.RankingType; import playlist.server.ranking.service.RankingService; +import playlist.server.ranking.vo.ResponseRankingDto; + +import java.util.List; + +import static playlist.server.domain.domains.ranking.domain.RankingInfo.MONTH; +import static playlist.server.domain.domains.ranking.domain.RankingInfo.WEEK; +import static playlist.server.domain.domains.ranking.domain.RankingType.isStringLikeOrView; @RestController @RequestMapping("/ranking") @@ -23,35 +30,28 @@ public class RankingController { @Operation(summary = "랭킹을 조회합니다.") @GetMapping("/daily") - public ResponseEntity getDailyRanking( + public ResponseEntity> getDailyRanking( @RequestParam(name = "type", defaultValue = "like") String type) { - MainPageRankingInfoVo rankingInfoVo = rankingService.getRanking(String.valueOf((RankingInfo.DAILY)), type, "boardId"); - if (rankingInfoVo == null) { - return ResponseEntity.notFound().build(); - } - return ResponseEntity.ok(rankingInfoVo); + return ResponseEntity.ok(getRanking(RankingInfo.DAILY, isStringLikeOrView(type))); } @Operation(summary = "주간 랭킹을 조회합니다.") @GetMapping("/weekly") - public ResponseEntity getWeeklyRanking( + public ResponseEntity> getWeeklyRanking( @RequestParam(name = "type", defaultValue = "like") String type) { - MainPageRankingInfoVo rankingInfoVo = rankingService.getRanking(String.valueOf((RankingInfo.WEEKLY)), type, "boardId"); - if (rankingInfoVo == null) { - return ResponseEntity.notFound().build(); - } - return ResponseEntity.ok(rankingInfoVo); - } + return ResponseEntity.ok(getRanking(WEEK, isStringLikeOrView(type))); + } @Operation(summary = "월간 랭킹을 조회합니다.") @GetMapping("/monthly") - public ResponseEntity getMonthlyRanking( + public ResponseEntity> getMonthlyRanking( @RequestParam(name = "type", defaultValue = "like") String type) { - MainPageRankingInfoVo rankingInfoVo = rankingService.getRanking(String.valueOf((RankingInfo.MONTHLY)), type, "boardId"); - if (rankingInfoVo == null) { - return ResponseEntity.notFound().build(); - } - return ResponseEntity.ok(rankingInfoVo); + return ResponseEntity.ok(getRanking(MONTH, isStringLikeOrView(type))); + } + + + private List getRanking(RankingInfo period, RankingType searchType) { + return rankingService.getRankingList(period, searchType); } } diff --git a/Api/src/main/java/playlist/server/ranking/service/RankingLikeService.java b/Api/src/main/java/playlist/server/ranking/service/RankingLikeService.java deleted file mode 100644 index dfa5167..0000000 --- a/Api/src/main/java/playlist/server/ranking/service/RankingLikeService.java +++ /dev/null @@ -1,32 +0,0 @@ -package playlist.server.ranking.service; - - -import lombok.RequiredArgsConstructor; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Service; -import playlist.server.domain.domains.ranking.domain.RankingInfo; -import playlist.server.exception.LikeIncrementException; - -import java.util.Collections; -import java.util.List; - -@Service -@RequiredArgsConstructor -public class RankingLikeService { - - private final RedisTemplate redisTemplate; - - public List getLikeRankingInfoList() { - - return Collections.emptyList(); - } - - public void incrementLikes(String rankingType, String boardId) { - try { - String countsKey = rankingType + "_LIKE_COUNTS"; - redisTemplate.opsForHash().increment(countsKey, boardId, 1L); - } catch (Exception e) { - throw new LikeIncrementException(); - } - } -} diff --git a/Api/src/main/java/playlist/server/ranking/service/RankingViewService.java b/Api/src/main/java/playlist/server/ranking/service/RankingViewService.java deleted file mode 100644 index 551abc8..0000000 --- a/Api/src/main/java/playlist/server/ranking/service/RankingViewService.java +++ /dev/null @@ -1,33 +0,0 @@ -package playlist.server.ranking.service; - - -import lombok.RequiredArgsConstructor; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Service; -import playlist.server.domain.domains.ranking.domain.RankingInfo; -import playlist.server.exception.LikeIncrementException; -import playlist.server.exception.ViewIncrementException; - -import java.util.Collections; -import java.util.List; - -@Service -@RequiredArgsConstructor -public class RankingViewService { - - private final RedisTemplate redisTemplate; - - public List getViewRankingInfoList() { - - return Collections.emptyList(); - } - - public void incrementViews(String rankingType, String boardId) { - try { - String countsKey = rankingType + "_VIEW_COUNTS"; - redisTemplate.opsForHash().increment(countsKey, boardId, 1L); - } catch (Exception e) { - throw new ViewIncrementException(); - } - } -} diff --git a/Api/src/main/java/playlist/server/ranking/service/RedisRankingService.java b/Api/src/main/java/playlist/server/ranking/service/RedisRankingService.java new file mode 100644 index 0000000..1832903 --- /dev/null +++ b/Api/src/main/java/playlist/server/ranking/service/RedisRankingService.java @@ -0,0 +1,100 @@ +package playlist.server.ranking.service; + + +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; +import playlist.server.domain.domains.ranking.domain.RankingInfo; +import playlist.server.domain.domains.ranking.domain.RankingType; +import playlist.server.ranking.vo.ResponseRankingDto; + +import java.util.Arrays; +import java.util.List; + +/** + * 참고한 Reference : https://cantcoding.tistory.com/82 + */ +@Service +@RequiredArgsConstructor +public class RedisRankingService implements RankingService { + + private final RedisTemplate redisTemplate; + + /** + * 랭킹 리스트를 0~10까지 가져온다. + * @param period + * @param type + * @return + */ + @Override + public List getRankingList(RankingInfo period, RankingType type) { + return redisTemplate.opsForZSet() + .reverseRangeWithScores(getRankingTypeKey(period, type), 0, 10) + .stream() + .map(ResponseRankingDto::convertToResponseRankingDto).toList(); + } + + /** + * Like, View의 Daily, Week, Month의 카운트를 모두 증가시킨다. + * + * @param type + * @param boardId + */ + @Override + public void incrementCountProcess(RankingType type, String boardId) { + Arrays.stream(RankingInfo.values()).forEach(period -> { + if (isExistInRanking(period, type, boardId)) { + incrementRankingCount(period, type, boardId); + } else { + addRanking(period, type, boardId); + } + }); + } + + + /** + * 현재 ZSet에 값이 존재하는지 확인한다. + * @param period + * @param type + * @param boardId + * @return + */ + private boolean isExistInRanking(RankingInfo period, RankingType type, String boardId) { + return redisTemplate.opsForZSet() + .score(getRankingTypeKey(period, type), boardId) != null; + } + + /** + * 값이 존재하지 않는 경우 Default Value로 1을 제공한다. + * + * @param period + * @param type + * @param boardId + */ + private void addRanking(RankingInfo period, RankingType type, String boardId) { + redisTemplate.opsForZSet().add(getRankingTypeKey(period, type), boardId, 1); + } + + /** + * Zset에 존재하는 경우 해당 값을 증가시킨다 + * + * @param period + * @param type + * @param boardId + */ + private void incrementRankingCount(RankingInfo period, RankingType type, String boardId) { + redisTemplate.opsForZSet() + .incrementScore(getRankingTypeKey(period, type), boardId, 1); + } + + /** + * Type에 따라 Key를 다르게 가져온다. + * + * @param period + * @param type + * @return + */ + private String getRankingTypeKey(RankingInfo period, RankingType type) { + return RankingType.LIKE.equals(type) ? period.getLikeKey() : period.getViewKey(); + } +} diff --git a/Api/src/main/java/playlist/server/ranking/vo/ResponseRankingDto.java b/Api/src/main/java/playlist/server/ranking/vo/ResponseRankingDto.java new file mode 100644 index 0000000..4040a1e --- /dev/null +++ b/Api/src/main/java/playlist/server/ranking/vo/ResponseRankingDto.java @@ -0,0 +1,28 @@ +package playlist.server.ranking.vo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.data.redis.core.ZSetOperations; + +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ResponseRankingDto { + private String boardId; + private Long score; + + public static ResponseRankingDto convertToResponseRankingDto(ZSetOperations.TypedTuple typedTuple) { + return ResponseRankingDto.builder() + .boardId(typedTuple.getValue().toString()) + .score(typedTuple.getScore().longValue()) + .build(); + } + +} + + diff --git a/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingInfo.java b/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingInfo.java index f55a63f..8d152be 100644 --- a/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingInfo.java +++ b/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingInfo.java @@ -7,10 +7,10 @@ @AllArgsConstructor @Getter public enum RankingInfo { - DAILY("like_daily_counts", "like_daily_ranking"), - WEEKLY("like_weekly_counts", "like_weekly_ranking"), - MONTHLY("like_monthly_counts", "like_monthly_ranking"); + DAILY("daily_like", "daily_view"), + WEEK("week_like", "week_view"), + MONTH("month_like", "month_view"); - private final String countsKey; - private final String rankingKey; + private final String likeKey; + private final String viewKey; } diff --git a/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingType.java b/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingType.java index 374813b..c069753 100644 --- a/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingType.java +++ b/Domain/src/main/java/playlist/server/domain/domains/ranking/domain/RankingType.java @@ -6,19 +6,20 @@ @AllArgsConstructor @Getter public enum RankingType { - DAILY("일간"), - WEEKLY("주간"), - MONTHLY("월간"), LIKE("like"), // 좋아요 랭킹 VIEW("view"); // 조회수 랭킹 private final String description; - public String getCountsKey() { - return "like_" + this.name().toLowerCase() + "_counts"; - } - - public String getRankingKey() { - return "like_" + this.name().toLowerCase() + "_ranking"; + /** + * 문자열을 LIKE인지 확인한다, 아닌 경우에는 VIEW를 Return 한다. + * @param type + * @return + */ + public static RankingType isStringLikeOrView(String type) { + if(type.toLowerCase().equals(LIKE.description) ) { + return LIKE; + } + return VIEW; } } From ac8c5307c921c51c2ef1edbdb00118308e39afa4 Mon Sep 17 00:00:00 2001 From: donsonioc2010 Date: Fri, 22 Sep 2023 21:28:52 +0900 Subject: [PATCH 6/6] =?UTF-8?q?feat=20:=20Redis=20=EB=9E=AD=ED=82=B9=20Int?= =?UTF-8?q?erface=20=EC=B6=94=EA=B0=80=EC=A0=9C=EC=9E=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ranking/service/RankingService.java | 37 +++---------------- 1 file changed, 5 insertions(+), 32 deletions(-) diff --git a/Api/src/main/java/playlist/server/ranking/service/RankingService.java b/Api/src/main/java/playlist/server/ranking/service/RankingService.java index 828ad9a..3090d9a 100644 --- a/Api/src/main/java/playlist/server/ranking/service/RankingService.java +++ b/Api/src/main/java/playlist/server/ranking/service/RankingService.java @@ -1,41 +1,14 @@ package playlist.server.ranking.service; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import playlist.server.domain.domains.ranking.domain.RankingType; -import playlist.server.mainpagerankingInfo.vo.MainPageRankingInfoVo; import playlist.server.domain.domains.ranking.domain.RankingInfo; -import playlist.server.exception.DataFetchException; -import playlist.server.exception.InvalidParameterException; +import playlist.server.domain.domains.ranking.domain.RankingType; +import playlist.server.ranking.vo.ResponseRankingDto; import java.util.List; -@Service -@RequiredArgsConstructor -public class RankingService { - - private final RankingLikeService rankingLikeService; - private final RankingViewService rankingViewService; - - public MainPageRankingInfoVo getRanking(RankingType rankingType, String type, List rankingInfoList) { - try { - String rankingInfoKey = rankingType.getCountsKey(); +public interface RankingService { + List getRankingList(RankingInfo period, RankingType type); - if (RankingType.LIKE.equals(rankingType) && "like".equals(type)) { - List likeRankingInfoList = rankingLikeService.getLikeRankingInfoList(); // 랭킹 정보를 가져오는 메서드 호출 - rankingLikeService.incrementLikes(rankingInfoKey, boardId); - return MainPageRankingInfoVo.from(null, rankingType, likeRankingInfoList); - } else if (RankingType.VIEW.equals(rankingType) && "view".equals(type)) { - List viewRankingInfoList = rankingViewService.getViewRankingInfoList(); // 랭킹 정보를 가져오는 메서드 호출 - rankingViewService.incrementViews(rankingInfoKey, boardId); - return MainPageRankingInfoVo.from(null, rankingType, viewRankingInfoList); - } else { - throw new InvalidParameterException(); - } - return MainPageRankingInfoVo.from(null, rankingType, rankingInfoList); - } catch (Exception e) { - throw new DataFetchException(); - } - } + void incrementCountProcess(RankingType type, String boardId); }