ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [과제] 일정 관리 앱 만들기 도전 Lv4
    내일배움캠프/과제 2025. 3. 25. 18:15

    ✅ Lv4. 페이지네이션

    1️⃣ 과제 조건

    • 설명
      • 많은 양의 데이터를 효율적으로 표시하기 위해 데이터를 여러 페이지로 나눕니다.
        • 페이지 번호와 페이지 크기를 쿼리 파라미터로 전달하여 요청하는 항목을 나타냅니다.
        • 전달받은 페이지 번호와 크기를 기준으로 쿼리를 작성하여 필요한 데이터만을 조회하고 반환
    • 조건
      • 등록된 일정 목록을 페이지 번호와 크기를 기준으로 모두 조회
      • 조회한 일정 목록에는 작성자 이름이 포함
      • 범위를 넘어선 페이지를 요청하는 경우 빈 배열을 반환
      • Paging 객체를 활용할 수 있음

     

    2️⃣ 목록 조회 시 조건 매개변수 변경

    1. Paging 객체 생성

    public class CustomPageable {
        @Schema(description = "페이지 번호 (1부터 시작)", defaultValue = "1")
        private int page = 1;
    
        @Schema(description = "페이지 크기", defaultValue = "10")
        private int size = 10;
    
        public int getOffset() {
            return (this.page - 1) * this.size;
        }
    }

     

    2. 조건 객체 생성

    public class ScheduleSearchDto {
    
        @Schema(description = "작성자 PK")
        private Long writerId;
    
        @Schema(description = "수정일")
        private String modDt;
    }

     

    3. Controller 매개변수 변경

    @GetMapping
    public BaseResponse<List<ScheduleResDto>> findAllSchedule(@ParameterObject CustomPageable pageable, @ParameterObject ScheduleSearchDto dto) {
        return BaseResponse.from(scheduleService.findAllSchedule(pageable, dto));
    }

     

    4.Service 

    public List<ScheduleResDto> findAllSchedule(CustomPageable pageable, ScheduleSearchDto dto) {
        return scheduleRepository.findAllSchedule(pageable, dto).stream()
                .map(ScheduleResDto::new) // 일정 목록 조회 후  mapping
                .collect(Collectors.toList());
    }

     

    5.Repository

    Limit, Offset 을 사용하여 페이징 처리

    public List<Schedule> findAllSchedule(CustomPageable pageable, ScheduleSearchDto dto) {
        List<Object> params = new ArrayList<>();
    
        StringBuilder query = new StringBuilder()
                .append("SELECT a.id, a.schedule, a.password, a.reg_dt, a.mod_dt\n")
                .append(" ,b.id AS writer_id, b.email, b.name, b.reg_dt as writer_reg_dt, b.mod_dt as writer_mod_dt\n")
                .append(" FROM schedule a JOIN writer b ON a.writer_id = b.id\n")
                .append(" WHERE a.del_dt IS NULL \n");
    
        if (dto.getWriterId() != null) { // 작성자 PK 검색조건이 있을 경우
            query.append(" AND b.id = ? \n");
            params.add(dto.getWriterId());
        }
    
        if (StringUtils.isNotBlank(dto.getModDt())) { // 수정일 검색조건이 있을 경우
            query.append(" AND DATE(a.mod_dt) = ? \n");
            params.add(dto.getModDt());
        }
    
        query.append(" ORDER BY a.mod_dt DESC \n")
                .append(" LIMIT ? OFFSET ?");
    
        // 페이징 계산
        params.add(pageable.getSize());               // LIMIT 몇 개 가져올지
        params.add(pageable.getOffset());        // OFFSET (page 번호 * size)
    
        return jdbcTemplate.query(query.toString(), params.toArray(), this.scheduleRowMapper());
    }

     

     

    3️⃣ 페이지네이션 결과 객체 

    페이지네이션을 도입 후 페이징 처리를 하기 위해 return 객체에 페이징 정보랑 총 데이터 수를 return 해주기로함

     

    1. 페이지네이션 결과 객체 생성

    제네릭을 사용하여 유연하게 대응

    public class PaginationResDto<T> {
    
        @Schema(description = "결과 Data 목록")
        private List<T> data;
    
        @Schema(description = "총 Data 수")
        private Long total;
    
        @Schema(description = "한 페이지에 표시할 데이터 개수")
        private Integer size;
    
        @Schema(description = "페이지 번호")
        private Integer page;
    
        @Schema(description = "총 페이지 수")
        private Long totalPages;
    }

     

    2. Controller Return 객체 변경

    @GetMapping
    public BaseResponse<PaginationResDto<ScheduleResDto>> findAllSchedule(@ParameterObject @Valid CustomPageable pageable, @ParameterObject ScheduleSearchDto dto) {
        return BaseResponse.from(scheduleService.findAllSchedule(pageable, dto));
    }

     

    3. Service, Return 객체 변경 및 총 데이터 수 조회 로직 추가

    public PaginationResDto<ScheduleResDto> findAllSchedule(CustomPageable pageable, ScheduleSearchDto dto) {
        long totalCnt = scheduleRepository.findAllScheduleCount(dto);
    
        List<ScheduleResDto> resultList = scheduleRepository.findAllSchedule(pageable, dto).stream()
                .map(ScheduleResDto::new) // 일정 목록 조회 후  mapping
                .collect(Collectors.toList());
    
        return PaginationResDto.<ScheduleResDto>builder()
                .data(resultList)
                .total(totalCnt)
                .size(pageable.getSize())
                .page(pageable.getPage())
                .totalPages((totalCnt + pageable.getSize() - 1) / pageable.getSize())
                .build();
    }

     

    4.Repository 총 데이터 수 조회 

    public long findAllScheduleCount(ScheduleSearchDto dto) {
        List<Object> params = new ArrayList<>();
    
        StringBuilder query = new StringBuilder()
                .append("SELECT count(*) \n")
                .append(" FROM schedule a JOIN writer b ON a.writer_id = b.id\n")
                .append(" WHERE a.del_dt IS NULL \n");
    
        if (dto.getWriterId() != null) { // 작성자 PK 검색조건이 있을 경우
            query.append(" AND b.id = ? \n");
            params.add(dto.getWriterId());
        }
    
        if (StringUtils.isNotBlank(dto.getModDt())) { // 수정일 검색조건이 있을 경우
            query.append(" AND DATE(a.mod_dt) = ? \n");
            params.add(dto.getModDt());
        }
    
        return jdbcTemplate.queryForObject(query.toString(), params.toArray(), Long.class);
    }

     

     

Designed by Tistory.