20220904_WIL
들어가며
오늘로 실전 프로젝트 9일차, 전주 금요일에 발제하여 주차로는 2주차가 지나가고있다. 오늘은 실전 프로젝트 2주차에 대한 회고와 더불어 가장 최근에 도입했던 Pageable 사용법에 대하여 정리해보고자 한다.
Pageable
Pageable은 Spring framework에서 제공하는 내장 인터페이스로서 Pagination(직역하자면 쪽수 매기기)을 위하여 요청하는 정보를 page(말 그대로 페이지, 0부터 시작한다.)와 size(한 페이지 당 넘겨줄 정보 단위)로 끊어주는 기능이다.
Pageable로 인하여 spring에서는 이러한 Pagination을 위한 밑작업을 정말 간단하게 구현할 수 있었다.
내가 기존 작성했던 전체 상품(게시글) 조회 Method가 Pageable을 도입하여 어떻게 Response Data가 변화하는지 기록해보고자 한다.
ItemController(Pageable 적용 전)
/* 전체 상품 조회 */
@GetMapping("items")
public ResponseEntity<?> getAllItem(@AuthenticationPrincipal UserDetails userDetails) {
return ResponseEntity.ok().body(itemService.getAllItem(userDetails));
}
ItemService(Pageable 적용 전)
/* 전체 상품 조회 */
@Transactional(readOnly = true)
public List<ItemResponseDto> getAllItem(UserDetails userDetails) {
List<Item> itemList = itemRepository.findAllByOrderByCreatedAtDesc();
List<ItemResponseDto> itemResponseDtoList = new ArrayList<>();
for (Item item : itemList) {
itemResponseDtoList.add(
buildItemResponseDto(userDetails, item)
);
}
return itemResponseDtoList;
}
//...
/* 공통 작업 - ResponseDto build */
private ItemResponseDto buildItemResponseDto(UserDetails userDetails, Item item) {
int commentCnt = commentRepository.countByItem_Id(item.getId());
/* 해당 item의 이미지 호출 */
List<Image> imageList = imageRepository.findAllByItemId(item.getId());
List<String> imgUrlList = new ArrayList<>();
for (Image image : imageList) {
System.out.println();
imgUrlList.add(image.getImgUrl());
}
/* IsZzimed - 사용자가 찜한 상품인지 아닌지 확인 */
boolean isZzimed = false;
if(userDetails != null) {
Optional<Zzim> zzim = zzimRepository.findByItemIdAndZzimedBy(item.getId(), userDetails.getUsername());
if(zzim.isPresent()) isZzimed = true;
}
return ItemResponseDto.builder()
.id(item.getId())
.IsMine(userDetails != null && item.getNickname().equals(((UserDetailsImpl) userDetails).getMember().getNickname()))
.nickname(item.getNickname())
.title(item.getTitle())
.content(item.getContent())
.petCategory(item.getPetCategory())
.itemCategory(item.getItemCategory())
.itemImgs(imgUrlList)
.location(item.getLocation())
.zzimCnt(item.getZzimCnt())
.commentCnt(commentCnt)
.viewCnt(item.getViewCnt())
.purchasePrice(item.getPurchasePrice())
.sellingPrice(item.getSellingPrice())
.IsComplete(item.isComplete())
.IsZzimed(isZzimed)
.createdAt(item.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")))
.modifiedAt(item.getModifiedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")))
.build();
}
ItemRepository - Pageable 적용 전
List<Item> findAllByOrderByCreatedAtDesc();
Pageable을 적용하기 전에는 아주 평범한 Get Method였다. 기존에 등록된 Item(게시글)들을 전부 불러오는(등록시점을 기준으로 내림차순으로 정렬) 메소드였다. 게시글이 서버에 40개가 등록되어있다면 40개 모두 한 번에 불러왔다.
하지만 이번 실전 프로젝트에서 FE는 무한스크롤을 도입하고자 하였고, 해당 파트의 BE를 담당하고 있는 나에게 한 번의 요청마다 10개의 게시글만을 불러와줄 것을 부탁하였다. 이를 바탕으로 Pageable을 적용한 코드는 다음과 같다.
(수정된 부분에 주석으로 설명을 붙였다.)
ItemController - Pageable 적용 후
/* 전체 상품 조회 */
@GetMapping("items")
public ResponseEntity<?> getAllItem(@AuthenticationPrincipal UserDetails userDetails,
Pageable pageable) { /* Pageable pageable 추가 */
return ResponseEntity.ok().body(itemService.getAllItem(userDetails, pageable));
}
ItemService - Pageable 적용 후
/* 전체 상품 조회 */
@Transactional(readOnly = true) /* Pageable pageable 추가 */
public List<ItemResponseDto> getAllItem(UserDetails userDetails, Pageable pageable) {
Page<Item> itemList = itemRepository.findAllByOrderByCreatedAtDesc(pageable); /* List -> Page / Method도 수정 */
List<ItemResponseDto> itemResponseDtoList = new ArrayList<>();
for (Item item : itemList) {
itemResponseDtoList.add(
buildItemResponseDto(userDetails, item)
);
}
return itemResponseDtoList;
}
ItemRepository - Pageable 적용 후
/* Return type을 List에서 Page로 수정, 파라미터 값으로 Pageable pageable 추가 */
Page<Item> findAllByOrderByCreatedAtDesc(Pageable pageable);
정말 코드 몇 자 추가하지 않았는데 간단하게 페이지네이션을 위한 밑작업이 완료되었다, Postman을 통해 해당 API를 확인한결과는 다음과 같았다.
해당 요청을 위해서는 파라미터 값으로 page(페이지 - 0부터 시작, 0이 첫 페이지)와 size(한 페이지에 불러올 게시글 수)를 보내야했다.
위 이미지 크기의 한계가 있어 확인이 어렵지만 39개의 게시글이 등록되어있는 서버에서 정확히 10개의 게시글만을 불러온 것이 확인되었다. 페이지를 0이 아닌 1로 바꾸자 그 다음 페이지에 등록되어 있는 게시글 10개가 차례로 보여졌다.
이것만으로도 Pageable 사용이 완료가 된 것이지만 추가로 한 스탭 더 설정해줄 수 있는 부분이 있었다.
바로 @PageableDefault가 그것이다.
@PageableDefault 어노테이션은 Pageable 인터페이스를 사용함에 있어서 편의성을 증대해주는 어노테이션으로 default page, size, sort(정렬) 등을 설정해줄 수 있다.
이번 프로젝트에서 FE 측에서 요청했던 것은 한 번의 요청 당 10개의 게시글을 불러올 수 있게해달라는 것이었다. 이를 바탕으로 코드를 일부 수정하였다.
ItemController - @PageableDefault 적용 후
/* 전체 상품 조회 */
@GetMapping("items")
public ResponseEntity<?> getAllItem(@AuthenticationPrincipal UserDetails userDetails,
/* @PageableDefault 추가, sort(정렬 기준), direction(정렬 방식) */
@PageableDefault(sort = "id", direction = Sort.Direction.DESC) Pageable pageable) {
return ResponseEntity.ok().body(itemService.getAllItem(userDetails, pageable));
}
ItemService - @PageableDefault 적용 후
/* 전체 상품 조회 */
@Transactional(readOnly = true)
public List<ItemResponseDto> getAllItem(UserDetails userDetails, Pageable pageable) {
Page<Item> itemList = itemRepository.findAll(pageable); /* 게시글 찾는 Method 간소화 */
List<ItemResponseDto> itemResponseDtoList = new ArrayList<>();
for (Item item : itemList) {
itemResponseDtoList.add(
buildItemResponseDto(userDetails, item)
);
}
return itemResponseDtoList;
}
ItemRepository - @PageableDefault 적용 후
/* 게시글 찾는 Method 간소화 - 정렬 부분 삭제 */
Page<Item> findAll(Pageable pageable);
ItemController 중 Pageable에 대한 부분이다.
@PageableDefault(sort = "id", direction = Sort.Direction.DESC) Pageable pageable)
size는 default 값이 10으로 설정되어있다.
FE에서 요청하였던 size는 10이었기에 따로 작성할 필요가 없었다.
기존에는 ItemRepository 단의 메소드에서 OrderBy로 정렬한 값을 가져왔지만 @PageableDefault 자체에 정렬 기준 및 방식을 설정할 수 있었기에 메소드 자체를 간략화하여 @PageableDefault 설정값으로 대체하였다.
findAllByOrderByCreatedAtDesc() -> findAll
sort는 정렬기준, Item의 id를 기준으로 정렬하도록 설정하였으며 정렬 방식은 DESC(내림차순)으로 설정해주었다.
이를 바탕으로 가장 최신글부터 차례로 불러오게끔 만들었다.
size를 별도로 파라미터로 설정해주지 않아도 10개의 게시글만을 불러왔으며 Repository 단의 메소드를 간략화하였지만(정렬 부분 삭제) Id값을 기준으로 내림차순 정렬하여 값을 가져오는 것을 확인 할 수 있었다.
처음 항해에 합류하였을 때는 실전 프로젝트가 무척이 겁이 났었다.
제로베이스인 내가 과연 잘 할 수 있을까란 의문이 항상 들었고 팀원들에게 폐를 끼치지는 않을까, 내가 스스로 무너져내리지는 않을까 걱정하였다. 하지만 막상 닥치고나니 걱정했던 것 보다 괜찮은 것 같다.(오히려 초반주차들이 더 힘들었던 느낌)
그간 정신적으로나 기술적으로나 단련된 덕분일까 실전 프로젝트 2주차도 무사히 보낼 수 있었던 것 같다.
아직 앞으로 남은 항해 기간이 있기는 하지만 그간 잘 해왔던 것 처럼 이기내보자.
'WIL👨🏫' 카테고리의 다른 글
20220925_WIL(실전프로젝트 5주차 회고) (0) | 2022.09.25 |
---|---|
20220918_WIL(실전 프로젝트 중간발표 회고) (0) | 2022.09.18 |
20220828_WIL(클론코딩 주차 및 실전 프로젝트 1주차 회고) (0) | 2022.08.28 |
20220821_WIL(프로젝트 협업) (0) | 2022.08.21 |
20220814_WIL(Spring Security CORS) (0) | 2022.08.14 |