From 5f2a8f3fcd7fcc0a48f5a480124de1c61d8ff1a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=84=9D?= Date: Tue, 13 Aug 2024 05:36:33 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat=20:=20keyword=20=EA=B2=80=EC=83=89=20?= =?UTF-8?q?=EC=97=94=EC=A7=84=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/exception/KeywordException.java | 16 +++++++++ .../KeywordExceptionControllerAdvice.java | 24 +++++++++++++ .../ReferenceExceptionControllerAdvice.java | 2 +- .../status/BaseExceptionResponseStatus.java | 4 ++- .../itpick/backend/config/WebConfig.java | 2 +- .../backend/controller/KeywordController.java | 34 +++++++++++++++++++ .../backend/repository/KeywordRepository.java | 5 +++ .../backend/service/KeywordService.java | 13 +++++++ 8 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 src/main/java/store/itpick/backend/common/exception/KeywordException.java create mode 100644 src/main/java/store/itpick/backend/common/exception_handler/KeywordExceptionControllerAdvice.java create mode 100644 src/main/java/store/itpick/backend/controller/KeywordController.java diff --git a/src/main/java/store/itpick/backend/common/exception/KeywordException.java b/src/main/java/store/itpick/backend/common/exception/KeywordException.java new file mode 100644 index 0000000..d47a855 --- /dev/null +++ b/src/main/java/store/itpick/backend/common/exception/KeywordException.java @@ -0,0 +1,16 @@ +package store.itpick.backend.common.exception; + + +import lombok.Getter; +import store.itpick.backend.common.response.status.ResponseStatus; + +@Getter +public class KeywordException extends RuntimeException{ + private final ResponseStatus exceptionStatus; + + public KeywordException(ResponseStatus exceptionStatus) { + super(exceptionStatus.getMessage()); + this.exceptionStatus = exceptionStatus; + } + +} \ No newline at end of file diff --git a/src/main/java/store/itpick/backend/common/exception_handler/KeywordExceptionControllerAdvice.java b/src/main/java/store/itpick/backend/common/exception_handler/KeywordExceptionControllerAdvice.java new file mode 100644 index 0000000..a28a2b7 --- /dev/null +++ b/src/main/java/store/itpick/backend/common/exception_handler/KeywordExceptionControllerAdvice.java @@ -0,0 +1,24 @@ +package store.itpick.backend.common.exception_handler; + + +import jakarta.annotation.Priority; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import store.itpick.backend.common.exception.KeywordException; +import store.itpick.backend.common.exception.ReferenceException; +import store.itpick.backend.common.response.BaseErrorResponse; + +@Slf4j +@Priority(0) +@RestControllerAdvice +public class KeywordExceptionControllerAdvice { + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ExceptionHandler(KeywordException.class) + public BaseErrorResponse handle_UserException(KeywordException e) { + log.error("[handle_KeywordException]", e); + return new BaseErrorResponse(e.getExceptionStatus(), e.getMessage()); + } +} diff --git a/src/main/java/store/itpick/backend/common/exception_handler/ReferenceExceptionControllerAdvice.java b/src/main/java/store/itpick/backend/common/exception_handler/ReferenceExceptionControllerAdvice.java index 6fe21e6..32f956c 100644 --- a/src/main/java/store/itpick/backend/common/exception_handler/ReferenceExceptionControllerAdvice.java +++ b/src/main/java/store/itpick/backend/common/exception_handler/ReferenceExceptionControllerAdvice.java @@ -19,7 +19,7 @@ public class ReferenceExceptionControllerAdvice { @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(ReferenceException.class) public BaseErrorResponse handle_UserException(ReferenceException e) { - log.error("[handle_UserException]", e); + log.error("[handle_ReferenceException]", e); return new BaseErrorResponse(e.getExceptionStatus(), e.getMessage()); } } diff --git a/src/main/java/store/itpick/backend/common/response/status/BaseExceptionResponseStatus.java b/src/main/java/store/itpick/backend/common/response/status/BaseExceptionResponseStatus.java index 435686f..32a7b71 100644 --- a/src/main/java/store/itpick/backend/common/response/status/BaseExceptionResponseStatus.java +++ b/src/main/java/store/itpick/backend/common/response/status/BaseExceptionResponseStatus.java @@ -87,7 +87,9 @@ public enum BaseExceptionResponseStatus implements ResponseStatus { INVALID_REFERENCE(8000,HttpStatus.BAD_REQUEST.value(),"잘못된 관련자료 요청입니다"), NO_Search_REFERENCE(8001,HttpStatus.BAD_REQUEST.value(),"관련자료를 뉴스에서 검색하지 못하였습니다"), - EMPTY_REFERENCE(8002,HttpStatus.BAD_REQUEST.value(),"해당 키워드의 관련자료를 찾지 못하였습니다"); + EMPTY_REFERENCE(8002,HttpStatus.BAD_REQUEST.value(),"해당 키워드의 관련자료를 찾지 못하였습니다"), + + NO_SEARCH_KEYWORD(8004,HttpStatus.BAD_REQUEST.value(),"관련된 키워드를 찾지 못했습니다"); diff --git a/src/main/java/store/itpick/backend/config/WebConfig.java b/src/main/java/store/itpick/backend/config/WebConfig.java index afc0451..acce18f 100644 --- a/src/main/java/store/itpick/backend/config/WebConfig.java +++ b/src/main/java/store/itpick/backend/config/WebConfig.java @@ -26,7 +26,7 @@ public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(jwtAuthenticationInterceptor) .order(1) .addPathPatterns("/**") - .excludePathPatterns("/auth/login", "/auth/signup", "/auth/refresh","/auth/emails/**", "/rank/**","/auth/email/check","/auth/nickname/check","/favicon.ico"); + .excludePathPatterns("/auth/login", "/auth/signup", "/auth/refresh","/auth/emails/**", "/rank/**","/auth/email/check","/auth/nickname/check","/favicon.ico","/keyword/**"); //인터셉터 적용 범위 수정 registry.addInterceptor(getJwtInterceptor) .addPathPatterns("/user/email"); diff --git a/src/main/java/store/itpick/backend/controller/KeywordController.java b/src/main/java/store/itpick/backend/controller/KeywordController.java new file mode 100644 index 0000000..a080085 --- /dev/null +++ b/src/main/java/store/itpick/backend/controller/KeywordController.java @@ -0,0 +1,34 @@ +package store.itpick.backend.controller; + +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 store.itpick.backend.common.exception.KeywordException; +import store.itpick.backend.common.response.BaseResponse; +import store.itpick.backend.model.Keyword; +import store.itpick.backend.service.KeywordService; + +import java.util.List; + +import static store.itpick.backend.common.response.status.BaseExceptionResponseStatus.EMPTY_REFERENCE; +import static store.itpick.backend.common.response.status.BaseExceptionResponseStatus.NO_SEARCH_KEYWORD; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/keyword") +public class KeywordController { + + private final KeywordService keywordService; + + @GetMapping("/search") + public BaseResponse> searchKeywords(@RequestParam String query) { + List keywords = keywordService.searchKeywords(query); + if(keywords.isEmpty()){ + throw new KeywordException(NO_SEARCH_KEYWORD); + } + return new BaseResponse<>(keywords); + } +} diff --git a/src/main/java/store/itpick/backend/repository/KeywordRepository.java b/src/main/java/store/itpick/backend/repository/KeywordRepository.java index f7ff3a3..56497a6 100644 --- a/src/main/java/store/itpick/backend/repository/KeywordRepository.java +++ b/src/main/java/store/itpick/backend/repository/KeywordRepository.java @@ -34,4 +34,9 @@ Optional findTop1ByKeywordAndCommunityOrderByUpdatedAtDesc(@Param("keyw @Query("SELECT k FROM Keyword k JOIN k.communityPeriods cp WHERE cp.community = 'zum' ORDER BY k.updateAt DESC") List findTop10ByCommunityZum(Pageable pageable); + + /** 검색할때 사용하는 JPA **/ + List findByKeywordContainingIgnoreCase(String substring); + + } \ No newline at end of file diff --git a/src/main/java/store/itpick/backend/service/KeywordService.java b/src/main/java/store/itpick/backend/service/KeywordService.java index 77fe943..5a476ac 100644 --- a/src/main/java/store/itpick/backend/service/KeywordService.java +++ b/src/main/java/store/itpick/backend/service/KeywordService.java @@ -15,6 +15,7 @@ import java.time.Instant; import java.time.ZoneId; import java.time.format.DateTimeFormatter; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.Set; @@ -176,4 +177,16 @@ public void performDailyTasksZum() { keywordRepository.save(keyword); // 연관관계 업데이트 후 저장 } } + + public List searchKeywords(String keyword) { + List keywordList= keywordRepository.findByKeywordContainingIgnoreCase(keyword); + List keywords= new ArrayList<>(); + for (Keyword keyword1 : keywordList) { + keywords.add(keyword1.getKeyword()); + } + + return keywords; + } + + } From 59d52c774c2d3dc5c4ca3cfd2d9329bb282ad18a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=84=9D?= Date: Tue, 13 Aug 2024 06:01:26 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat=20:=20=ED=82=A4=EC=9B=8C=EB=93=9C=20?= =?UTF-8?q?=EA=B2=80=EC=83=89(=EB=B1=83=EC=A7=80=EB=8F=84=20=EA=B0=99?= =?UTF-8?q?=EC=9D=B4=20response)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/controller/KeywordController.java | 11 ++++++- .../itpick/backend/dto/keyword/SearchDTO.java | 14 +++++++++ .../backend/repository/KeywordRepository.java | 2 +- .../backend/service/KeywordService.java | 31 +++++++++++++++---- 4 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 src/main/java/store/itpick/backend/dto/keyword/SearchDTO.java diff --git a/src/main/java/store/itpick/backend/controller/KeywordController.java b/src/main/java/store/itpick/backend/controller/KeywordController.java index a080085..5429f3e 100644 --- a/src/main/java/store/itpick/backend/controller/KeywordController.java +++ b/src/main/java/store/itpick/backend/controller/KeywordController.java @@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.RestController; import store.itpick.backend.common.exception.KeywordException; import store.itpick.backend.common.response.BaseResponse; +import store.itpick.backend.dto.keyword.SearchDTO; import store.itpick.backend.model.Keyword; import store.itpick.backend.service.KeywordService; @@ -23,7 +24,7 @@ public class KeywordController { private final KeywordService keywordService; - @GetMapping("/search") + @GetMapping("/search/nobadge") public BaseResponse> searchKeywords(@RequestParam String query) { List keywords = keywordService.searchKeywords(query); if(keywords.isEmpty()){ @@ -31,4 +32,12 @@ public BaseResponse> searchKeywords(@RequestParam String query) { } return new BaseResponse<>(keywords); } + @GetMapping("/search") + public BaseResponse> searchKeywordsWithBadge(@RequestParam String query) { + List keywords = keywordService.searchKeywordsWithBadge(query); + if(keywords.isEmpty()){ + throw new KeywordException(NO_SEARCH_KEYWORD); + } + return new BaseResponse<>(keywords); + } } diff --git a/src/main/java/store/itpick/backend/dto/keyword/SearchDTO.java b/src/main/java/store/itpick/backend/dto/keyword/SearchDTO.java new file mode 100644 index 0000000..d9c47bf --- /dev/null +++ b/src/main/java/store/itpick/backend/dto/keyword/SearchDTO.java @@ -0,0 +1,14 @@ +package store.itpick.backend.dto.keyword; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class SearchDTO { + private String keyword; + private long nateRank; + private long naverRank; + private long zumRank; +} + diff --git a/src/main/java/store/itpick/backend/repository/KeywordRepository.java b/src/main/java/store/itpick/backend/repository/KeywordRepository.java index 56497a6..292db93 100644 --- a/src/main/java/store/itpick/backend/repository/KeywordRepository.java +++ b/src/main/java/store/itpick/backend/repository/KeywordRepository.java @@ -36,7 +36,7 @@ Optional findTop1ByKeywordAndCommunityOrderByUpdatedAtDesc(@Param("keyw /** 검색할때 사용하는 JPA **/ - List findByKeywordContainingIgnoreCase(String substring); + List findByKeywordStartingWithIgnoreCase(String substring); } \ No newline at end of file diff --git a/src/main/java/store/itpick/backend/service/KeywordService.java b/src/main/java/store/itpick/backend/service/KeywordService.java index 5a476ac..6263ea0 100644 --- a/src/main/java/store/itpick/backend/service/KeywordService.java +++ b/src/main/java/store/itpick/backend/service/KeywordService.java @@ -6,19 +6,21 @@ import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import store.itpick.backend.dto.keyword.SearchDTO; +import store.itpick.backend.dto.redis.RankDTO; +import store.itpick.backend.dto.redis.RankListForKeyword; import store.itpick.backend.model.CommunityPeriod; import store.itpick.backend.model.Keyword; +import store.itpick.backend.model.rank.PeriodType; import store.itpick.backend.repository.CommunityPeriodRepository; import store.itpick.backend.repository.KeywordRepository; +import store.itpick.backend.util.Redis; import java.sql.Timestamp; import java.time.Instant; import java.time.ZoneId; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; @Service @@ -28,6 +30,7 @@ public class KeywordService { private final KeywordRepository keywordRepository; private final CommunityPeriodRepository communityPeriodRepository; + private final Redis redis; @@ -179,14 +182,30 @@ public void performDailyTasksZum() { } public List searchKeywords(String keyword) { - List keywordList= keywordRepository.findByKeywordContainingIgnoreCase(keyword); + List keywordList= keywordRepository.findByKeywordStartingWithIgnoreCase(keyword); List keywords= new ArrayList<>(); for (Keyword keyword1 : keywordList) { keywords.add(keyword1.getKeyword()); } - return keywords; } + public List searchKeywordsWithBadge(String keyword) { + List keywordList= keywordRepository.findByKeywordStartingWithIgnoreCase(keyword); + List keywords= new ArrayList<>(); + for (Keyword keyword1 : keywordList) { + keywords.add(keyword1.getKeyword()); + } + + List rankingList = new ArrayList<>(); + for (String keywordBadge : keywords) { + RankListForKeyword rankingBadgeResponse = redis.getRankingBadgeResponse(keywordBadge, PeriodType.BY_REAL_TIME, ""); + rankingList.add(new SearchDTO(keywordBadge, rankingBadgeResponse.getNateRank(), rankingBadgeResponse.getNaverRank(), rankingBadgeResponse.getZumRank())); + } + return rankingList; + } + + + }