semtax의 개발 일지

스프링부트로 게시판 만들기 9 : 페이징 기능 구현 본문

개발/Java

스프링부트로 게시판 만들기 9 : 페이징 기능 구현

semtax 2020. 5. 1. 19:13
반응형

개요

이번 포스팅에서는, 게시글 페이징을 구현하는 시간을 가지도록 하겠다.

##페이징을 왜 쓰는건가?

사실, 이 글을 읽는 사람들 중에서 이런 생각을 하는 사람도 있을것이다.

굳이, 페이징 안쓰고 한꺼번에 보여주면 안되는건가? 왜 귀찮게 잘라서 보여주려는거지?

물론 유저의 숫자도 적고, 데이터의 양이 10개, 100개 처럼 양이 적은 경우에는 굳이 페이징을 안하고 한꺼번에 로딩해서 보여줘도 된다.

하지만, 유저수가 많아지고, 불러와야 하는 데이터의 양도 많아지고, 처리해야되는 로직이 복잡해진다면 이는 크나큰 성능 병목으로 이어지게 된다.

여담으로, 실제로 필자가 겪어본 서비스 중에, 동시 접속자 수가 30005000 정도 되는 서비스인데, 페이징 기능이 구현이 안되있어서 로딩에 거의 25분 정도가 걸리는 케이스도 경험을 해보았다.

따라서, 저렇게 데이터가 많은 경우에는 어차피 사람은 인지적 한계로 인해 모든 데이터를 한번에 볼수 있는 능력이 없으므로, 쪼개서 데이터를 보여주는것이 성능을 덜 깎아먹는 선택지가 된다.

그러면 스프링, 그리고 JPA 에서는 어떻게 페이징을 구현하는걸까?

구현 아이디어 떠올려 보기

사실 방법은 여러가지가 있긴 하다.

가장 단순하게 떠올릴 수 있는 방법은 SQL을 이용하는 것인데, SQL로 구현을 한다면 대략 아래와 같이 구현하면 된다.

"SELECT * FROM post LIMIT page_size*(page_num-1), page_size"

이때, page_size는 한번에 보여줄 개수이고, page_num은 페이지 번호이다.

조금 더 효울적으로 짠다고 하면, 아래와 같이 짜면 된다.

SELECT * FROM my_table WHERE id > page_size*(page_num-1)-1 LIMIT page_size;

하지만, 페이징을 해야되는 기준이 복잡하거나 한다면(예를 들어 특정 목록 기준으로 정렬을 해서 보여줘야 된다거나), 저 쿼리를 짜는것이 매우 고역인 작업이 된다.

다행히도 Spring Data JPA 에서는 페이징을 편하게 해주는 기능을 기본적으로 제공을 해주고 있다.

그럼 페이징 기능을 실제로 구현을 하면서, 알아보도록 하자.

##구현

Spring Data JPA 에서는, 페이징을 위해서 기본적으로 Page 라는 객체와, Pageable 이라는 객체를 가지고 있다.

간단하게 말해서, Pagable 이라는 객체는, 페이징 하는 방법을 기술해놓은 클래스(인터페이스) 라고 보면되고, Page 객체는 실제로 페이징으로 잘려진 객체들을 담고있는 객체라고 생각하면 된다.

대략적으로 사용방법은 아래와 같다.

먼저, JPA 레포지토리에 Paging 하는 함수를 선언 해준다.

// JPA 레포지토리에 Paging 함수 선언
public interface PostRepository extends JpaRepository<Post,Long> {

    Page<Post> findAll(Pageable pageable);
}

그리고, 페이징을 위한 DTO를 실제로 작성을 해보도록 하자.

(Entity를 그대로 넘길 수도 있지만, 이렇게 되면 만약 Entitiy가 변경되는 경우 API의 스펙이 바뀌어 버리므로 사용하는 사람 입장에서는 혼란이 오게 된다.)

package com.semtax.application.dto;


import lombok.Data;

import java.time.LocalDateTime;
import java.util.Objects;

@Data
public class PagingDTO {

    private Long id;
    private String title;
    private String createdBy;
    private LocalDateTime createdTime;

    public PagingDTO(Long id, String title, String createdBy, LocalDateTime createdTime) {
        this.id = id;
        this.title = title;
        this.createdBy = createdBy;
        this.createdTime = createdTime;
    }
}

다음으로, 실제로 페이징을 사용해주는 코드를 작성 해준다.

// 실제로 JPA로 선언된 레포지토리를 사용하는 곳

@RestController
@RequiredArgsConstructor
public class PageController {

    @Autowired
    PostRepository postRepository;

    @CrossOrigin(origins = "*", allowedHeaders = "*")
    @GetMapping("/post/page")
    public Page<PagingDTO> paging(@PageableDefault(size=5, sort="createdTime") Pageable pageRequest) {

        Page<Post> postList = postRepository.findAll(pageRequest);

        Page<PagingDTO> pagingList = postList.map(
                post -> new PagingDTO(
                    post.getId(),post.getTitle(),
                    post.getCreatedBy(), post.getCreatedTime()
                ));

        return pagingList;
    }
}

사실, 위와 같이 컨트롤러에 직접 작성하는것보다, 서비스 객체를 따로 만들어서 위에서 선언한 컨트롤러 부분을 서비스 객체에 전부 옮겨주는게 더 좋다.

마지막으로, 인터셉터에서 페이징 URL 부분을 제외 해주도록 하자.

@Configuration
public class WebserviceConfig implements WebMvcConfigurer {

    @Autowired
    LoginInterceptor loginInterceptor;

    @Autowired
    PostAuthInterceptor postAuthInterceptor;

    @Autowired
    CommentAuthInterceptor commentAuthInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .excludePathPatterns("/post/page")
                .addPathPatterns("/post/**")
                .addPathPatterns("/comment/**");

        registry.addInterceptor(postAuthInterceptor)
                .excludePathPatterns("/post/page")
                .excludePathPatterns("/post/**/comment/**")
                .addPathPatterns("/post/**");

        registry.addInterceptor(commentAuthInterceptor)
                .addPathPatterns("/post/**/comment/**");
    }
}

테스트

Postman을 켜서 아래와 같이 실행을 해보자.

먼저 저번 포스팅과 똑같이 회원가입, 로그인을 해주고 포스팅을 대충 8~10개 정도 생성해주자.

다음으로 페이징 API에 아래와 같이 실제로 요청을 해주자

정상적으로 페이징이 되는것을 확인 할 수 있다.

출처

  1. [https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%8D%B0%EC%9D%B4%ED%84%B0-JPA-%EC%8B%A4%EC%A0%84/dashboard](
반응형
Comments