[6.3]

Veloger·2023년 1월 4일
0

3. 상품 관리하기

✨ 상품 리스트를 조회할 수 있는 화면

상품 조회 조건을 설정 후 페이징 기능을 통해 일정 개수만 볼 수 있도록 구현

조회 조건

  • 상품 등록일
  • 상품 판매 기간
  • 상품명 또는 상품 등록자 아이디

Querydsl을 이용해 QDomain 클래스를 생성한다.

✨ 상품 데이터 조회 시 상품 조회 조건을 가지는 Dto

ItemSearchDto
@Getter
@Setter
public class ItemSearchDto {
    /*
    현재 시간과 상품 등록일을 비교해서 조회
    - all : 상품 등록일 전체
    - 1d : 최근 하루 동안 등록된 상품
    - 1w : 최근 일주일 동안 등록된 상품
    - 1m : 최근 한달 동안 등록된 상품
    - 6m : 최근 6개월 동안 등록된 상품
     */
    private String searchDateType;

    // 상품의 판매상태를 기준으로 조회
    private ItemSellStatus searchSellStatus;

    /* 아딴 유형으로 조회할지 선택
       - itemNm
       - createdBy
    */
    private String searchBy;

    // 조회할 검색어 저장할 변수
    private String searchQuery = "";
}

✨ Querydsl을 SpringDataJPA와 함께 사용하기

사용자 정의 레포지터리를 정의한다.

  1. 사용자 정의 인터페이스 작성
  2. 사용자 정의 인터페이스 구현
  3. Spring Data Jpa의 Repository에서 사용자 정의 interface 상속

1. 사용자 정의 인터페이스 작성

-> ItemRepositoryCustom

public interface ItemRepositoryCustom {
    // 상품 조회 조건을 담는 itemSearchDto, 페이징 정보를 담는 Pageable
    // Page<Item> 객체 반환
    Page<Item> getAdminItemPage(ItemSearchDto itemSearchDto, Pageable pageable);
}

2. 사용자 정의 인터페이스 구현

Querydsl에서 BooleanExpression (where절에서 사용할 수 있는 값)을 지원

-> ItemRepositoryCustomImpl

public class ItemRepositoryCustomImpl implements ItemRepositoryCustom {
    // 2. 동적 쿼리를 생성하기 위해 JPAQueryFactory 사용
    private JPAQueryFactory queryFactory;

    // 3.JpaQueryFactory 생성자에 EntityManager 넣음
    public ItemRepositoryCustomImpl(EntityManager em){
        this.queryFactory = new JPAQueryFactory(em);
    }

    // 4. 상품 판매 상태가 전체(null)이면 null 반환 / 아니면 해당 조건의 상품만 조회
    private BooleanExpression searchSellStatusEq(ItemSellStatus searchSellStatus){

        return searchSellStatus == null ? null : QItem.item.itemSellStatus.eq(searchSellStatus);
    }

    // 5. searchDateType을 1m으로 하면, dateTime이 한달 전으로 설정 되고, 최근 한 달 동안 등록된 상품만 등록하도록 설정
    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 QItem.item.regTime.after(dateTime);
    }


    // 6.  searchBy 값이 상품명에 검색어를 포함 혹은 생성자의 아이디에 검색어를 포함하는지 구분 후 조회
    private BooleanExpression searchByLike(String searchBy, String searchQuery){

        if(StringUtils.equals("itemNm", searchBy)){
            return QItem.item.itemNm.like("%" + searchQuery + "%");
        } else if(StringUtils.equals("createdBy", searchBy)){
            return QItem.item.createdBy.like("%" + searchQuery + "%");
        }

        return null;
    }


    @Override
    public Page<Item> getAdminItemPage(ItemSearchDto itemSearchDto, Pageable pageable) {
        // 7. queryFactory로 쿼리를 생성
        QueryResults<Item> results = queryFactory.selectFrom(QItem.item) // selectForm() : 상품 데이터를 조회하기 위해 QItem의 item을 지정
                .where(regDtsAfter(itemSearchDto.getSearchDateType()), // where : BooleanExpression 반환하는 조건문들 넣어줌
                        searchSellStatusEq(itemSearchDto.getSearchSellStatus()),
                        searchByLike(itemSearchDto.getSearchBy(),
                                itemSearchDto.getSearchQuery()))
                .orderBy(QItem.item.id.desc()) // 내림차순
                .offset(pageable.getOffset()) // offset : 데이터를 가지고 올 시작 인덱스 지정
                .limit(pageable.getPageSize()) // limit : 한번에 가져올 최대 개수 지정
                .fetchResults(); // fetchResults : 조회한 리스트 및 전체 개수를 포함하는 QueryResults를 반환 (상품 데이터 리스트 조회, 상품 데이터 전체 개수 조회 실행)
        List<Item> content = results.getResults();
        long total = results.getTotal();
        // 8. 조회 후 데이터를 PageImpl 객체로 반환
        return new PageImpl<>(content, pageable, total);
    }

    // 검색어가 null 아니면 상품명에 해당 검색어가 포함되는 상품을 조회
    private BooleanExpression itemNmLike(String searchQuery){
        return StringUtils.isEmpty(searchQuery) ? null : QItem.item.itemNm.like("%"+searchQuery + "%");
    }

    @Override
    public Page<MainItemDto> getMainItemPage(ItemSearchDto itemSearchDto, Pageable pageable) {
        QItem item = QItem.item;
        QItemImg itemImg = QItemImg.itemImg;

        QueryResults<MainItemDto> results = queryFactory
                .select(
                        new QMainItemDto( // QMainItemDto 생성자에 반환할 값들 입력
                                item.id,
                                item.itemNm,
                                item.itemDetail,
                                itemImg.imgUrl,
                                item.price
                        )
                )
                .from(itemImg)
                .join(itemImg.item, item) // itemImg와 item을 내부 조인
                .where(itemImg.repImgYn.eq("Y")) // 상품 이미지는 대표 상품의 이미지만 가져옴
                .where(itemNmLike(itemSearchDto.getSearchQuery()))
                .orderBy(item.id.desc()) // 내림차순
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .fetchResults();

        List<MainItemDto> content = results.getResults();
        long total = results.getTotal();
        return new PageImpl<>(content, pageable, total);
    }
}

3. Spring Data Jpa의 Repository에서 사용자 정의 interface 상속

마지막으로 ItemRepository 인터페이스에서 ItemRepositoryCustom 상속

✨ 상품 조회 조건, 페이지 저보로 상품 데이터 조회하는 메소드 사용하기

getAdminItemPage()를 ItemService에서 사용해보자

-> ItemService

    @Transactional(readOnly = true)
    public Page<Item> getAdminItemPage(ItemSearchDto itemSearchDto, Pageable pageable){
        return itemRepository.getAdminItemPage(itemSearchDto, pageable);
    }

✨ 컨트롤러에 상품 관리 화면 이동 및 조회한 상품 데이터를 화면에 전달

✨ 상품 관리 목록 뷰를 만들어준다.

4. 메인화면

@QueryProjection으로 DTO 객체로 결과를 받는 방법을 사용
위 어노테이션으로 Item 객체로 받은 값을 DTO 객체로 바로 뽑아 사용

✨ 메인페이지에서 상품 보여줄 DTO

-> MainItemDto

@Getter @Setter
public class MainItemDto {

    private Long id;

    private String itemNm;

    private String itemDetail;

    private String imgUrl;

    private Integer price;

    @QueryProjection // Querydsl로 조회 시 MainItemDto로 바로 받음
    public MainItemDto(Long id, String itemNm, String itemDetail, String imgUrl,Integer price){
        this.id = id;
        this.itemNm = itemNm;
        this.itemDetail = itemDetail;
        this.imgUrl = imgUrl;
        this.price = price;
    }

}

해당 Dto에 대한 QDto 파일을 생성한다.

✨ 메인 페이지에 보여줄 상품 리스트 가져오는 메소드

-> ItemRepositoryCustom

Page<MainItemDto> getMainItemPage(ItemSearchDto itemSearchDto, Pageable pageable);

위 커스텀 레포지토리를 구현하는 구현체를 작성한다.

-> ItemRepositoryCustomImpl

	private BooleanExpression itemNmLike(String searchQuery){
        return StringUtils.isEmpty(searchQuery) ? null : QItem.item.itemNm.like("%" + searchQuery + "%");
    }

    @Override
    public Page<MainItemDto> getMainItemPage(ItemSearchDto itemSearchDto, Pageable pageable) {
        QItem item = QItem.item;
        QItemImg itemImg = QItemImg.itemImg;

        QueryResults<MainItemDto> results = queryFactory
                .select(
                        new QMainItemDto(
                                item.id,
                                item.itemNm,
                                item.itemDetail,
                                itemImg.imgUrl,
                                item.price)
                )
                .from(itemImg)
                .join(itemImg.item, item)
                .where(itemImg.repimgYn.eq("Y"))
                .where(itemNmLike(itemSearchDto.getSearchQuery()))
                .orderBy(item.id.desc())
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .fetch();

		List<MainItemDto> content = results.getResults();
        long total = results.getTotal();

        return new PageImpl<>(content, pageable, total);
    }

✨ 메인 페이지 보여줄 상품 데이터를 조회하는 메소드 추가

✨ 메인 페이지에 상품 보여주는 주소 컨틀롤러에 매핑


5. 상품 상세 페이지

메인 페이지의 상품 클릭 시 상셍 정보를 보여주는 페이지를 구현해보자

✨ 상품 컨트롤러에 상품 상세 페이지 주소 매핑

✨ 상품 상세 페이지 뷰를 생성

0개의 댓글

관련 채용 정보