diff --git a/src/main/java/goorm/ddok/member/repository/UserRepository.java b/src/main/java/goorm/ddok/member/repository/UserRepository.java index 9ef2a7a9..1d3a846b 100644 --- a/src/main/java/goorm/ddok/member/repository/UserRepository.java +++ b/src/main/java/goorm/ddok/member/repository/UserRepository.java @@ -226,4 +226,33 @@ interface UserOverlayRow { ORDER BY LOWER(u.nickname) ASC, u.id ASC """) Page searchPlayersWithKeyword(@Param("keyword") String keyword, Pageable pageable); + + @Query(""" + SELECT DISTINCT u.id, LOWER(u.nickname) as nickname_lower FROM User u + LEFT JOIN u.location loc + LEFT JOIN u.positions pos + WHERE (:keyword IS NULL OR :keyword = '' OR + LOWER(u.nickname) LIKE LOWER(CONCAT('%', :keyword, '%')) OR + LOWER(pos.positionName) LIKE LOWER(CONCAT('%', :keyword, '%')) OR + LOWER(COALESCE(loc.region1DepthName, '')) LIKE LOWER(CONCAT('%', :keyword, '%')) OR + LOWER(COALESCE(loc.region2DepthName, '')) LIKE LOWER(CONCAT('%', :keyword, '%')) OR + LOWER(COALESCE(loc.region3DepthName, '')) LIKE LOWER(CONCAT('%', :keyword, '%')) OR + LOWER(COALESCE(loc.roadName, '')) LIKE LOWER(CONCAT('%', :keyword, '%')) OR + LOWER(COALESCE(loc.mainBuildingNo, '')) LIKE LOWER(CONCAT('%', :keyword, '%')) OR + LOWER(COALESCE(loc.subBuildingNo, '')) LIKE LOWER(CONCAT('%', :keyword, '%')) OR + LOWER(CONCAT(COALESCE(loc.region1DepthName, ''), ' ', COALESCE(loc.region2DepthName, ''))) LIKE LOWER(CONCAT('%', :keyword, '%')) + ) + ORDER BY LOWER(u.nickname) ASC, u.id ASC + """) + Page searchPlayerIdsWithKeywordAndNickname(@Param("keyword") String keyword, Pageable pageable); + + // 2단계: ID 리스트로 User 엔티티 조회 (정렬 유지) + @Query(""" + SELECT u FROM User u + LEFT JOIN FETCH u.location + LEFT JOIN FETCH u.positions + WHERE u.id IN :userIds + ORDER BY LOWER(u.nickname) ASC, u.id ASC + """) + List findUsersByIdsWithDetails(@Param("userIds") List userIds); } diff --git a/src/main/java/goorm/ddok/player/service/ProfileSearchService.java b/src/main/java/goorm/ddok/player/service/ProfileSearchService.java index e59ac086..f0811513 100644 --- a/src/main/java/goorm/ddok/player/service/ProfileSearchService.java +++ b/src/main/java/goorm/ddok/player/service/ProfileSearchService.java @@ -44,28 +44,40 @@ public Page searchPlayers(String keyword, int page, int s size = (size <= 0) ? 10 : size; Pageable pageable = PageRequest.of(page, size); - String searchKeyword = hasText(keyword) ? keyword.trim() : null; - Page rows = userRepository.searchPlayersWithKeyword(searchKeyword, pageable); + // 1단계: ID와 정렬용 nickname 조회 + Page userIdPage = userRepository.searchPlayerIdsWithKeywordAndNickname(searchKeyword, pageable); + + if (userIdPage.getContent().isEmpty()) { + return new PageImpl<>(Collections.emptyList(), pageable, 0); + } + + // ID만 추출 (이미 정렬된 순서) + List userIds = userIdPage.getContent().stream() + .map(row -> (Long) row[0]) + .toList(); + + // 2단계: User 엔티티 조회 (정렬 순서 유지) + List users = userRepository.findUsersByIdsWithDetails(userIds); - List distinctUsers = rows.getContent().stream() - .collect(Collectors.toMap(User::getId, user -> user, (existing, replacement) -> existing)) - .values() - .stream() - .sorted((u1, u2) -> { - int nicknameCompare = u1.getNickname().compareToIgnoreCase(u2.getNickname()); - return nicknameCompare != 0 ? nicknameCompare : u1.getId().compareTo(u2.getId()); - }) + // ID 순서대로 정렬 (첫 번째 쿼리의 정렬 순서 유지) + Map userMap = users.stream() + .collect(Collectors.toMap(User::getId, user -> user)); + + List sortedUsers = userIds.stream() + .map(userMap::get) + .filter(Objects::nonNull) .toList(); - List responses = distinctUsers.stream() + List responses = sortedUsers.stream() .map(u -> toResponse(u, currentUserId)) .toList(); - return new PageImpl<>(responses, pageable, rows.getTotalElements()); + return new PageImpl<>(responses, pageable, userIdPage.getTotalElements()); } + // 나머지 메서드들은 그대로 유지 private ProfileSearchResponse toResponse(User u, Long currentUserId) { // 기존 코드 그대로