쌓고 쌓다

[스프링 부트] 댓글, 날짜순 게시글 정렬 기능 - 14 본문

프로그래밍/spring

[스프링 부트] 댓글, 날짜순 게시글 정렬 기능 - 14

승민아 2023. 7. 23. 00:27

SpringDataJpa에서 페이징을 쉽게 처리할 수 있다.

public interface SpringDataJpaPosterRepository extends JpaRepository<Poster, Long> {
    Page<Poster> findByTitleContaining(String title, Pageable pageable);
}

검색과 관련된 코드 작성은 포스팅한적 있다. 자세한 사항은 그 게시글을 보자.

간단히 포함될 내용과 페이징 처리를 위한 파라미터를 전달하여

해당 내용이 포함되고 페이징 처리된 정보를 가져올 수 있다.

 

정렬시 Pageable 인터페이스를 넘겨준다. Pageable은 페이징 처리에 필요한 정보를 타입이며

실제 구현체는 PageRequest 클래스를 사용한다.

 

PageRequest 객체 생성 방법

Pageable pageable = PageRequest.of(page, 5, sort);

PageRequest 객체 생성 방법에는 여러 방법을 지원한다.

그 중에서 (page, size, sort) 형태로 페이징 처리된 게시글을 가져오고자 한다.

잘 정리된 내용은 아래의 블로그에 있다.

https://bnzn2426.tistory.com/135

 

PosterController 기존의 코드

@PageableDefault(sort="id", value=5, direction = Sort.Direction.DESC)
Pageable pageable
Page<Poster> pageList;
if(searchTitle==null || searchTitle.equals(""))
    pageList = posterService.pageList(pageable);
else
    pageList = posterService.searchPageList(searchTitle, pageable);

기존의 페이징 처리를 @PageableDefault로 기본값으로 제목 검색만 존재했고 id순 정렬이였다.

이제 날짜, 댓글순 등 정렬 방법을 자유자재로 변경하고 추가할 수 있게 작성하고자 한다.

 

PosterController - 변경 코드

@Controller
public class PosterController {

    @GetMapping("/posters")
    public String list(Model model, @RequestParam(defaultValue = "0") int page,@RequestParam(required = false, defaultValue = "regdate") String order, @RequestParam(required = false) String searchTitle) {

        Sort sort=Sort.by("regdate").descending();
        if(order.equals("comment"))
            sort = Sort.by("commentCnt").descending();

        Pageable pageable = PageRequest.of(page, 5, sort);
    }
    
}

 

URL로 쿼리스트링 파라미터를 변경했다.

@GetMapping("/posters")
    public String list(Model model, 
                @RequestParam(defaultValue = "0") int page, 
                @RequestParam(required = false, defaultValue = "regdate") String order,
                @RequestParam(required = false) String searchTitle) 
	{ }

page를 통해 원하는 페이지

order로 정렬 방식

searchTitle로 검색어를 받아오는 방식으로 변경했다.

이제 위의 파라미터들로 PageRequest를 생성하여 Pageable로 넘겨 원하는 방법으로 정렬 페이징을 처리할 수 있다.

 

PageRequest 생성

Sort sort=Sort.by("regdate").descending();
if(order.equals("comment"))
    sort = Sort.by("commentCnt").descending();
Pageable pageable = PageRequest.of(page, 5, sort);

Sort.by(정렬할 필드) 형태인데 쿼리스트링 파라미터의 order을 그대로 넣게 구현했다.

쿼리스트링 파마리터 order의 기본값은 defaultValue="regdate"로 날짜순으로 정렬한다.

만약 order이 comment라면 댓글 개수로 정렬하여야한다.

이때 Poster 클래스의 필드에 댓글 개수인 commentCnt가 있으므로

order가 comment라면 order 스트링을 commentCnt로 바꿔 댓글개수로 정렬하게 작성했다.

 

정렬 기준 변경 버튼

<div>
    <button th:onclick="|location.href='@{/posters(order=regdate, searchTitle=${searchTitle})}'|">최신순</button>
    <button th:onclick="|location.href='@{/posters(order=comment, searchTitle=${searchTitle})}'|">댓글순</button>
</div>

해당 버튼 클릭시 게시글 리스트 요청을 보내는데

정렬 기준인 order을 날짜, 댓글 개수로 맞춰 파라미터를 넣고

제목 검색은 기존의 searchTitle을 유지하도록했다.

posterList 페이지 요청시 page, order, searchTitle을 View에 함께 넘겨주게 작성했다.

이렇게 넘겨주면 페이지네이션시 유용할 것 같아서이다.

 

 

이제 페이지네이션을 통해 쿼리스트링을 유지하면서 이동하게 변경이 필요하다.

posterList.html

<li class="page-item">
	<a class="page-link" th:text="${num}"
        th:href="@{/posters(page=${num}-1, order=${order}, searchTitle=${searchTitle})}"></a>
</li>

페이지네이션시 넘어온 page, order, searchTitle을 통해 동작하도록 했다.

기존의 order과 searchTitle이 유지된다.

 

동작 결과

 

 

+ 위의 페이징 방법에는 문제가있다.

ORDER BY는 동일한 값에대해 고유한 순서를 보장해주지 않는다.

LIMIT는 서로 다른 행 집합을 선택을 보장해 주지 않는다.

https://non-stop.tistory.com/512

 

[JPA] Pageable 중복 레코드 문제 (MySQL Limit 주의)

문제의 발견 게시글 정렬의 방법으로 날짜, 댓글 개수를 구현했다. 이상하게 날짜순은 잘 정렬되어 나오는데 댓글 개수로 정렬시 게시글(레코드)의 누락과 중복이 발생했다. JPA의 Paging은 ORDER BY

non-stop.tistory.com

 

코드 수정

Sort sort=Sort.by(Sort.Order.desc("regdate"), Sort.Order.desc("id"));
if(order!=null&&order.equals("comment"))
    sort = Sort.by(Sort.Order.desc("commentCnt"), Sort.Order.asc("id"));
Comments