From 19d160886bc342cbea1d282059c7f627ed681935 Mon Sep 17 00:00:00 2001 From: lilloo04 Date: Tue, 14 Oct 2025 23:30:31 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EB=82=98=EC=9D=98=20=EC=97=AC=ED=96=89?= =?UTF-8?q?=EC=A7=80=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B2=80=EC=83=89=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/PlaceSaveController.java | 18 ++++++++-- .../userPlace/service/UserPlaceService.java | 34 ++++++++++++------- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/comma/soomteum/domain/userPlace/controller/PlaceSaveController.java b/src/main/java/com/comma/soomteum/domain/userPlace/controller/PlaceSaveController.java index bc480d9..da166b0 100644 --- a/src/main/java/com/comma/soomteum/domain/userPlace/controller/PlaceSaveController.java +++ b/src/main/java/com/comma/soomteum/domain/userPlace/controller/PlaceSaveController.java @@ -79,7 +79,18 @@ public ResponseEntity> unsave( @Operation( summary = "내 저장 목록 조회", - description = "현재 로그인 사용자의 저장 목록을 페이징으로 조회합니다.", + description = """ + 현재 로그인 사용자의 저장 목록을 페이징으로 조회합니다. + + **검색 기능:** + - `keyword`: 장소명으로 검색 (부분 일치, 대소문자 무관) + - 검색어가 없으면 전체 목록 반환 + + **예시:** + - `/api/my/places?page=0&size=20` - 전체 목록 조회 + - `/api/my/places?keyword=경복궁` - "경복궁" 포함 장소만 조회 + - `/api/my/places?keyword=바다&page=0&size=10` - "바다" 검색 + 페이징 + """, security = @SecurityRequirement(name = "JWT TOKEN") ) @ApiResponses({ @@ -90,9 +101,10 @@ public ResponseEntity> unsave( public ResponseEntity> mySaved( @Parameter(hidden = true) @LoginUser User user, @Parameter(description = "페이지 번호 (0부터 시작)") @RequestParam(value = "page", defaultValue = "0") int page, - @Parameter(description = "페이지 크기") @RequestParam(value = "size", defaultValue = "20") int size) { + @Parameter(description = "페이지 크기") @RequestParam(value = "size", defaultValue = "20") int size, + @Parameter(description = "장소명 검색어 (부분 일치)") @RequestParam(value = "keyword", required = false) String keyword) { - var result = userPlaceService.getMyPlaces(user.getUserId (), UserActionType.SAVE, page, size); + var result = userPlaceService.getMyPlaces(user.getUserId(), UserActionType.SAVE, page, size, keyword); return ResponseEntity.ok(ApiResponse.ok(result)); } diff --git a/src/main/java/com/comma/soomteum/domain/userPlace/service/UserPlaceService.java b/src/main/java/com/comma/soomteum/domain/userPlace/service/UserPlaceService.java index afa8a1b..330df0f 100644 --- a/src/main/java/com/comma/soomteum/domain/userPlace/service/UserPlaceService.java +++ b/src/main/java/com/comma/soomteum/domain/userPlace/service/UserPlaceService.java @@ -161,24 +161,34 @@ public long getActionCountByContentId(String contentId, UserActionType type) { } @Transactional(readOnly = true) - public UserPlacePageResponseDto getMyPlaces(Long userId, UserActionType type, int page, int size) { + public UserPlacePageResponseDto getMyPlaces(Long userId, UserActionType type, int page, int size, String keyword) { userRepository.findById(userId) .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); var pageable = org.springframework.data.domain.PageRequest.of(page, size); var pageResult = userPlaceRepository.findByUser_UserIdAndType(userId, type, pageable); - var items = pageResult.getContent().stream().map(up -> { - var place = up.getPlace(); - return UserPlaceItemDto.builder() - .cnctrLevel(place.getCnctrLevel()) - .contentId(place.getContentId()) - .placeName(place.getName()) - .likeCount(place.getLikeCount()) - .themeName(place.getTheme() != null ? place.getTheme().getName() : null) - .savedAt(up.getCreatedAt()) - .build(); - }).toList(); + var items = pageResult.getContent().stream() + // 검색 필터링 + .filter(up -> { + if (keyword == null || keyword.isBlank()) { + return true; // 검색어 없으면 모두 통과 + } + String placeName = up.getPlace().getName(); + return placeName != null && placeName.toLowerCase() + .contains(keyword.toLowerCase()); + }) + .map(up -> { + var place = up.getPlace(); + return UserPlaceItemDto.builder() + .cnctrLevel(place.getCnctrLevel()) + .contentId(place.getContentId()) + .placeName(place.getName()) + .likeCount(place.getLikeCount()) + .themeName(place.getTheme() != null ? place.getTheme().getName() : null) + .savedAt(up.getCreatedAt()) + .build(); + }).toList(); return UserPlacePageResponseDto.of( items,