오늘은 페이징 처리하는 방법을 알아보자.
페이징 처리하는 방법은 생각보다 간단했다. 🙋♀️
Controller 코드
먼저 컨트롤러에서 @PageableDefault 어노테이션을 명시하고, Pageable 객체를 받아오면 된다.
@PageableDefault는 Spring Data JPA에서 페이징 처리를 위한 기본 설정을 지정하는 어노테이션이다.
이 어노테이션은 컨트롤러의 매개변수로 받는 Pageable 객체의 기본값을 설정할 때 사용된다.
또한 size 속성을 활용해서 몇개씩 content 를 끊어서 가져올지도 명시하면된다.
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
@RestController
@RequiredArgsConstructor
public class ImageApiController {
private final ImageService imageService;
@GetMapping("/api/image")
public ResponseEntity<?> imageStory(@AuthenticationPrincipal PrincipalDetails principalDetails,
@PageableDefault(size = 3) Pageable pageable) { // 파라미터로 pagealble 객체 받기
Page<Image> images = imageService.imageStory(principalDetails.getUser().getId(), pageable);
return new ResponseEntity<>(new CMRespDto<>(1, "이미지 스토리 불러오기 성공", images), HttpStatus.OK);
}
}
또한 Service 단으로 pageable 객체를 그대로 전달해주면 된다.
더불어 리턴받는 객체 타입을 Page 로 받아줘야한다.
🚨 주의
import 문을 잘 보자.
org.springframework.data.domain 패키지의 Page, Pageable 을 받아와야 한다.
Service 코드
@Transactional(readOnly = true)
public Page<Image> imageStory(int principalId, Pageable pageable) {
Page<Image> images = imageRepository.mStory(principalId, pageable);
return images;
}
- 파라미터로 받아온 pageable 객체를 Repository 단으로 그대로 전달한다.
- 리턴타입을 Page 객체타입으로 변경해준다.
Repository 코드
@Query(value = "SELECT * FROM Image WHERE userId IN (SELECT toUserId FROM Subscribe WHERE fromUserId = :principalId) ORDER BY id DESC", nativeQuery = true)
Page<Image> mStory(int principalId, Pageable pageable);
- 쿼리 뒷 부분에 ORDER BY id DESC 로 정렬 기준을 명시해준다.
- 역시 리턴 타입을 Page 로 받고,
- 매개변수로 전달할 때 Pageable 객체를 함께 넘겨준다.
Postman 으로 호출하여 테스트 해보기
요청 URL :
http://localhost:8080/api/image?page=1
- 파라미터로 페이지의 번호를 함께 넘긴다.
결과 JSON
{
"code": 1,
"message": "이미지 스토리 불러오기 성공",
"data": {
"content": [
{
"id": 2,
"caption": "증명사진입니다. ",
"postImageUrl": "057ca241-2b08-47f5-99bc-20458819122d_강민희_증명사진_24.jpeg",
"user": {
"id": 1,
"username": "ssar",
"password": "$2a$10$IvSLlXgdAFg4PExkMwP5ReQAo5xhxZPCyDXc4C46iThNp.TtSsjYK",
"name": "쌀",
"website": "https://github.com/minhe2810",
"bio": "안녕하세요. ddd 입니다. 가가가",
"email": "ssar@naver.com",
"phone": "0104699",
"gender": "여",
"profileImageUrl": null,
"role": "ROLE_USER",
"createDate": "2024-03-13T16:12:17.173425"
},
"createDate": "2024-03-13T17:15:40.489208"
},
{
"id": 1,
"caption": "내 미니마우스 기엽지",
"postImageUrl": "28efeb09-ab6c-4027-bac3-1f9a3b410f6f_미니.jpeg",
"user": {
"id": 1,
"username": "ssar",
"password": "$2a$10$IvSLlXgdAFg4PExkMwP5ReQAo5xhxZPCyDXc4C46iThNp.TtSsjYK",
"name": "쌀",
"website": "https://github.com/minhe2810",
"bio": "안녕하세요. ddd 입니다. 가가가",
"email": "ssar@naver.com",
"phone": "0104699",
"gender": "여",
"profileImageUrl": null,
"role": "ROLE_USER",
"createDate": "2024-03-13T16:12:17.173425"
},
"createDate": "2024-03-13T16:12:42.465745"
}
],
"pageable": {
"sort": {
"sorted": false,
"unsorted": true,
"empty": true
},
"offset": 3,
"pageNumber": 1,
"pageSize": 3,
"paged": true,
"unpaged": false
},
"last": true,
"totalPages": 2,
"totalElements": 5,
"size": 3,
"first": false,
"sort": {
"sorted": false,
"unsorted": true,
"empty": true
},
"number": 1,
"numberOfElements": 2,
"empty": false
}
}
- content 로 묶여서 데이터들이 정렬되어 출력되는 것을 발견할 수 있다.
- number 값을 보면 페이지 번호가 기록되어있다.
- 예시 json 데이터는 page 파라미터의 값을 1로 넘겼으므로 number: 1 인 것을 발견할 수 있다.
웹 브라우저에서 해당 URL 을 요청해도 json 데이터 출력결과를 볼 수 있다.
역시 page 파라미터를 바꿀때마가 출력되는 데이터는 다르게 보인다.
Spring Data JPA 제공 page 기능을 활용해보았는데 생각보다 매우 간단해서 조금 당황스러웠다!
이번 글에서는 JavaScript와 AJAX를 사용하여 페이징 처리를 구현하는 방법에 대해 알아보자.
페이지 내의 특정 부분에 데이터를 동적으로 불러오는 방법을 통해 사용자 경험을 향상시킬 수 있다!
페이지 레이아웃
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="../layout/header.jsp"%>
<main class="main">
<section class="container">
<!--전체 리스트 시작-->
<article class="story-list" id="storyList">
<!--전체 리스트 아이템-->
<!-- 스토리 아이템 끝-->
</article>
</section>
</main>
<script src="/js/story.js"></script>
</body>
</html>
Javascript 로 데이터 불러오기
// (1) 스토리 로드하기
let page = 0; // 페이지 값을 스크롤하면서 올리기 위해서 변수 선언 후 0으로 초기화
function storyLoad() {
$.ajax({
url: `/api/image?page=${page}`,
dataType: "json"
}).done(res=>{
console.log(res);
res.data.content.forEach((image)=> {
let storyItem = getStoryItem(image);
$("#storyList").append(storyItem);
})
}).fail(error=>{
console.log("오류 : " , error);
});
}
- 위의 코드에서는 storyLoad() 함수를 호출하여 페이지가 로드될 때마다 서버로부터 데이터를 가져와 화면에 표시한다.
- /api/image 엔드포인트로 AJAX 요청을 보내고, 페이지 번호를 쿼리 스트링으로 전달하여 페이징 처리를 구현한다.
- 받아온 데이터는 res.data.content 에 있으며, 각각의 이미지에 대해 getStoryItem 함수를 호출하여 스토리 아이템을 생성하고 #storyList 에 추가한다.
- 이렇게 함으로써 페이지를 로드할 때마다 새로운 데이터를 가져와서 화면에 표시할 수 있게된다.
getStoryItem() 함수
function getStoryItem(image) {
let item = `<div class="story-list__item">
<div class="sl__item__header">
<div>
<img class="profile-image" src="/upload/${image.user.profileImageUrl}"
onerror="this.src='/images/person.jpeg'" />
</div>
<div>${image.user.username}</div>
</div>
<div class="sl__item__img">
<img src="/upload/${image.postImageUrl}" />
</div>
<div class="sl__item__contents">
<div class="sl__item__contents__icon">
<button>
<i class="fas fa-heart active" id="storyLikeIcon-1" onclick="toggleLike()"></i>
</button>
</div>
<span class="like"><b id="storyLikeCount-1">3 </b>likes</span>
<div class="sl__item__contents__content">
<p>${image.caption}</p>
</div>
<div id="storyCommentList-1">
<div class="sl__item__contents__comment" id="storyCommentItem-1"">
<p>
<b>Lovely :</b> 부럽습니다.
</p>
<button>
<i class="fas fa-times"></i>
</button>
</div>
</div>
<div class="sl__item__input">
<input type="text" placeholder="댓글 달기..." id="storyCommentInput-1" />
<button type="button" onClick="addComment()">게시</button>
</div>
</div>
</div>`;
return item;
}
scroll 할 때마다 데이터를 렌더링하는 기능
// (2) 스토리 스크롤 페이징하기
$(window).scroll(() => {
// console.log("윈도우 scrollTop", $(window).scrollTop());
// console.log("문서의 높이", $(document).height());
// console.log("윈도우 높이", $(window).height());
let checkNum = $(window).scrollTop() - ($(document).height() - $(window).height() );
console.log(checkNum);
if(checkNum < 1 && checkNum > -1){
page++;
storyLoad();
}
});
먼저 콘솔로 다음을 출력해보면
console.log("윈도우 scrollTop", $(window).scrollTop());
console.log("문서의 높이", $(document).height());
console.log("윈도우 높이", $(window).height());
다음과 같이 스크롤의 높이, 문서의 높이, 윈도우의 높이가 출력된다.
또한 checkNum 변수를 만든 뒤 윈도우의 scrollTop - (문서의 높이 - 윈도우의 높이) 를 계산해서 콘솔 로그를 찍어보면
스크롤이 가장 아래로 내려가는 시점의 checkNum 은 -0.75 즉 1과 -1 정도로 계산이 된다.
따라서 if문을 활용해서 1과 -1 사이의 값일 때 storyLoad() 함수를 호출하여 계속해서 새로운 item 들을 가져오고 page++ 를 통해서 다음 페이지의 값들을 랜더링 할 수 있도록 값을 하나씩 올려주면 된다.
이와 같이 설정한 뒤 실행시켜보면
-0.25일 때 새로 함수를 호출해서 값을 추가적으로 불러오는 것을 발견할 수 있다.
그럼 checkNum 이 계속 음수로 가는 것을 발견할 수 있는데 그럼 또 스크롤 가장 끝으로 가면 어떻게 될까?
이렇게 다시 -1 과 1 사이가 되고 다시 checkNum 값이 조건에 일치하여 함수를 호출하게 된다.
'👩💻 BackEnd > 🍃 스프링부트 [SpringBoot]' 카테고리의 다른 글
[ SpringBoot ]@NotNull, @NotEmpty, @NotBlank 차이 (0) | 2024.03.19 |
---|---|
[SpringBoot] 중복 유니크 키 제약조건 생성 (0) | 2024.03.18 |
[JPA] 양방향 매핑 (0) | 2024.03.13 |
[ Spring Boot / thymleaf ] spring mvc 2 검증 내용 정리 (0) | 2024.02.22 |
[JSP / Spring Boot] 시큐리티 태그 라이브러리 (0) | 2024.02.21 |