1.상품 검색
컨트롤러
- 먼저, 사용자가 어떠한 항목에 대해 검색할 것인지에 대한 정보를 ProductSearchDto를 만들어 받는다
(사용자가 카테고리에 대한 검색을 하는 지, 상품에 대한 검색을 하는 지 등)
- 그러면 모든 상품목록에다 해당 사용자가 검색한 기준에 맞는 데이터를 조회하여 제공하면 된다.
@GetMapping("/list")
public ResponseEntity<?> productList(Pageable pageable, ProductSearchDto dto){
Page<ProductResDto> productResDtos = productService.findAll(pageable,dto);
return new ResponseEntity<>(productResDtos,HttpStatus.OK);
}
---------------------------------ProductSerachDto 클래스---------------------------
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ProductSearchDto {
private String category;
private String productName;
}
서비스
public Page<ProductResDto> findAll(Pageable pageable, ProductSearchDto searchDto) {
Specification<Product> specification = new Specification<Product>() {
**-->Specification인터페이스는 JPA에서 동적 쿼리를 작성하기 위해 제공되는 인터페이스**
**==>Specification인터페이스를 즉석에서 구현하여 인터페이스의 추상메서드를 구현**
@Override
public Predicate toPredicate(Root<Product> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder){
**-->Predicate클래스는 조건절을 표현하는 객체로 주로 WHERE,HAVING조건을 생성할 때 사용
Predicate 객체는 CriteriaBuilder로 생성된다.
.toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder)에서,
Root<T> root는 쿼리에서 엔티티의 속성에 접근하는 객체, 따라 T에는 엔티티가 들어가야함
CriteriaQuery는 전체 쿼리를 구성하는 객체
CriteriaBuilder criteriaBuilder: 조건,그룹,정렬등을 만들기 위한 객체**
List<Predicate> predicates = new ArrayList<>();
if(searchDto.getCategory() != null){**-->사용자가 카테고리로 검색한다면**
predicates.add(criteriaBuilder.equal(root.get("category"), searchDto.getCategory()));
**-->카테코리 속성이 사용자가 입력한 카테고리(검색 카테고리)과 같음을 가지는 조건객체 생성**
} **-->equal대신에 like,and,or이 올 수 있음
-->여러개의 조건을 표현하기 위해 Predicate를 리스트로 만들고 조건을 넣음**
if(searchDto.getProductName() != null){**-->사용자가 상품이름으로 검색한다면**
predicates.add(criteriaBuilder.like(root.get("name"),"%"+searchDto.getProductName()+"%"));
} **-->name칼럼이 %사용자가 입력한 이름%을 포함하는 조건을 가지는 객체를 만듬**
Predicate[] predicateArr = new Predicate[predicates.size()];
for(int i=0; i< predicates.size(); i++){
predicateArr[i] = predicates.get(i);
}
--> **리스트를 배열로 변환하는 작업(List<Predicate> predicates -> Predicate[] predicateArr**
**-->왜? 리스트를 배열로 바꿀까 여러 조건 객체를 자유롭게 넣기 위해 리스트로 만들어 넣었고.
criteriaBuilder.and()메서드나 criteriaBuilder.or()메서드는 배열을 매개변수로 받기 때문에 변환함**
Predicate predicate = criteriaBuilder.and(predicateArr);
**->여러 조건(Predicate)을 AND연산으로 조합한 최종조건.
여기서는 category = 사용자 입력값과 name like %사용자입력값% 을 and조건으로 묶은것**
return predicate;
}
};
**==> 추상메서드 구현이 끝났고, 이제는 이 어떻게 데이터를 조회할지 조건에 대한 정보가
specification객체에 담겼고 이것을 매개변수로 데이터를 불러오면 된다.
-->우리는 위에서 인터페이스를 즉석에서 구현하여 객체를 만든 익명 클래스 방식을 사용했기때문에
인터페이스지만, specification객체로 사용할 수 있는 것**
Page<Product> productList = productRepository.findAll(specification,pageable);
return productList.map(p->p.fromEntity());
}
}
- Specification 인터페이스의 toPredicate메서드를 익명 클래스 방식으로 구현한다.
- 사용자가 입력한 필터 조건에 따라 Predicate객체들을 생성한다.
- 여러개의 조건 객체들을 and또는 or로 조합해야하는데 이때 매개변수로 배열로 받기 때문에,
- 여러 조건 객체들을 담은 리스트를 배열로 변환한다.
- 3번을 통해 최종 조합된 specification객체를 매개변수로 하여 데이터를 조회한다.
레포지토리
@Repository
public interface ProductRepository extends JpaRepository<Product,Long> {
Page<Product> findAll(Specification<Product> specification, Pageable pageable);
}
2.주문넣기
- 현재 주문과 주문상세 테이블이 서로 1:N관계로 조인된 상태다.
- 따라서 하나의 주문객체가 생기면 여러 개의 주문 상세 객체가 생기도록해야한다.
(예를 들어 청송사과, 대구사과를 한 번에 주문했다면 여기에 대한 주문객체 한개에
청송사과에 대한 상세 주문 한 개와 대구사과에 대한 상세 주문 한개해서 두 개의 상세 주문 객체가 생겨야한다)
컨트롤러
- OrderCreateDto는 Ordering이 아니라 OrderDetail에 해당되는 개념이다.
(OrderCreateDto는 품목과 주문수량을 받음)