본문 바로가기

Spring Boot

스프링부트 검색, 페이징처리 하기 Pageable - 2 -

드디어 모든 기능 구현 끝났다 ㅜㅜㅜ

 

gonyda.tistory.com/15

 

스프링부트 검색, 페이징처리 하기 Pageable

오늘은 검색 기능과 페이징 처리에 대해서 포스팅해보겠다 90프로 정도 완성했는데 완성 못한 게 있다 각 페이지에 대한 부분을 동적으로 바꾸고 싶은데 어떻게 해야 할지 모르겠다ㅜㅜ 이건 천

gonyda.tistory.com

 

저번 글에 이어서 구현한 기능들을 포스팅하겠다

 

이번 포스팅에서 설명할 기능들은

 

1. pagination에 따른 동적 URL (feat.Mustache)

2. 마지막 페이지 일시 'Next' 버튼 비활성화

번외. List와 Page

 

 

 

1. pagination에 따른 동적 URL (feat.Mustache)

먼저 코드부터 보자

 

1-1 Mustache

{{>layout/header}}

<table class="table">
    <thead class="thead-light">
    <tr>
        <th scope="col">#</th>
        <th scope="col">제목</th>
        <th scope="col">작성자</th>
        <th scope="col">작성시간</th>
    </tr>
    </thead>
    {{#boardList}}
        <tbody>
        <tr>
            <th scope="row">{{id}}</th>
            <td><a href="/{{id}}">{{title}}</a></td>
            <td>{{author}}</td>
            <td>{{createdTime}}</td>
        </tr>
        </tbody>
    {{/boardList}}
</table>

<ul class="pagination justify-content-center">
    <li class="page-item"><a class="page-link" href="?page={{previous}}">Previous</a></li>
    <li class="page-item"><a class="page-link" href="?page={{next}}">Next</a></li>           
</ul>


{{>search/searchForm}}

{{>layout/footer}}

코드를 보면 li태그에 mustache를 쓴 걸 확인할 수 있다. {{previous}}, {{next}}

저렇게 변수를 넣어주면 a태그 안에 빨간 줄이 나타난다. 닫는 태그가 없다는 오류가 뜨는데, 그래도 실행하는 데는 아무 문제없더라

원래 머스타치에서 변수를 사용하려면 {{& next}} 이렇게였나? 아무튼 &를 붙이고 뒤에 변수명을 써야 하는데 이상하게 작동이 안 해서 저렇게 처리를 했다

 

그럼 저 URL을 어떻게 동적으로 바꿨을까?

일단 머스타치에서 증감연산식을 지원을 안 한다. 그래서 저 URL 부분을 어떻게 처리해야 할지 몰라서 방황하고 있었다. 

일단 구글링은 몇 시간 동안 했는데 방법을 찾지 못했었다. 그러다가 정말 기적같이 글 하나를 발견했다

 

1-2 Controller

 @GetMapping("/")
    public String index(Model model, @PageableDefault(size = 10, sort = "id", direction = Sort.Direction.DESC) Pageable pageable) {

        model.addAttribute("boardList", boardService.getBoardList(pageable));
        model.addAttribute("previous", pageable.previousOrFirst().getPageNumber());
        model.addAttribute("next", pageable.next().getPageNumber());
    
        return "index";
    }

 

 

pageable을 이용하면 정말 쉽게 해결할 수 있었다

이걸 하기 위해 날린 내 시간.. 이렇게 간단했다니ㅜㅜ

왼쪽눈에는 기쁨의 눈물이 흐르고, 오른쪽에는 슬픔의 눈물이 흘렀다

 

 

 

2. 마지막 페이지 일시 'Next' 버튼 비활성화

그리고 바로 또 다른 문제에 직면했다

바로 저 Next버튼을 누르면 게시글이 없어도 끝없이 계속 나오는 거다

하아.. 문제를 하나 푸니 또 또 다른 시련이 찾아왔다

이것도 해결하는데 꽤나 고생 좀 했다

 

2-1 Service

@Transactional
    public Boolean getListCheck(Pageable pageable) {
        Page<Board> saved = getBoardList(pageable);
        Boolean check = saved.hasNext();

        return check;
    }

 

구글링으로 찾아봤지만 마땅한 정보가 없어서, 이때부터 코드에 들어가서 마땅한 기능이 없나 일일이 찾아봤다

그래서 저렇게 작성한 코드가 정답인지는 확실치 않다

아무튼, 이 기능에 대해서 내가 생각한 구조는 다음 페이지에 객체가 없다면 Next버튼을 비활성화시키는 거였다

그래서 코드들을 뒤져보니 Page에 hasNext라는 메서드를 발견했다

저 메서드는 말 그대로 다음 페이지에 객체가 있다면 true, 없다면 false를 반환한다

그래서 저 메서드를 선택했고 해당 기능을 구현했다

 

2-2 Mustache

<ul class="pagination justify-content-center">
    <li class="page-item"><a class="page-link" href="?page={{previous}}">Previous</a></li>
    {{#check}}
        <li class="page-item"><a class="page-link" href="?page={{next}}">Next</a></li>
    {{/check}}
    {{^check}}
        <li class="page-item disabled"><a class="page-link" href="?page={{next}}">Next</a></li>
    {{/check}}
</ul>

 

머스타치에서는 이렇게 작성했다

머스타치 문법에 대해서 구글링을 해보니 저런 식으로 if문을 사용할 수 있었다

 

{{#check}}

   조건식이 참이면 실행

{{/check}}
{{^check}}

   거짓이면 실행
{{/check}}

 

이런 식으로 작동한다

여기서 주의해야 할 점은 ^를 쓰지 않는다면 반복문처럼 작동한다

 

그래서 위에처럼 코드를 두 개 작성하고 하나는 disabled를 걸어줬다

다음 페이지에 객체가 없을 경우 활성화를 안되게 했다

 

이렇게 하니 작동이 잘됐다

 

 

2-3 Controller

model.addAttribute("check", boardService.getListCheck(pageable));

 

컨트롤러에서는 이런 식으로 작성했다

 

 

 

번외. List와 Page

 

저렇게 메인화면에 모든 페이징 기능을 끝이 났다

그리고 한 곳이 남았는데, 바로 검색 결과에 대한 페이징 처리였다

그래서 코드를 후딱 작성했다

근데 이상하게 내가 생각하던 데로 작동이 안 됐다

분명 '1'을 검색했고 검색 결과는 총 12개가 나와야 했다

나는 페이지 사이즈를 10으로 했으니 2페이지까지 나오고 버튼이 비활성화가 됐어야 했다

근데 첫 페이지부터 버튼이 비활성화가 되더라

 

또 시작이네

 

따로 테스트 코드는 작성 안 하고 서버를 시작해서 웹상에서 확인하니 뭐가 문제인지 모르겠더라

그래도 바보같이 몇 시간 동안 테스트 코드로 안 하고 웹상에서 확인했다

 

 

혹시나 하는 마음에 테스트 코드 말고 간단하게 로그를 찍어서 데이터가 어떻게 들어오는지 확인해봤다

로그 결과를 보니, 검색 결과가 10개밖에 생성이 안 되는 거였다

분명 12개가 나와야 하는데 10개가 나옴

 

근데 또 페이징 처리는 됐다

직접 URL에 page=1치고 들어가면 페이지에 해당 데이터들이 들어가 있었다

 

 

이 상황을 어떻게 이해해야 할지를 몰랐다

 

무튼 hasNext() 메서드는 당연히 false를 반환하고 있던 거였다

데이터가 10개만 들어오니..

 

 

그래서 뭐가 문제인지를 찾아보다가

public interface BoardRepository extends JpaRepository<Board, Long> {

    List<Board> findByTitleContaining(String keyword, Pageable pageable);

}

 

Repository에서 List 요놈이 이상하게 수상해 보이더라

 

확신은 안서지만 뭔가에 이끌리듯 List를 Page로 바꿔보았다

 

설마설마했는데 작동이 잘 됐다

사실 아직도 왜 List는 안됐고 Page는 됐는지 이해를 못하겠다

이해를 못하고 있는 이유는 기본이 부족해서겠지

정말 자주 쓰는 List인데도 제대로 이해를 안 하고 쓰고 있다는 증거

 

이러한 문제점을 겪고 나서 느낀 게 몇 가지가 있다

 

1. 기본이 중요하다(Java)

2. 테스트 코드의 중요성

 

그래도 이번에 검색 및 페이징 처리하면서 공부를 정말 많이 한 거 같다