JPA

[JPA] Pageable 사용 시 Page<Entity>를 Page<DTO>로 변환하기(Builder, 람다식 사용)

cornarong 2021. 10. 26. 17:35

 

각 레이어간의 역할을 확실히 분리하기 위해서 클라이언트에 전달 할 객체는 항시 DTO로 변환해서 전달 합니다.

 

이떄 Spring Data Jpa 에서 제공하는 Pageable을 사용할 경우 반환받은 Page<Entity>를 Page<DTO>로 변환하는 상황이 생겨서 기록하였습니다.

 

1. Repository

public interface BoardRepository extends JpaRepository<Board, Long> {
// Containing : like와 비슷한 문법
    Page<Board> findByTitleContainingOrContentContaining(String title, String content, Pageable pageable);

}

'title'과 'content'를 인자값으로 전달받아 where 검색결과를 return하도록 설정하였습니다.


2. Controller

    /* 게시글 목록 */
    @GetMapping
    public String list(Model model, @PageableDefault(size = 10) Pageable pageable, @RequestParam(defaultValue = "") String searchTerm){
        Page<Board> boardList = boardRepository.findByTitleContainingOrContentContaining(searchTerm, searchTerm, pageable);
        Page<BoardDto> boardDtoList = new BoardDto().toDtoList(boardList); // Page<Entity> -> Page<Dto> 변환.
        int startPage = Math.max(1, boardDtoList.getPageable().getPageNumber() - 10);
        int endPage = Math.min(boardDtoList.getTotalPages(), boardDtoList.getPageable().getPageNumber() + 10);

        model.addAttribute("startPage", startPage);
        model.addAttribute("endPage", endPage);
        model.addAttribute("boardDtoList", boardDtoList);
        return "board/list";
    }

boardRepository에서 전달받은 Page<Board> boardList를 BoardDto 클래스의 toDtoList 메소드에 인자로 담아서 호출합니다.


3. DTO (객체지향에 가깝게 대부분의 비즈니스 로직들은 해당 Entity나 DTO에서 호출하여 처리합니다)

    /* Page<Entity> -> Page<Dto> 변환처리 */
    public Page<BoardDto> toDtoList(Page<Board> boardList){
        Page<BoardDto> boardDtoList = boardList.map(m -> BoardDto.builder()
                .id(m.getId())
                .type(m.getType())
                .title(m.getTitle())
                .content(m.getContent())
                .writer(m.getUser().getUid())
                .regdate(m.getRegdate())
                .views(m.getViews())
                .build());
        return boardDtoList;
    }

 

전달받은 boardList를 람다식 .map을 이용하여 Build한 후 Page<BoardDto>로 반환 받습니다.


4. HTML (타임리프)

<!-- 페이징 처리 -->
  <nav aria-label="Page navigation example">
    <ul class="pagination justify-content-center">
      <li class="page-item" th:classappend="${1 == boardDtoList.pageable.pageNumber + 1} ? 'disabled'">
        <a class="page-link" th:href="@{/board(page=${boardDtoList.pageable.pageNumber}-1, searchTerm=${param.searchTerm})}" tabindex="-1" aria-disabled="true">이전</a>
      </li>
      <li class="page-item" th:classappend="${page == boardDtoList.pageable.pageNumber + 1} ? 'disabled'" th:each="page : ${#numbers.sequence(startPage, endPage)}">
     	<a class="page-link" th:href="@{/board(page=${page} - 1, searchTerm=${param.searchTerm})}" th:text="${page}">1</a>
      </li>
      <li class="page-item" th:classappend="${boardDtoList.totalPages == boardDtoList.pageable.pageNumber + 1} ? 'disabled'">
      	<a class="page-link" th:href="@{/board(page=${boardDtoList.pageable.pageNumber} + 1, searchTerm=${param.searchTerm})}">다음</a>
      </li>
    </ul>
  </nav>
<!-- // 페이징 처리 -->

전달 받은 pageable 메소드들이 정상적으로 호출되는 것을 확인합니다