나와바리 - (검색결과)페이징처리

Sungmin·2023년 6월 20일
0

내가 만들어놓은 통합검색 기능에 페이징처리를 추가하는 작업을 진행하였다.
페이징 방식은 무한스크롤 방식이다.

🔔 No - Offset

No - Offset 방식은 조회 시작하는 부분을 인덱스로 빠르게 찾아서 매번 첫 페이지만 읽도록 하는 방식이다.

기존의 Offset방식은 만약 Offset이 100이고 limit이 10이면 처음부터 100까지 모든 데이터를 가져오고 limit만큼만 반환해 준다. 이 방식을 사용할 수는 있지만 성능상 효율적이지 않아 사용한 방식이 No - Offset이다.


🔔 Slice

Slice 형태로 응답했을 때 나오는 JSON 형식.
content에 검색결과인 식당이 담기고, last페이지인지 sort는 어떻게 했는지 다 담겨져 나온다.

slice는 카운트쿼리가 나가지 않고 다음 slice가 존재하는지 여부만 확인할 수 있기때문에, 데이터 양이 많으면 많을수록 slice를 사용하는것이 성능상 유리하다.

page는 게시판과 같이 총 데이터 갯수가 필요한 환경에서,
slice는 모바일과 같이 총 데이터 갯수가 필요없는 환경



Slice 객체를 사용한 통합검색 Repository

    //통합검색
    public Slice<Restaurant> searchByNameAndAddress(String keyword, Pageable pageable) {
        List<Restaurant> restaurantList = em.createQuery("select r from Restaurant r where r.name like :keyword or r.address_name like :keyword", Restaurant.class)
                .setParameter("keyword", keyword)
                .setFirstResult((int) pageable.getOffset())
                .setMaxResults(pageable.getPageSize())
                .getResultList();

        return new SliceImpl<>(restaurantList, pageable, restaurantList.size() >= pageable.getPageSize());
    }

    //키워드를 포함하는 주소나 가게이름 조회
    public Slice<Restaurant> searchByKeywordContaining(String keyword, Pageable pageable) {
        List<Restaurant> restaurantList = em.createQuery("select r from Restaurant r where r.name like CONCAT('%', :keyword, '%') or " +
                        "r.address_name like CONCAT('%', :keyword, '%') order by r.avgRating desc", Restaurant.class)
                .setParameter("keyword", keyword)
                .setFirstResult((int) pageable.getOffset())
                .setMaxResults(pageable.getPageSize())
                .getResultList();

        return new SliceImpl<>(restaurantList, pageable, restaurantList.size() >= pageable.getPageSize());
    }
  • keyword를 받아오고 pageable로 페이지의 정보를 받아온다.
  • setFirstResult((int) pageable.getOffset())를 사용해서 검색 결과의 시작 위치를 설정.
  • setMaxResults(pageable.getPageSize())를 사용해 한 페이지에 표시할 결과수를 설정하였다.
  • 가장 중요한 new SliceImple<>()를 사용하여 Slice 객체를 생성하고
    restaurantList는 검색결과를 담고, pageable은 페이지 정보, restaurantList.size() >= pageable.getPageSize()은 다음 페이지가 있는지 여부를 확인하는데 쓰인다.
    만약 설정한 값이 10인데 11이 담긴다면 다음페이지가 존재 한다고 볼 수 있다.

Service

    //통합 검색
    public Slice<Restaurant> searchByNameAndAddress(String keyword, Pageable pageable) {
        if (keyword.length() < 2) {
            throw new IllegalArgumentException("최소 두 글자 이상 입력해 주세요.");
        }
        Slice<Restaurant> restaurants = restaurantRepository.searchByNameAndAddress(keyword, pageable);

        if (restaurants.isEmpty()) {
            restaurants = restaurantRepository.searchByKeywordContaining(keyword, pageable);
        }

        return restaurants;
    }
  • 서비스 코드는 기존 List형태에서 Slice로 바꿔주었다.

Controller

    //통합검색
    @GetMapping("api/v1/restaurants/search")
    public Slice<RestaurantDTO> keywordSearch(@RequestParam("keyword") String keyword,@PageableDefault(size = 10, page = 0) Pageable pageable) {

        Slice<Restaurant> restaurants = restaurantService.searchByNameAndAddress(keyword, pageable);

        if (restaurants.isEmpty()) {
            restaurants = restaurantService.searchByNameAndAddress(keyword, pageable);
        }

/*        List<Restaurant> restaurantList = restaurants.getContent();
        System.out.println("restaurantList: "+ restaurantList);*/

        List<RestaurantDTO> restaurantDTOS = restaurants.getContent().stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
        return new SliceImpl<>(restaurantDTOS, restaurants.getPageable(), restaurants.hasNext());
    }

@PageableDefault 어노테이션을 사용하여 기본설정을 0페이지 10개 조회되게 하였다.

profile
Let's Coding

0개의 댓글