1. 용어 정의
Client → Server
- 페이징
- page : 조회할 페이지 번호 (1부터 시작)
- size : 한 페이지에 보여줄 상품 개수 (10개로 고정!)
- 정렬
- sortBy (정렬 항목)
- id : Product 테이블의 id
- title : 상품명
- lprice : 최저가
- createdAt : 생성일 (보통 id 와 동일)
- isAsc (오름차순?)
- true: 오름차순 (asc)
- false : 내림차순 (desc)
- sortBy (정렬 항목)
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);
}
'프로그래밍 > SpringBoot' 카테고리의 다른 글
JPA 의 연관관계 (0) | 2022.06.17 |
---|---|
JPA 연관관계를 이용한 폴더 테이블 설계 (0) | 2022.06.17 |
Spring Data JPA (0) | 2022.06.08 |
통합 테스트(Integration Test) - 예제) 관심상품 통합 테스트 (0) | 2022.06.06 |
Edge 케이스를 고려한 단위 테스트 (0) | 2022.06.06 |