1. 용어 정의

Client → Server

  1.  페이징
    1. page : 조회할 페이지 번호 (1부터 시작)
    2. size : 한 페이지에 보여줄 상품 개수 (10개로 고정!)
  2. 정렬
    1. sortBy (정렬 항목)
      1. id : Product 테이블의 id
      2. title : 상품명
      3. lprice : 최저가
      4. createdAt : 생성일 (보통 id 와 동일)
    2. isAsc (오름차순?)
      1. true: 오름차순 (asc)
      2. false : 내림차순 (desc)

 

Server → Client

  • number: 조회된 페이지 번호 (0부터 시작)
  • content: 조회된 상품 정보 (배열)
  • size: 한 페이지에 보여줄 상품 개수
  • numberOfElements: 실제 조회된 상품 개수
  • totalElement: 전체 상품 개수 (회원이 등록한 모든 상품의 개수)
  • totalPages: 전체 페이지 수
totalPages = totalElement / size 결과를 소수점 올림
1 / 10 = 0.1 => 총 1 페이지
9 / 10 = 0.9 => 총 1페이지
10 / 10 = 1 => 총 1페이지
11 / 10 => 1.1 => 총 2페이지
  • first: 첫 페이지인지? (boolean)
  • last: 마지막 페이지인지? (boolean)

 

2. 구현

 예제 코드

Controller

import com.sparta.springcore.model.Product;
import com.sparta.springcore.dto.ProductMypriceRequestDto;
import com.sparta.springcore.dto.ProductRequestDto;
import com.sparta.springcore.security.UserDetailsImpl;
import com.sparta.springcore.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import java.sql.SQLException;
import java.util.List;

@RestController // JSON으로 데이터를 주고받음을 선언합니다.
public class ProductController {
    // 멤버 변수 선언
    private final ProductService productService;

    // 생성자: ProductController() 가 생성될 때 호출됨
    @Autowired
    public ProductController(ProductService productService) {
        // 멤버 변수 생성
        this.productService = productService;
    }

//    // 등록된 전체 상품 목록 조회
//    @GetMapping("/api/products")
//    public List<Product> getProducts() throws SQLException {
//        List<Product> products = productService.getProducts();
//        // 응답 보내기
//        return products;
//    }

    // 페이징 처리 안했을 때 로그인한 회원이 등록한 상품들 조회
//    @GetMapping("/api/products")
//    public List<Product> getProducts(@AuthenticationPrincipal UserDetailsImpl userDetails) {
//        Long userId = userDetails.getUser().getId();
//        return productService.getProducts(userId);
//    }

    // 페이징 처리 한 로그인한 회원이 등록한 상품들 조회
    @GetMapping("/api/products")
    public Page<Product> getProducts(
            @RequestParam("page") int page,
            @RequestParam("size") int size,
            @RequestParam("sortBy") String sortBy,
            @RequestParam("isAsc") boolean isAsc,
            @AuthenticationPrincipal UserDetailsImpl userDetails
    ) {
        Long userId = userDetails.getUser().getId();
        page = page - 1;
        return productService.getProducts(userId, page , size, sortBy, isAsc);
    }

    // 신규 상품 등록
    @PostMapping("/api/products")
    public Product createProduct(@RequestBody ProductRequestDto requestDto, @AuthenticationPrincipal UserDetailsImpl userDetails) { //로그인된 사용자의 정보를 가져옴
        // 로그인 되어 있는 ID
        Long userId = userDetails.getUser().getId();

        Product product = productService.createProduct(requestDto, userId);

        return product;
    }

    // 설정 가격 변경
    @PutMapping("/api/products/{id}")
    public Long updateProduct(@PathVariable Long id, @RequestBody ProductMypriceRequestDto requestDto) throws SQLException {
        Product product = productService.updateProduct(id, requestDto);

        return product.getId();
    }

    // 페이징 처리 안 했을 때 (관리자용) 등록된 모든 상품 목록 조회
//    @Secured("ROLE_ADMIN")
//    @GetMapping("/api/admin/products")
//    public List<Product> getAllProducts() {
//        return productService.getAllProducts();
//    }

    // 페이징 처리 했을 때 (관리자용) 등록된 모든 상품 목록 조회
    @Secured("ROLE_ADMIN")
    @GetMapping("/api/admin/products")
    public Page<Product> getAllProducts(
            @RequestParam("page") int page,
            @RequestParam("size") int size,
            @RequestParam("sortBy") String sortBy,
            @RequestParam("isAsc") boolean isAsc
    ) {
        return productService.getAllProducts(page , size, sortBy, isAsc);
    }

}

 

Service

import com.sparta.springcore.dto.ProductMypriceRequestDto;
import com.sparta.springcore.dto.ProductRequestDto;
import com.sparta.springcore.model.Product;
import com.sparta.springcore.repository.ProductRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.List;

//@RequiredArgsConstructor
@Service
public class ProductService {
    // 멤버 변수 선언
    private final ProductRepository productRepository;
    private static final int MIN_PRICE = 100;

    //생성자: ProductService() 가 생성될 때 호출됨
    @Autowired
    public ProductService(ProductRepository productRepository) {
        // 멤버 변수 생성
        this.productRepository = productRepository;
    }

//    등록된 전체 상품 목록 조회 - productController에서 호출
//    public List<Product> getProducts() {
//        // 멤버 변수 사용
//        return productRepository.findAll();
//    }

    // 페이징 없이 회원 ID 로 등록된 모든 상품 조회
//    public List<Product> getProducts(Long userId) {
//        return productRepository.findAllByUserId(userId);
//    }

    // 페이징 처리 된 회원 ID 로 등록된 모든 상품 조회
    public Page<Product> getProducts(Long userId, int page, int size, String sortBy, boolean isAsc) {
        // 페이징 아래 3줄은 템플릿처럼 가져다 쓰면 됨 - Spring Data JPA에서 제공하는 툴에 맞춰져 있음.
        Sort.Direction direction = isAsc ? Sort.Direction.ASC : Sort.Direction.DESC;
        Sort sort = Sort.by(direction, sortBy);
        Pageable pageable = PageRequest.of(page, size, sort);

        return productRepository.findAllByUserId(userId, pageable);
    }

    @Transactional // 메소드 동작이 SQL 쿼리문임을 선언합니다.
    public Product createProduct(ProductRequestDto requestDto, Long userId ) {
        // 요청받은 DTO 로 DB에 저장할 객체 만들기
        Product product = new Product(requestDto, userId);
        productRepository.save(product);
        return product;
    }

    @Transactional // 메소드 동작이 SQL 쿼리문임을 선언합니다.
    public Product updateProduct(Long id, ProductMypriceRequestDto requestDto) {
        Product product = productRepository.findById(id).orElseThrow(
                () -> new NullPointerException("해당 아이디가 존재하지 않습니다.")
        );

        // 변경될 관심 가격이 유효한지 확인합니다.
        int myPrice = requestDto.getMyprice();
        if (myPrice < MIN_PRICE) {
            throw new IllegalArgumentException("유효하지 않은 관심 가격입니다. 최소 " + MIN_PRICE + " 원 이상으로 설정해 주세요.");
        }

        product.updateMyPrice(requestDto);
        return product;
    }

    // 페이징 없이 모든 상품 조회 (관리자용)
//    public List<Product> getAllProducts() {
//        return productRepository.findAll();
//    }

    // 페이징 처리 된 모든 상품 조회 (관리자용)
    public Page<Product> getAllProducts(int page, int size, String sortBy, boolean isAsc) {
        Sort.Direction direction = isAsc ? Sort.Direction.ASC : Sort.Direction.DESC;
        Sort sort = Sort.by(direction, sortBy);
        Pageable pageable = PageRequest.of(page, size, sort);

        return productRepository.findAll(pageable);
    }
}

 

Repository

import com.sparta.springcore.model.Product;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface ProductRepository extends JpaRepository<Product, Long> {
    // 페이징 안한 findAllByUserId
    //    List<Product> findAllByUserId(Long userId);

    // 페이징 처리한 findAllByUserId
    Page<Product> findAllByUserId(Long userId, Pageable pageable);
}

 

 

 

 

 

+ Recent posts