1. Spring Data JPA의 PagingAndSortingRepository
- 기본적으로 페이징과 정렬 기능을 지원하는 인터페이스
- Pageable 객체를 사용해 간단하게 페이징을 처리 가능
Ex 코드
// 1.
public interface UserRepository extends PagingAndSortingRepository<User, Long> {
Page<User> findAll(Pageable pageable);
}
Pageable pageable = PageRequest.of(0, 10); // 페이지 번호 0, 페이지 당 10개 데이터
Page<User> page = userRepository.findAll(pageable);
List<User> users = page.getContent(); // 페이징된 데이터
2. JpaRepository
- 더 많은 기능 제공
- 페이징을 포함, 여러 간편 작업 가능
- Page나 Slice를 반환하여 페이징 된 데이터 로드 가능
Ex 코드
public interface UseRepository extends JpaRepository<User, Long> {
Page<User> findByName(String name, Pageable pageable);
}
Pageable pageable = PageRequest.of(0, 10);
Page<User> page = userRepository.findByName("John", pageable);
List<User> users = page.getContent();
// Page : 전체 페이지 수, 현재 페이지 번호, 총 데이터 수 등을 제공
// Slice : 전체 페이지 수나 총 데이터 수 없이 다음 페이지가 있는지 여부만 제공
3. JPQL과 EntityManager를 사용한 페이징 처리
- 직접 JPQL 쿼리를 사용해 페이징 처리 가능
EntityManager
의createManager
의createQuery()
메소드를 사용하여 페이징 쿼리 실행
Ex 코드
String jpql = "SELECT u FROM User u WHERE [u.name](http://u.name/) = :name";
TypedQuery<User> query = entityManager.createQuery(jpql, User.class);
query.setParameter("name", "John");
query.setFirstResult(0); // 시작 인덱스 (0부터 시작)
query.setMaxResults(10); // 한 번에 가져올 데이터 수
List<User> users = query.getResultList();
4. Native Query를 사용한 페이징 처리
- Native SQL Query를 통해서도 페이징 구현 가능
- 이 경우 SQL 문법을 그대로 사용 가능
Ex 코드
@Query(value = "SELECT * FROM users WHERE name = :name LIMIT :limit OFFSET :offset", nativeQuery = true)
List<User> findUsersByNameWithPaging(@Param("name") String name, @Param("limit") int limit, @Param("offset") int offset);
List<User> users = userRepository.findUsersByNameWithPaging("John", 10, 0);
5.Json Viewer(https://jsonviewer.stack.hu)를 통한 데이터 시각화


실습
1. Controller
@GetMapping("/")
public String list(
@RequestParam(name = "title", required = false) String title,
@RequestParam(name = "page", required = false, defaultValue = "0") Integer page,
HttpServletRequest request) {
Page<Board> boardP6 = boardService.게시글목록보기(title, page); // jpa의 Page 객체로 반환
// Request에 Model 추가
request.setAttribute("model", boardP6);
request.setAttribute("prev", boardP6.getNumber()-1);
request.setAttribute("next", boardP6.getNumber()+1);
return "board/list";
}
2. Service
public Page<Board> 게시글목록보기(String title, int page) {
// 한 페이지당 3개 게시글 보여줌, ID 기준 내림차순, PageRequest.of를 통해 페이징 처리를 위한 Pageable 객체 생성
Pageable pageable = PageRequest.of(page, 3, Sort.Direction.DESC, "id");
if (title == null) { // 검색어 없으면 findAll(pageable) 메소드를 사용해 모든 게시글 가져옴
return boardRepository.findAll(pageable);
} else { // 검색어 있으면 mFindAll(title, pageable)로 제목에 해당 검색어 포함 게시글 목록 가져옴
return boardRepository.mFindAll(title, pageable);
}
}
3. Repository
public interface BoardRepository extends JpaRepository<Board, Integer> {
@Query("select b from Board b where b.title like %:title% order by b.id desc")
Page<Board> mFindAll(@Param("title") String title, Pageable pageable);
@Query("select b from Board b join fetch b.user left join fetch b.replies r left join fetch r.user where b.id=:id")
Optional<Board> mFindByIdWithReply(@Param("id") int id);
@Query("select b from Board b join fetch b.user u where b.id=:id")
Optional<Board> mFindById(@Param("id") int id);
}
mFindAll
: 제목에 검색어가 포함된 게시글을 ID 기준으로 내림차순 정렬하여 페이징 처리된 결과를 반환하는 커스텀 쿼리.@Query
어노테이션으로 JPQL로 쿼리 작성.%:title%
은 제목에 해당 검색어가 포함된 항목을 검색
mFindByIdWithReply
: 게시글을 조회하면서 해당 게시글의 유저 정보 및 댓글과 관련된 유저 정보까지 fetch join으로 가져옴
mFindById
: 특정 ID에 해당하는 게시글과 그 유저 정보를 가져옴
4. mustache
<div class="container p-5">
<div class="d-flex justify-content-end mb-2">
<form action="/" method="get" class="d-flex col-md-3">
<input class="form-control me-2" type="text" placeholder="Search" name="title">
<button class="btn btn-primary">Search</button>
</form>
</div>
{{#model.content}}
<div class="card mb-3">
<div class="card-body">
<h4 class="card-title mb-3">{{title}}</h4>
<a href="/board/{{id}}" class="btn btn-primary">상세보기</a>
</div>
</div>
{{/model.content}}
<ul class="pagination d-flex justify-content-center">
<li class="page-item"><a class="page-link" href="?page={{prev}}">Previous</a></li>
<li class="page-item"><a class="page-link" href="?page={{next}}">Next</a></li>
</ul>
</div>
{{#model.content}}
:model
의content
리스트를 순회하며 게시글 출력model.content
는Page
객체의 게시글 목록.
{{prev}}
,{{next}}
: 이전 페이지와 다음 페이지 링크 제공. Controller에서 설정한prev
와next
를 사용
5. Response DTO
@Data
public static class PageDTO {
private Integer number; // 현재 페이지
private Integer totalPage; // 전체 페이지 개수
private Integer size; // 한 페이지에 보여줄 아이템 개수
private Boolean first; // 첫 번째 페이지 여부
private Boolean last; // 마지막 페이지 여부
private Integer prev; // 이전 페이지
private Integer next; // 다음 페이지
private List<Content> contents; // 페이지에 포함된 게시글 리스트
@Data
class Content {
private Integer id; // 게시글 ID
private String title; // 게시글 제목
}
}
Page
객체에서 필요한 정보를 추출하여 클라이언트로 전달할 때 사용
요약
- 클라이언트가 검색어와 페이지 번호를 전송하면 Controller에서 받아 Service에 전달
- Service는 검색어 유무에 따라 적절한 Repository 메소드 호출 후 데이터 로드
- Repository는 JPA를 통해 DB에서 데이터 조회, 결과를
Page
객체 반환
- Controller는 이 데이터를 mustache에 전달해 페이징된 게시글 목록을 화면에 렌더링
Share article