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.