본문 바로가기
개발/Field-Passer 프로젝트

[Field-Passer 프로젝트] Spring Data JPA 페이징 처리하기

by 코코의 주인 2023. 2. 3.

프론트엔드 쪽에서 회원 목록을 조회하는 API에 대해 한 페이지에 데이터 10개씩 페이징해서 결과를 달라는 요청을 했다. 그래서 처음으로 데이터 페이징 기능 구현한 겸 글을 써본다.


1. Controller

@GetMapping("/admin/members")
public MemberListVO lookUpMembers(@RequestParam(name = "page") int page) {
    try {
        return adminService.lookUpmembers(page);
    } catch (Exception e) {
        return MemberListVO.builder()
                .resultCode(e.getMessage())
                .build();
    }
}

이름을 lookuUpmembers으로 했는데 지금 보니까 이름을 좀 잘못 지은 거 같다. totalLookupmembers나 lookupAllMembers라고 했으면 좀 더 알아보기 쉬웠을 거 같다. 짧은 영어 실력이 원망스럽다.


2. Service

/**
 * 전체 회원 조회
 * @param page
 * @return
 * @throws Exception
 */
@Override
public MemberListVO lookUpmembers(int page) throws Exception{
    try {
        Page<Member> members = memberService.findAllMembers(page);
        List<MemberListDTO> resultData = new ArrayList<>();
        for (Member member : members.getContent()) {
            resultData.add(MemberListDTO.builder()
                            .memberId(member.getMemberId())
                            .email(member.getEmail())
                            .memberName(member.getMemberName())
                            .signupDate(member.getSignUpDate())
                            .postCount(postService.countPostById(member.getMemberId()))  //글 개수
                            .visitCount(member.getVisitCount())
                            .privilege(member.convertPrivilege())
                            .reportNum(punishService.countBytargetId(member.getMemberId()))  //신고 수
                            .authority(member.convertAuthority())
                    .build());
        }
        System.out.println("members.getTotalPages() = " + members.getTotalPages());
        System.out.println("members.getNumber() = " + members.getNumber());
        return MemberListVO.builder()
                .resultCode("success")
                .resultDataNum(members.getTotalElements())
                .resultData(resultData)
                .currentPage(members.getNumber())
                .totalPage(members.getTotalPages())
                .sort(members.getSort())
                .build();
    } catch (NullPointerException e) {
        throw new Exception("failed : 조회할 수 있는 회원이 없습니다.");
    }
}

MemberService의 findAllMembers() 메서드를 호출해서 Page 리스트의 형태로 값을 받아왔다. 회원을 조회할 때 예외가 발생하면 에러 메시지를 반환한다. 만약 나쁜 사용자가 page=10000 같은 큰 수를 입력했을 때를 대비했다.

 

private final int contentsSize = 10;

/**
 * 전체 회원 조회(페이징)
 * @param page
 * @return
 * @throws NullPointerException
 */
@Override
public Page<Member> findAllMembers(int page) throws NullPointerException{
    PageRequest pageRequest = PageRequest.of(page - 1, contentsSize, Sort.by(Sort.Direction.ASC, "id"));
    Page<Member> allMembers = memberRepository.findAllMembers(pageRequest);
    if (allMembers.getContent().isEmpty()) {
        throw new NullPointerException("조회할 수 있는 회원이 없습니다.");
    } else {
        return allMembers;
    }
}

contentsSize는 상수로 설정해서 언제든 바꿀 수 있게 해뒀다.


3.Repository

//전체 회원 조회
@EntityGraph(attributePaths = {"admin"})
@Query("select m from Member m where m.delete = 0")
Page<Member> findAllMembers(Pageable pageable);

페치 조인을 사용하지 않으면 쿼리 낭비가 있는데 페치 조인을 사용하면 페이징이 되지 않는다. 그래서 @EntityGraph를 사용해봤는데 이건 된다. 이것도 안 되면 배치 사이즈 조절해서 해결하려고 했는데 그럴 필요가 없어졌다.


결과

{
    "resultCode": "success",
    "resultDataNum": 3,
    "resultData": [
        {
            "memberId": 1,
            "email": "hello123@email.com",
            "memberName": "신림동 모드리치",
            "signupDate": "2023-01-13T09:00:00",
            "postCount": 1,
            "visitCount": 100,
            "privilege": "일반 회원",
            "reportNum": 1,
            "authority": "인증 완료"
        },
        {
            "memberId": 3,
            "email": "hi123@email.com",
            "memberName": "대치동 메시",
            "signupDate": "2023-01-25T09:00:00",
            "postCount": 1,
            "visitCount": 0,
            "privilege": "일반 회원",
            "reportNum": 1,
            "authority": "이메일 인증 전"
        },
        {
            "memberId": 4,
            "email": "admin@email.com",
            "memberName": "관리자1",
            "signupDate": "2023-12-13T09:00:00",
            "postCount": 1,
            "visitCount": 999,
            "privilege": "관리자",
            "reportNum": 0,
            "authority": "인증 완료"
        }
    ],
    "currentPage": 0,
    "totalPage": 1,
    "sort": {
        "unsorted": false,
        "sorted": true,
        "empty": false
    }
}

아주 만족스럽게 반환되는 것을 확인할 수 있다.

{
    "resultCode": "failed : 조회할 수 있는 회원이 없습니다.",
    "resultDataNum": null,
    "resultData": null,
    "currentPage": 0,
    "totalPage": 0,
    "sort": null
}

에러가 발생하면 이렇게 나온다.

댓글