이 내용은 스프링 부트 쇼핑몰 프로젝트 with JPA 책을 학습한 내용입니다.
1. Qdomain 생성
- Querydsl을 사용하기 위해서 Qdomain 생성
- dependencies 부분 추가
- build.gradle - [other] - [compileQuerydsl]
2. 상품 조회 조건 DTO
- 상품 조회 조건
- 상품 등록일
- 상품 판매 상태
- 상품명 또는 상품 등록자 아이디
- 상품 조회 조건을 담을 ItemSearchDto 클래스 생성
import kr.spring.item.constant.ItemSellStatus;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class ItemSearchDto {
private String searchDateType;
private ItemSellStatus searchSellStatus;
private String searchBy; // 방법(사람이름인지 상품 이름인지)
private String searchQuery; // 검색
}
3. Querydsl & Spring Data Jpa
- Querydsl과 Spring Data Jpa를 함께 사용하기 위해서는 사용자 정의 리포지토리가 필요함② 사용자 정의 인터페이스 구현
- ③ Spring Data Jpa 리포지토리에서 사용자 정의 인터페이스 상속
- ① 사용자 정의 인터페이스 작성
4. 사용자 정의 인터페이스 작성
- 상품 조회 조건을 담고 있는 itemSearchDto 객체와 페이징 정보를 담고 있는 pageable 객체를 파라미터로 받고, Page<Item> 객체를 반환
import kr.spring.item.dto.ItemMainDto;
import kr.spring.item.dto.ItemSearchDto;
import kr.spring.item.entity.Item;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
public interface ItemRepositoryCustom {
// 몇 번째 페이지부터 몇 개를 가져올 건지
Page<Item> getAdminItemPage(ItemSearchDto itemSearchDto, Pageable pageable);
}
5. 사용자 정의 인터페이스 구현
- 클래스명 끝에 "Impl" 를 붙여야 정상적으로 동작함
- 클래스 생성 및 사용자 정의 인터페이스 구현
public class ItemRepositoryCustomImpl implements ItemRepositoryCustom {
private JPAQueryFactory queryFactory;
public ItemRepositoryCustomImpl(EntityManager em) {
queryFactory = new JPAQueryFactory(em);
}
}
- BooleanExpression 을 통해 where 절에 적용될 조회 조건을 생성
- BooleanExpresiion 값이 null 이면 해당 조회 조건을 사용하지 않겠다는 의미 (=all)
- 상품 등록일 조건
// ItemRepositoryCustomImpl
private BooleanExpression regDtsAfter(String searchDateType) {
LocalDateTime dateTime = LocalDateTime.now();
if(StringUtils.equals("all", searchDateType) || searchDateType == null) {
return null;
} else if(StringUtils.equals("1d", searchDateType)) {
dateTime = dateTime.minusDays(1);
} else if(StringUtils.equals("1w", searchDateType)) {
dateTime = dateTime.minusWeeks(1);
} else if(StringUtils.equals("1m", searchDateType)) {
dateTime = dateTime.minusMonths(1);
} else if(StringUtils.equals("6m", searchDateType)) {
dateTime = dateTime.minusMonths(6);
}
return item.regTime.after(dateTime);
}
- 상품 판매 상태 조건
private BooleanExpression searchSellStatusEq(ItemSellStatus searchSellStatus) {
return searchSellStatus == null ? null : item.itemSellStatus.eq(searchSellStatus);
}
- 상품명 또는 상품 등록자 아이디 조건
private BooleanExpression searchByLike(String searchBy, String searchQuery) {
// 방법에 따라 다름
// 상품명에 따라 검색
if(StringUtils.equals("itemNm", searchBy)) {
return item.itemNm.like("%" + searchQuery + "%");
}
// 작성자에 따라 검색
else if (StringUtils.equals("createdBy", searchBy)) {
return item.createdBy.like("%" + searchQuery + "%");
}
return null;
}
- QueryFactory 를 이용하여 Querydsl 쿼리문 생성offset : 데이터를 가지고 올 시작 인덱스를 지정limit : 한 번에 가지고 올 최대 개수를 지정
- fetchResult() 메소드를 이용하여 조회 대상 리스트 및 전체 개수를 포함하는 QueryResults 객체 반환
- Page 클래스의 구현체인 PageImpl 객체로 반환
@Override
public Page<Item> getAdminItemPage(ItemSearchDto itemSearchDto, Pageable pageable) {
List<Item> content = queryFactory
.selectFrom(item)
.where(regDtsAfter(itemSearchDto.getSearchDateType()),
searchSellStatusEq(itemSearchDto.getSearchSellStatus()),
// 어떤 방법으로 어떤 디비를 던질 것인지
searchByLike(itemSearchDto.getSearchBy(), itemSearchDto.getSearchQuery()))
.orderBy(item.id.desc())
.offset(pageable.getOffset()) // 시작할 위치
.limit(pageable.getPageSize()) // 가져올 갯수
.fetch(); // 리스트를 가져옴
long total = queryFactory.select(Wildcard.count).from(item)
.where(regDtsAfter(itemSearchDto.getSearchDateType()),
searchSellStatusEq(itemSearchDto.getSearchSellStatus()),
searchByLike(itemSearchDto.getSearchBy(), itemSearchDto.getSearchQuery()))
.fetchOne();
return new PageImpl<>(content, pageable, total);
}
6. 사용자 정의 인터페이스 상속
- JpaRepository 를 구현한 ItemRepository 에서 ItemRepositoryCustom을 상속
public interface ItemRepository extends JpaRepository<Item, Long>,
QuerydslPredicateExecutor<Item>, ItemRepositoryCustom {
7. ItemService 수정
- 위에서 만든 사용자 정의 조회문(=메소드)을 수행하는 로직 추가
- 조회 기능이므로 읽기 전용 상태로 지정
// 정보 불러오기
public Page<Item> getAdminItemPage(ItemSearchDto itemSearchDto, Pageable pageable) {
return itemRepository.getAdminItemPage(itemSearchDto, pageable);
}
8. ItemController 수정
- Mapping 파라미터로 객체를 지정하면(ItemSearchDto) 자동으로 new 객체 생성
- URL을 통해 페이지 번호가 넘어오는 경우 @PathVariable로 변수 값 매핑
// 요청 URL에 페이지 번호가 없는 경우와 있는 경우 2가지를 매핑
@GetMapping({"/admin/items", "/admin/items/{page}"})
public String itemList(ItemSearchDto itemSearchDto, Model model,
@PathVariable("page")Optional<Integer> page) {
// 페이지의 내용이 있으면 페이지 번호(page.get())을 가져오고 없으면 0으로 가져옴
Pageable pageable = PageRequest.of(page.isPresent() ? page.get() : 0, 10); // 한페이지에 표시되는 상품의 수를 관리(현재는 3개씩 보여줌)
Page<Item> items = itemService.getAdminItemPage(itemSearchDto, pageable);
model.addAttribute("items", items);
// 검색어 다시 받아오기
model.addAttribute("itemSearchDto", itemSearchDto);
// View 단에서 하단에 보여줄 페이지 번호의 최대 개수 설정
model.addAttribute("maxPage", 5);
return "item/itemList";
}
'Web & Android > 스프링 부트 쇼핑몰 프로젝트 with JPA' 카테고리의 다른 글
[스프링 부트 쇼핑몰 프로젝트 with JPA] 9. 메인화면 (0) | 2023.10.16 |
---|---|
[스프링 부트 쇼핑몰 프로젝트 with JPA] 8-2. [상품 관리] 상품 목록 페이지 (0) | 2023.10.16 |
[스프링 부트 쇼핑몰 프로젝트 with JPA] 7. 상품 수정 (0) | 2023.10.16 |
[스프링 부트 쇼핑몰 프로젝트 with JPA] 6-2. [상품 등록] Controller, Service, Repository (0) | 2023.10.15 |
[스프링 부트 쇼핑몰 프로젝트 with JPA] 6-1. [상품 등록] Entity, DTO, View (0) | 2023.10.15 |