[내배캠/26일차] TIL - 페이지네이션, 예외처리

euphony·2025년 2월 3일
0

내일배움캠프

목록 보기
41/66

✅오늘의 한 일

  • Spring 입문 과제 Lv.3 ~ Lv.6 완료
  • 트러블 슈팅 작성 및 새로 알게 된 내용 정리

💻오늘의 학습

Spring 입문 과제 - 일정 관리 앱

페이지네이션

  • 페이지네이션(Pagination) : 많은 데이터를 여러 페이지로 나누어 표시하는 기술.

웹 애플리케이션이나 데이터베이스에서 데이터를 조회할 때, 한 번에 모든 데이터를 불러오면 성능 문제가 발생할 수 있기 때문에 이를 해결하기 위해 페이지 단위로 데이터를 가져오는 방식을 사용한다. 페이지네이션을 이용해 등록된 일정을 페이지 번호와 크기 기준으로 모두 조회하는 기능을 구현했다.

페이지네이션의 방식에는 다음과 같이 두 가지가 있었다. 그 중 가장 많이 사용되는 방식인 오프셋 기반 페이지네이션을 사용했다.

  • 오프셋 기반 페이지네이션
  • 커서 기반 페이지네이션

Pageable 객체를 이용하면 더 편리하다고 했지만, 현재 프로젝트에서는 JDBC만 사용 중이기 때문에 직접 LIMITOFFSET을 사용하는 방향으로 진행했다. 따라서 다음과 같이 직접 Paging 클래스를 만들어 페이지네이션을 처리했다.

@Getter
@AllArgsConstructor
public class Paging<T> {
    private List<T> content;
    private int totalPages;
    private int totalElements;
    private int size;
    private int number;
}

기존 코드에서의 List<T> 대신 Paging<T>을 사용해 페이지네이션 정보를 포함하여 반환받도록 했다. 그리고 기존 코드의 매개변수에 pagesize를 추가했다.

@GetMapping
public ResponseEntity<Paging<ScheduleResponseDto>> findSchedules(
        @RequestParam(required = false) String writer,
        @RequestParam(required = false) String updatedAt,
        @RequestParam(defaultValue = "0") int page,
        @RequestParam(defaultValue = "5") int size
) {
    Paging<ScheduleResponseDto> response;

    if (writer == null && updatedAt == null) {
        response = scheduleService.findAllSchedules(page, size);
    } else {
        response = scheduleService.findSchedules(writer, updatedAt, page, size);
    }
    return ResponseEntity.ok(response);
}

Service Layer에서는 Repository를 통해 pagesize에 맞는 Schedule 목록과 totalElements(전체 데이터 개수)와 totalPages(총 페이지 개수)를 구해 반환한다.

@Override
public Paging<ScheduleResponseDto> findAllSchedules(int page, int size) {
    List<ScheduleResponseDto> schedules = scheduleRepository.findAllSchedules(page, size);
    int totalElements = scheduleRepository.countSchedules();
    int totalPages = (int) Math.ceil((double) totalElements / size);
    return new Paging<>(schedules, totalPages, totalElements, size, page);
}

@Override
public Paging<ScheduleResponseDto> findSchedules(String writer, String updatedAt, int page, int size) {
    List<ScheduleResponseDto> schedules = scheduleRepository.findSchedules(writer, updatedAt, page, size);
    int totalElements = scheduleRepository.countSchedulesByWriter(writer, updatedAt);
    int totalPages = (int) Math.ceil((double) totalElements / size);
    return new Paging<>(schedules, totalPages, totalElements, size, page);
}

Repository Layer에서는 userId를 기준으로 schedules 테이블과 users 테이블을 조인해 각 사용자와 맞는 일정을 조회하고자 했다.

private String getScheduleWithUserQuery() {
    return """
    SELECT s.scheduleId, s.task, u.name AS writer, s.createdAt, s.updatedAt
    FROM schedules s
    JOIN users u ON s.userId = u.userId
""";
}
@Override
public int countSchedules() {
    return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM schedules", Integer.class);
}
@Override
    public int countSchedulesByWriter(String writer, String updatedAt) {
        List<Object> params = new ArrayList<>();

        StringBuilder query = new StringBuilder("""
            SELECT COUNT(*)
            FROM schedules s
            JOIN users u ON s.userId = u.userId
        """);

        if (writer != null || updatedAt != null) {
            query.append(" WHERE");

            boolean addAnd = false;

            if (writer != null) {
                query.append(" u.name = ?");
                params.add(writer);
                addAnd = true;
            }

            if (updatedAt != null) {
                if (addAnd) query.append(" AND");
                query.append(" DATE(s.updatedAt) = ?");
                params.add(updatedAt);
            }
        }

        return jdbcTemplate.queryForObject(
                query.toString(),
                Integer.class,
                params.toArray()
        );
    }

📝오늘의 회고

주말 일정 때문에 오늘 벼락치기로 과제를 거의 마무리 했다. 숙련 과제는 빨리 끝내고 나서 리팩토링 해보는 시간을 가지고 싶다.😵

📌내일의 할 일

  • Spring 입문 과제 제출
  • 자바 중급 2편 섹션 11 완료
  • Spring 기초 강의 듣기
  • 베이직반 Spring 강의 듣기

0개의 댓글

관련 채용 정보