woowacourse-teams / 2024-code-zap

코드 템플릿, Zap싸게 저장하고! Zap싸게 공유하자! 코드잽 ⚡
https://www.code-zap.com
25 stars 8 forks source link

[BUG] 페이지네이션 기본 값 재설정 #690

Closed kyum-q closed 1 month ago

kyum-q commented 1 month ago

들아기기 전에 상황 설명

기본 페이지네이션 설정

페이지네이션의 페이지 번호는 기본적으로 0부터 시작한다.

원하는 것

하지만 프론트엔드와 소통하는 측면에서 페이지 값이 1일 때 0번째 페이지를 보여주고자 했다.

페이지 값 1 -> 0번째 페이지 페이지 값 2 -> 1번째 페이지

페이지네이션 설정 변경 방법

그래서 다음 yml 파일을 추가해서 페이지 값이 1로 들어오면 0번째 페이지를 보여지도록 설정했다. (관련 PR #539 )

spring:
  data.web.pageable.one-indexed-parameters: true

중요한 착각 포인트

여기서 우리는 저 설정이 JPA 처리 단을 변경해주는 줄 알고 있었다. 😊 즉, 컨트롤러에서 pageable 의 페이지 값이 1일 때 0번째 페이지를 보여주는 걸로 알고 있었다. 😊


🐞 어떤 버그인가요?

페이지 값을 설정하지 않고 템플릿 조회 요청을 보냈을 때 , 몇몇 케이스들이 검색된 전체 템플릿 수를 보면 템플릿 배열에 값이 있어야하는데 템플릿 배열에는 값이 없음.

🙄 어떤 상황에서 발생한 버그인가요?

(가능하면) Given-When-Then 형식으로 서술해주세요

  1. DB에 memberId=2이고 keyword="Card watch" 인 템플릿이 1개 존재
  2. http://localhost:8080/templates?memberId=2&keyword=Card%20watch 요청
  3. 반환 값이 잘못됨. 배열에 값이 존재하지 않음. image

👍 해결 방법

요약

spring:
  data.web.pageable.one-indexed-parameters: true

위 설정은 JPA 단에서 페이지 처리해주는 것이 아닌, 컨트롤러에 들어올 때 스프링이 처리해주는 것이다. 그래서 page를 입력했을 땐 컨트롤러 단에서 -1 됨을 확인할 수 있다.

http://localhost:8080/templates?memberId=2&keyword=Card%20watch&page=1 요청 시 : 컨트롤러에는 page가 자동으로 -1해서 0이 된다. image

위 문제의 원인은 이를 모르고 다음과 같이 pageable에 page의 기본 값을 1로 해줬다. 그래서 위에 문제는 시작 페이지가 0인데 1번째 페이지를 찾으니 배열에 값이 없었던 것이다 !

    @GetMapping("/login")
    public ResponseEntity<FindAllTemplatesResponse> getTemplatesWithMember(
            @AuthenticationPrinciple MemberDto memberDto,
            @RequestParam(required = false) Long memberId,
            @RequestParam(required = false) String keyword,
            @RequestParam(required = false) Long categoryId,
            @RequestParam(required = false) List<Long> tagIds,
            @PageableDefault(size = 20, page = 1) Pageable pageable
    ) {    }

그래서 해당 코드를 수정함으로 해결하였다.

AS-IS

    @GetMapping("/login")
    public ResponseEntity<FindAllTemplatesResponse> getTemplatesWithMember(
            @AuthenticationPrinciple MemberDto memberDto,
            @RequestParam(required = false) Long memberId,
            @RequestParam(required = false) String keyword,
            @RequestParam(required = false) Long categoryId,
            @RequestParam(required = false) List<Long> tagIds,
            @PageableDefault(size = 20, page = 1) Pageable pageable
    ) {    }

TO-BE

    @GetMapping("/login")
    public ResponseEntity<FindAllTemplatesResponse> getTemplatesWithMember(
            @AuthenticationPrinciple MemberDto memberDto,
            @RequestParam(required = false) Long memberId,
            @RequestParam(required = false) String keyword,
            @RequestParam(required = false) Long categoryId,
            @RequestParam(required = false) List<Long> tagIds,
            @PageableDefault(size = 20) Pageable pageable
    ) {    }

🎁 결과

  1. DB에 memberId=2이고 keyword="Card watch" 인 템플릿이 1개 존재
  2. http://localhost:8080/templates?memberId=2&keyword=Card%20watch 요청
  3. 배열에 값이 존재함. image

⏳ 소요 시간

1시간

🔍 참고할만한 자료(선택)

kyum-q commented 1 month ago

어떻게 이 문제를 알았는지 더 알고 싶은 분들을 위해 적는 글

image

해당 코드를 디버깅해보니 703번 줄에는 query.getResultList() 의 사이즈가 1이었다. 704번 줄에서 사이즈가 0이 된다.

704번 줄은 페이지 설정해주는 것, 즉 해당 페이지를 보여주는 코드다. 이 때 pageable 의 페이지 번호가 1이었음. 디버깅으로 pageable의 페이지 번호를 0으로 변경해서 넣으니 query.getResultList() 의 사이즈가 1이었다.

이렇게 문제 발견 ~!