본문 바로가기
개발 관련 학습 및 문제해결

자바 스프링 페이지네이션 구현 풀스택[20221010 TIL]

by 날파리1 2022. 10. 10.

잘 안풀렸던 페이지네이션을 정리할겸 티아이엘을 써보자.

 

쇼핑몰에 업로드할 모든 제품군들을 8개씩으로 분류해 페이지네이션 해주는 상황

 

일단 JpaRepository에서 타입을 Page로 받아준다.

public interface ProductRepository extends JpaRepository<Product, Long> {
  Page<Product> findAll(Pageable pageable);

  Optional<Product> findById(Long productId);
}

서비스 영역에서 마찬가지로 타입을 Page로 받아주고 

sort는 분류를 원하는 타입명(나는 생성일 순으로 하고싶어 createdAt을 넣었다.)을 넣어주고 리턴한다.

 

그리고 총 페이지수를 잡아줘야하므로 findAll 한 것을 totalPages로 바꿔준다.

@Service
@Transactional
public class ProductService {

  private ProductRepository productRepository;
  private Pageable pageable;

  public ProductService(ProductRepository productRepository) {
    this.productRepository = productRepository;
  }

  public Page<Product> list(int page) {
    Sort sort = Sort.by("createdAt").descending();
     pageable = PageRequest.of(page - 1, 8, sort);
    return productRepository.findAll(pageable);
  }

  public int pages() {
    return productRepository.findAll(pageable).getTotalPages();
  }
}

ProductsController

@RestController
public class ProductsController {
  private ProductService productService;

  public ProductsController(ProductService productService) {
    this.productService = productService;
  }

  @GetMapping("products")
  @ResponseStatus(HttpStatus.OK)
  public ProductsDto list(
      @RequestParam(required = false, defaultValue = "1") Integer page
  ) {
    List<ProductDto> productDtos =
        productService.list(page)
            .stream()
            .map(product -> product.toDto())
            .collect(Collectors.toList());

    int pageNumber = productService.pages();

    return new ProductsDto(productDtos, pageNumber);
  }
}

리퀘스트 파람으로 page번호를 매개변수로 받아준후 

 

스트림으로 Dto 리스트로 변환

 

그리고 변환해준 리스트와 , 아까 총 페이지수를 계산해준 pageNumber까지 받아서 return 해준다.

 

DTO

public class ProductsDto {
  private List<ProductDto> products;
  private int pageNumber;

  public ProductsDto() {
  }

  public ProductsDto(List<ProductDto> products, int pageNumber) {

    this.products = products;
    this.pageNumber = pageNumber;
  }

  public List<ProductDto> getProducts() {
    return products;
  }

  public int getPageNumber() {
    return pageNumber;
  }
}

그리고 리턴해주는 ProductsDto 타입에 int PageNumber 를 같이 받아주고 게터와 생성자를 만들어준다.

 

그럼 백엔드는 일단 완성

 

 

React

ApiService

에서

async fetchProducts() {
const url = `${baseUrl}/products`;
const { data } = await axios.get(url);

const { products, pageNumber } = data;

return { products, pageNumber };
}
 
products 라는 리스트와 페이지 넘버를 같이 받아와줌.
 
 
ProductsStore에서 
 
pageNumbers와 products 를 모두 배열로 지정해주고(pageNumbers 철자 주의!)
export default class ProductsStore {
constructor() {
this.listeners = new Set();
this.pageNumbers = [];
this.products = [];
}


async fetchProducts() {
this.products = [];
this.publish();

const { products, pageNumber } = await apiService.fetchProducts();

this.products = products;

this.pageNumbers = [...Array(pageNumber)].map((number, index) => index + 1);

this.publish();
}
 

api 백엔드 서버에서 받아오는 pageNumber를 맵핑을 통해서 인덱에 1씩 더한 값으로 배열을 만들어줌.

 

Productspage

export default function ProductsPage() {
const productsStore = useProductsStore();
useEffect(() => {
productsStore.fetchProducts();
}, []);

const navigate = useNavigate();

const { products, pageNumbers } = productsStore;

const handleClickPageButton = (number) => {
productsStore.changePageNumber(number);
navigate(`/products?page=${number}`);
};
return (
<Products
products={products}
pageNumbers={pageNumbers}
onClickPageButton={handleClickPageButton}
/>
);
}

페이지 버튼을 클릭하면 이동할 함수를 아래와 같이 만들어주자!

 

apiservice에서 

async changePageNumber(number) {
const url = `${baseUrl}/products`;

const { data } = await axios.get(url, {
params: {
page: number,
},
});
return data.products;
}
 

store에서

async changePageNumber(number) {
this.products = [];
this.products = await apiService.changePageNumber(number);
this.publish();
}
 

 

products 컴포넌트에서

<nav>
<ul>
{pageNumbers.map((number) => (
<li key={number}>
<button
type="button"
onClick={() => handleClickPageButton(number)}
>
{number}
</button>
</li>
))}
</ul>
</nav>
 
 
일단 요기까지...
 
복습하고 다시 정리하자!

 

댓글