SpringBoot Project

[SpringBoot] 게시판 Pagination(Pageable 이용한 페이징), 리스트 불러오기

꿈꾸는야오옹 2023. 1. 29. 17:20

게시판 페이징을 구현하여 게시글 리스트를 불러오려고 한다.  아래의 사진과 같이  구현하고자 하였다.

  • 게시물 5개씩 불러오기
  • Pagination 부분에 7개 고정하기

 

먼저 Board Entity에서 리스트로 끌어올때 필요한 정보들을 모아둔 DTO를 구성했다.

@Getter
public class BoardListDTO {
	
	private long bno;
	private String title;
	private int readCount;
	private String writer;
	private LocalDateTime updatedDate;
	private LocalDate toDay;
	private String writerId;
	
	//Entity를 -> BoardListDTO(BoardEntity ent)
	public BoardListDTO(BoardEntity ent) {
		
		this.bno = ent.getBno();
		this.title = ent.getTitle();
		this.readCount = ent.getReadCount();
		this.writer = ent.getMember().getName(); //member의 name이 작성자임
		this.updatedDate = ent.getUpdatedDate();
		toDay=LocalDate.now();
		this.writerId =ent.getMember().getId();
	}
	

}

 

 

다음으로 DB에 저장된 게시물 리스트를 불러오는 getListAll 메서드를 ServiceProcess에 작성을 해주었다.

 

우선 JPA에서 기본적으로 pageable을 제공한다. 페이징에 이를 이용했다.

  • Page<T> : 페이지 정보를 담는 인터페이스
  • Pageable : 페이지 처리에 필요한 정보를 담는 인터페이스

getListAll이라는 메소드에 변수로 page와 model를 이용해 데이터를 담아 오려고 한다.

	@Transactional
	@Override
	public void getListAll(int page, Model model) {
		//board list를 페이지로 전송
		
		//페이징 작업 pageable이용
		int size=5; // 5개씩 보이게
		Sort sort=Sort.by(Direction.DESC, "bno");
		
		Pageable pageable=PageRequest.of(page-1, size ,sort);
		Page<BoardEntity> result=repository.findAll(pageable);

		int nowPage = result.getNumber()+1;
		int startPage = Math.max(nowPage -3, 1);
		int endPage = Math.min(nowPage +3, result.getTotalPages());
		int totPage= result.getTotalPages();
		
		model.addAttribute("nowPage", nowPage);
		model.addAttribute("startPage", startPage);
		model.addAttribute("endPage", endPage);
		model.addAttribute("totPage", totPage);
		
		model.addAttribute("p", result);
		model.addAttribute("list", result.stream()
				.map(BoardListDTO::new)
				.collect(Collectors.toList()));
	}
  • page 는 게시글의 인덱스 번호이다.
  • size 는 한 페이지에 몇개의 게시물을 보여줄지 결정한다. 나는 size를 5로 설정하였다.
  • sort 는 정렬 방법이다. 나는 bno라는 게시물 번호를 이용하여 DESC 즉, 내림차순으로 정렬하고자 하였다.

 

그리고 Page에서 아래와 같은 메소드를 제공한다. 이를 이용하여 nowPage, startPage, endPage를 직접 설정해주었다.

 

getNumber() 현재 페이지 인덱스를 불러온다. 0부터 시작이다.
getTotalPages() 전체 페이지의 개수를 불러온다.
hasPrevious() 이전 페이지가 존재하는지 확인한다.
hasNext() 다음 페이지가 존재하는지 확인한다.

 

 

이제 controller에서 작성한 메소드를 이용해 매핑해보자.

	@GetMapping("/notice-boards")
	public String board(@RequestParam(defaultValue = "1") int page , Model model) {
		service.getListAll(page ,model);
		return "board/noticeList";
	}

 

 

다음으로 보이는 뷰에 페이징을 구현을 해보자. thymeleaf 문법사용에 주의하며 작성하였다. if 문이 꽤나 복잡하게 사용되었는데 page개수가 보이는 것을 7개로 고정하기 위해 짠 로직들이다.

 

  • 단순히 th:each="p:${#numbers.sequence(startPage, endPage)}" 를 이용 할 수 없다.

전, 후로 3페이지씩 가지고 있는 페이지들은 정상적으로 페이지 개수가 7개로 고정이 된다.

 

하지만 예를들어 1페이지 같은 경우는 이전 페이지들이 없다. 따라서  int startPage = Math.max(nowPage -3, 1) 에 따라 시작 페이지가 1페이지가 되고, endPage는 4페이지가 된다. 그러면  7개의 페이지 개수가 고정이 되지 않는다.

 

 

이러한 여러 문제들을 다양한 조건문들을 작성하여 예외가 발생하는 문제들을 해결 할 수 있었다.

<div class="page_wrap">
    <div class="page_nation">
        <div th:if="${p.getNumberOfElements()>0}">
            <a class="arrow prev" th:if="${p.hasPrevious()}" th:href="|/notice-boards?page=${nowPage-1}|">&lt;</a>

            <th:block th:if="${totPage>=6}">
            <th:block th:if="${nowPage <= 4}" th:each="p:${#numbers.sequence(1, 7)}">
                <a th:if="${p != nowPage}" th:href="@{notice-boards?(page=${p})}" th:text="${p}"></a>
                <a th:if="${p == nowPage}" th:text="${p}" class="active"></a>
            </th:block>

            <th:block th:if="${nowPage>4 && nowPage<totPage-2}" th:each="p:${#numbers.sequence(startPage, endPage)}">
                <a th:if="${p != nowPage}" th:href="@{notice-boards?(page=${p})}" th:text="${p}"></a>
                <a th:if="${p == nowPage}" th:text="${p}" class="active"></a>
            </th:block>

            <th:block th:if="${nowPage >= totPage-2}" th:each="p:${#numbers.sequence(nowPage-(6-(totPage-nowPage)), totPage)}">
                <a th:if="${p != nowPage}" th:href="@{notice-boards?(page=${p})}" th:text="${p}"></a>
                <a th:if="${p == nowPage}" th:text="${p}" class="active"></a>
            </th:block>
            </th:block>

            <th:block th:if="${totPage<6}">
            <th:block th:each="p:${#numbers.sequence(startPage, endPage)}">
                <a th:if="${p != nowPage}" th:href="@{notice-boards?(page=${p})}" th:text="${p}"></a>
                <a th:if="${p == nowPage}" th:text="${p}" class="active"></a>
            </th:block>
            </th:block>	

            <a class="arrow next" th:if="${p.hasNext()}" th:href="|/notice-boards?page=${nowPage+1}|">&gt;</a>
        </div>
    </div>
</div>