반응형

한 페이지에서 큰 단위로 조회 결과가 나오는 경우 한눈에 보기 어렵고 원하는 결과를 찾기도 어렵다.

이를 위해 일정한 단위만큼 나누어 페이지를 넘기도록 하는 기능을 구현하고자 한다.

 

회원 정보를 출력하는 메인 페이지에서 페이징 기능을 추가하도록 하였다.

 

스프링 프레임워크에서 제공하는 Pageable 인터페이스를 사용해보자.

 


Pageable 인터페이스?

 

Pageable 인터페이스는 페이지 번호, 페이지 크기, 정렬 조건 등을 설정할 수 있는 메서드를 제공한다. 이를 통해 검색 결과를 페이지 단위로 나누고 원하는 페이지를 가져오는 등의 작업을 수행할 수 있다.

 

  • 주요 메서드와 기능
  • getPageNumber(): 현재 페이지 번호를 반환합니다. 0부터 시작합니다.
  • getPageSize(): 페이지 크기(한 페이지에 포함되는 아이템 수)를 반환합니다.
  • getOffset(): 현재 페이지의 시작 인덱스(오프셋)를 반환합니다. 페이지 번호와 페이지 크기를 이용하여 계산됩니다.
  • getSort(): 정렬 조건을 반환합니다.
  • next(): 다음 페이지를 반환합니다.
  • previousOrFirst(): 이전 페이지를 반환합니다. 첫 번째 페이지인 경우 첫 번째 페이지를 반환합니다.
  • first(): 첫 번째 페이지를 반환합니다.
  • hasNext(): 다음 페이지가 있는지 여부를 확인합니다.
  • hasPrevious(): 이전 페이지가 있는지 여부를 확인합니다.

페이징 기능 구현을 위해 아래의 글을 참고하였다.

 

9. 스프링부트와 타임리프로 게시판 만들기 - 페이징

페이징 - 백엔드 개념 부분 페이징이란? 페이징이란 여러 게시물을 볼 때 일정 갯수 이상이 넘어가면 다음 페이지에 존재할 수 있게 하는 것을 의미합니다. 위와 같이 게시글이 일정 갯수가 넘어

velog.io

 

1. @PageableDefault으로 페이지 정보 view로 전달

환자 정보 리스트를 화면에 출력하는 main페이지가 요청될 때 페이지 정보를 view에 함께 전달해야 한다.

@GetMapping("/main") //환자 정보 리스트
public String main(Model model, HttpSession session, @PageableDefault(page = 0, size = 10, sort = "id", direction = Sort.Direction.ASC) Pageable pageable) {

    Page<PatientEntity> patientEntityList = memberService.findAll(session, pageable);
    int nowPage = patientEntityList.getPageable().getPageNumber()+1;
    int startPage = Math.max(nowPage-4, 1);
    int endPage = Math.min(startPage+9, patientEntityList.getTotalPages());

    model.addAttribute("nowPage", nowPage);
    model.addAttribute("startPage", startPage);
    model.addAttribute("endPage", endPage);
    model.addAttribute("patientList", patientEntityList);
    return "main2";
}
  • @PageableDefault(page = 0, size = 10, sort = "id", direction = Sort.Direction.ASC) Pageable pageable
    : Pageable 인터페이스에서 page는 0부터 시작한다. 한 페이지에 보일 레코드의 개수(size)를 10으로 설정하였다. sort는 정렬 기준으로, PatientEntity의 id 필드를 기준으로 정렬한다. direction은 정렬 방식으로 DESC(내림차순)와 ASC(오름차순)으로 설정할 수 있다. 이 초기값을 바탕으로 Pageable 인터페이스를 생성한다.
  • Page<PatientEntity> patientEntityList = memberService.findAll(session, pageable);
    : 페이지 기능으로 하기 전에는 List형태였으나, 이제 Pageable을 사용하기 때문에, Page로 가져올 것이다. 타입 역시 Entity타입으로 가져온다. 
    서비스의 findAll함수를 pageable을 추가한 것에 맞게 수정해야 한다!!!
  • int nowPage = patientEntityList.getPageable().getPageNumber()+1
    : 현재페이지에 대한 정보이다. pageable은 페이지가 0부터 시작하므로 +1을 해줌으로써 1페이지부터 시작하도록 한다.
  • int startPage = Math.max(nowPage-4, 1)
    : 표시될 시작페이지에 대한 정보이다. 현재 페이지 앞에 최대 4개까지 보이도록 하고, 4개보다 적다면 1페이지부터 표시되도록 한다.
  • int endPage = Math.min(startPage+9, patientEntityList.getTotalPages())
    :표시될 마지막페이지에 대한 정보이다. 시작페이지에 9를 더한 값의 페이지까지 보이도록 하여 총 10개만 보이도록 하였고, 최대 페이지를 넘지는 않도록 하였다.
  • 각 값들을 model의 attribute로 view에 전달한다.

 

2. 서비스의 findAll()함수에 Pageable 기능을 하도록 수정

public Page<PatientEntity> findAll(HttpSession session, Pageable pageable){
        Long Id = (Long) session.getAttribute("loginId");
//        List<PatientEntity> patientEntityList = patientRepository.findByMemberEntity_Id(Id);
//        List<PatientDTO> patientDTOList = new ArrayList<>();
//        for(PatientEntity patientEntity: patientEntityList){//여러개의 entity를 여러개의 dto로 하나씩 담기위해
//            patientDTOList.add(PatientDTO.toPatientDTO(patientEntity));
//        }
        return patientRepository.findByMemberEntity_Id(Id, pageable);
    }

서비스 함수의 반환 타입을 Page 형태로 PatientEntity들이 전달되도록 수정하였다. 그리고 Pageable 인터페이스를 인자로 받는다.

주석처리된 부분은 페이징 처리 전에 List형태로 받았던 코드이다.

레포지토리의 findByMemberEntity_Id함수를 수정하여 그 반환형태 자체를 반환하도록 하였다.

 

 

3. 레포지토리 findByMemberEntity_Id함수 수정하기

Page<PatientEntity> findByMemberEntity_Id(Long id, Pageable pageable);

pageable 정보를 넘겨주면 조회결과 레코드를 10개씩 나누어 페이지로 알아서 반환해준다.

 

 

4.view에서 페이징 처리하기!

<div class="card-footer py-4">
  <nav aria-label="...">
    <ul class="pagination justify-content-end mb-0">
      <li class="page-item disabled">
        <a class="page-link" href="#" tabindex="-1">
          <i class="fas fa-angle-left"></i>
          <span class="sr-only">Previous</span>
        </a>
      </li>
      <th:block th:each="page:${#numbers.sequence(startPage,endPage)}">
        <li class="page-item" th:class="${page == nowPage} ? 'page-item active' : 'page-item'">
          <a class="page-link" th:if="${page != nowPage}" th:href="@{/main(page=${page-1})}" th:text="${page}"></a>
          <a class="page-link" th:if="${page == nowPage}" th:text="${page}" style="color:white; font-weight:bold;"></a>
        </li>
      </th:block>
      <li class="page-item">
        <a class="page-link" href="#">
          <i class="fas fa-angle-right"></i>
          <span class="sr-only">Next</span>
        </a>
      </li>
    </ul>
  </nav>
</div>
  • 첫번째 li는 이전 페이지로 이동하는 버튼을 구현한것이다
  • 두번째 li가 현재 페이지를 포함한 10개의 페이지 버튼을 보이도록 구현한것이다.
    th:each를 통해 model로 전달된 startPage와 endPage의 정보를 가지고, 각 페이지를 표시하도록 한다.
    각 페이지를 순회하면서 현재 활성화된 페이지와 같으면, page-link 스타일을 가지면서, 페이지 번호는 white색이며, 볼드체로 표시되도록 하였고, 활성화된 페이지가 아니면, page-link스타일을 가지면서 페이지 번호에 해당 페이지 링크를 걸어주었다.
  • 세번째 li가 다음 페이지로 이동하는 버튼을 구현한 것이다.

 

5. 구현결과  

페이지 버튼 성공!!

5페이지 까지는 1이 첫번째고, 10이 최대며, 그다음부터는 1씩 늘어나며 shift되는 것을 확인하였다!

잘 동작한다!!! 디자인도 잘 적용되었다!

반응형

+ Recent posts