인프런 커뮤니티 질문&답변

유요한님의 프로필 이미지
유요한

작성한 질문수

실전! Querydsl

스프링 데이터 페이징 활용1 - Querydsl 페이징 연동

페이징 처리 질문

해결된 질문

작성

·

639

·

수정됨

0


[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (아니오)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)

[질문 내용]
지금 질문은 querydsl 뿐만 아니라 spring data jpa도 섞여있습니다.

 

여태 Spring Data JPA로 페이징을 처리할 때는

Page<BoardEntity> findAllByItemItemId(Long itemId, Pageable pageable);
    @Query(value = "select b from board b " +
            " join fetch b.member " +
            " join fetch b.item " +
            "where b.item.itemId = :itemId" +
            " order by b.boardId desc ",
            countQuery = "select count(b) from board b where b.item.itemId = :itemId")
    Page<BoardEntity> findAllByItemItemId(@Param("itemId") Long itemId, Pageable pageable);

이렇게 처리하고

서비스에서

 // 상품에 대한 문의글 보기
    @Transactional(readOnly = true)
    @Override
    public Page<BoardDTO> getBoards(Pageable pageable,
                                    Long itemId,
                                    String email) {

        // 회원 조회
        MemberEntity findUser = memberRepository.findByEmail(email);
        log.info("유저 : " + findUser);

        // 상품 조회
        ItemEntity findItem = itemRepository.findById(itemId)
                .orElseThrow(EntityNotFoundException::new);
        log.info("상품 : " + findItem);

        // 조회해올 게시글을 넣을 곳
        Page<BoardEntity> findAllBoards = boardRepository.findAllByItemItemId(itemId, pageable);
        // 댓글이 있으면 답변완료, 없으면 미완료
        for(BoardEntity boardCheck : findAllBoards) {
            if(boardCheck.getCommentEntityList().isEmpty()) {
                boardCheck.changeReply(ReplyStatus.REPLY_X);
            } else {
                boardCheck.changeReply(ReplyStatus.REPLY_O);
            }
        }

        for (BoardEntity boardEntity : findAllBoards) {
            // 파라미터로 받아온 이메일이 있다면
            if (email != null) {
                // 해당 게시글을 만들때 이메일과 조회한 이메일을 체크
                // 그리고 맞다면 읽을 권한주고 없으면 잠가주기
                if (boardEntity.getMember().getEmail().equals(findUser.getEmail())) {
                    boardEntity.changeSecret(BoardSecret.UN_LOCK);
                } else {
                    boardEntity.changeSecret(BoardSecret.LOCK);
                }
            } else {
                boardEntity.changeSecret(BoardSecret.LOCK);
            }
        }
        log.info("조회된 게시글 수 : {}", findAllBoards.getTotalElements());
        log.info("조회된 게시글 : {}", findAllBoards);

        return findAllBoards.map(board -> BoardDTO.toBoardDTO(
                board,
                board.getMember().getNickName(),
                board.getItem().getItemId()));
    }
  // 상품에 대한 문의글 전체 보기
    @GetMapping("")
    @Tag(name = "board")
    @Operation(summary = "문의글 전체 보기", description = "모든 상품에 대한 문의글을 봅니다.")
    public ResponseEntity<?> getBoards(
            // SecuritConfig에 Page 설정을 한 페이지에 10개 보여주도록
            // 설정을 해서 여기서는 할 필요가 없다.
            @PageableDefault(sort = "boardId", direction = Sort.Direction.DESC)
            Pageable pageable,
            @PathVariable(name = "itemId") Long itemId,
            @RequestParam(value = "email", required = false) String email) {
        try {
            log.info("email : " + email);
            // 검색하지 않을 때는 모든 글을 보여준다.
            Page<BoardDTO> boards = boardService.getBoards(pageable, itemId, email);
            Map<String, Object> response = new HashMap<>();
            // 현재 페이지의 아이템 목록
            response.put("items", boards.getContent());
            // 현재 페이지 번호
            response.put("nowPageNumber", boards.getNumber()+1);
            // 전체 페이지 수
            response.put("totalPage", boards.getTotalPages());
            // 한 페이지에 출력되는 데이터 개수
            response.put("pageSize", boards.getSize());
            // 다음 페이지 존재 여부
            response.put("hasNextPage", boards.hasNext());
            // 이전 페이지 존재 여부
            response.put("hasPreviousPage", boards.hasPrevious());
            // 첫 번째 페이지 여부
            response.put("isFirstPage", boards.isFirst());
            // 마지막 페이지 여부
            response.put("isLastPage", boards.isLast());

            return ResponseEntity.ok().body(response);
        } catch (Exception e) {
            return ResponseEntity.badRequest().build();
        }
    }

이렇게 처리를 했습니다. Page 기능을 사용해서 구현했고 querydsl에서 페이징처리는 다음과 같이 했습니다.

    @Override
    public Page<MemberTeamDTO> searchPageComplex(MemberSearchCondition condition,
                                                 Pageable pageable) {
        List<MemberTeamDTO> content = queryFactory
                .select(new QMemberTeamDTO(
                        member.id.as("memberId"),
                        member.userName,
                        member.age,
                        team.id.as("teamId"),
                        team.name.as("teamName")))
                .from(member)
                .leftJoin(member.team, team)
                .where(userNameEq(condition.getUserName()),
                        teamNameEq(condition.getTeamName()),
                        ageGoe(condition.getAgeGoe()),
                        ageLoe(condition.getAgeLoe()))
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .fetch();

        // count 쿼리 (조건에 부합하는 로우의 총 개수를 얻는 것이기 때문에 페이징 미적용)
        long total = queryFactory
                // SQL 상으로는 count(member.id)와 동일
                .select(member.count())
                .from(member)
//                .leftJoin(member.team, team)
                .where(userNameEq(condition.getUserName()),
                        teamNameEq(condition.getTeamName()),
                        ageGoe(condition.getAgeGoe()),
                        ageLoe(condition.getAgeLoe()))
                .fetchOne();

        return new PageImpl<>(content, pageable, total);
    }

fetchResult와 fetchCount가 지원을 안한다고 해서 조건에 따라 카운트를 구해서 총 개수를 구해서 하는 방식으로 했는데 이렇게 했을 때도

Map<String, Object> response = new HashMap<>();
            // 현재 페이지의 아이템 목록
            response.put("items", boards.getContent());
            // 현재 페이지 번호
            response.put("nowPageNumber", boards.getNumber()+1);
            // 전체 페이지 수
            response.put("totalPage", boards.getTotalPages());
            // 한 페이지에 출력되는 데이터 개수
            response.put("pageSize", boards.getSize());
            // 다음 페이지 존재 여부
            response.put("hasNextPage", boards.hasNext());
            // 이전 페이지 존재 여부
            response.put("hasPreviousPage", boards.hasPrevious());
            // 첫 번째 페이지 여부
            response.put("isFirstPage", boards.isFirst());
            // 마지막 페이지 여부
            response.put("isLastPage", boards.isLast());

이런식으로 뽑아서 프론트에 보낼 수 있는지와

실무에서도 spring data jpa와 querydsl 방식으로 페이징 처리를 할 때 이렇게 하는지 아니면 다른 방식이 더있는지 궁금해서 질문드립니다.

 

답변 2

1

안녕하세요. 유요한님, 공식 서포터즈 David입니다.

네, 이해하고 계신대로 작성해서 사용하셔도 무방합니다🙂

실무에서도 비슷하게 작성합니다.

감사합니다.

0

안녕하세요, 인프런 AI 인턴입니다.

페이징 처리에 대한 궁금증을 해결하기 위한 유사한 질문과 답변이 있어 링크를 안내해 드릴게요.

  • spqkwh159님의 질문: “searchSimple 에 관한 질문입니다.“에 대한 답변 링크입니다. 페이지네이션 처리와 관련된 문제 해결에 대한 팁을 얻을 수 있을 거예요.
    searchSimple 에 관한 질문입니다.

  • crispin님의 질문: “페이징 했을때 발생하는 문제”에 대한 답변 링크입니다. 페이징 처리 시 countQuery를 별도로 작성해야 하는 상황에 대한 설명이 담겨 있습니다.
    페이징 했을때 발생하는 문제

위 링크들을 참조하시어 페이징 처리에 대한 이해를 높이시고, 실무에서의 적용 방법에 대한 힌트를 얻으실 수 있기를 바랍니다.

유요한님의 프로필 이미지
유요한

작성한 질문수

질문하기