자바 웹 프로젝트 #5 repository

Dear·2025년 7월 16일

TIL

목록 보기
63/74

💙 ItemRepository

Spring Data JPA에서 Item 엔티티를 조회하기 위한 ItemRepository 인터페이스

JpaRepository<Item, Long>

기본적인 CRUD, 페이징 등을 제공하는 인터페이스

QuerydslPredicateExecutor<Item>

Querydsl을 통한 동적 쿼리 작성을 가능하게 한다.

동적 쿼리는 조건에 따라 쿼리의 WHERE, ORDER BY 등을 유동적으로 구성하는 것이다.
이름으로 검색할 수도 있고, 가격으로 검색할 수도 있고, 등록일 범위로도 검색할 수 있고 어떤 조건은 선택 안 할 수도 있다.
이럴 경우 고정된 쿼리 하나로 처리하기 어렵기 때문에, 입력된 조건만 가지고 쿼리를 구성하는게 동적 쿼리이다.

@Query (JPQL 쿼리 사용)

JPQL은 엔티티 기준으로 작성된다.

nativeQuery = true

Native SQL 사용하여 동일 조건으로 조회

JPQL과 Native SQL 차이

구분findByItemDetail (JPQL)findByItemDetailByNative (Native SQL)
언어JPQL (JPA Query Language)실제 SQL (DB 의존적)
기준엔티티 클래스 이름, 필드명 기준실제 테이블명, 컬럼명 기준
이식성JPA가 추상화해서 DB 독립적특정 DB에 의존적
예외 발생필드명/엔티티 틀리면 컴파일 에러런타임 오류 (SQL 문법 오류 등)
성능JPA 내부 최적화 가능성능 튜닝 직접 해야 함
사용 예JPA 중심 개발복잡한 SQL, 성능이 중요한 쿼리, DB 특수 기능 필요할 때

💙 ItemRepositoryCustom

Spring Data JPA는 메소드 이름으로 쿼리를 자동 생성하거나 @Query를 통해 쿼리를 지정할 수 있지만 복잡한 조건 검색, 동적 쿼리, 서브쿼리, join 등이 필요한 경우에는 Querydsl이나 직접 쿼리를 조립하는 방식이 필요하다
-> xxxRepositoryCustom + 구현 클래스 사용

💙 ItemRepositoryCustomImPl




코드는 ItemRepositoryCustom 인터페이스를 Querydsl 기반으로 구현한 클래스로
복잡한 조건 검색을 동적 쿼리로 처리하는 사용자 정의 리포지토리 구현체이다.

목적

관리자 페이지용 상품 목록 조회
메인 페이지용 DTO 기반 상품 목록 조회


public ItemRepositoryCustomImpl(EntityManager em) {
    this.queryFactory = new JPAQueryFactory(em);
}

Querydsl의 핵심 객체인 JPAQueryFactory를 생성자에서 초기화하는 부분이다.

  • ItemRepositoryCustomImpl
    사용자 정의 레포지토리 구현체

  • EntityManager em
    JPA의 핵심 객체로 DB 연결과 쿼리 실행을 담당

  • JPAQueryFactory
    Querydsl 쿼리를 만들고 실행하기 위한 객체

  • this.queryFactory = new JPAQueryFactory(em);
    EntityManager를 기반으로 쿼리 팩토리 생성

BooleanExpression

com.querydsl.core.types.dsl.BooleanExpression 클래스
Querydsl에서 조건절(WHERE 조건)을 표현하는 객체

Predicate처럼 동작하며, 조건을 동적으로 조립할 수 있다.
null을 반환하면 Querydsl이 해당 조건을 자동으로 무시한다.

SQLQuerydsl
where item_name like '%pen%'QItem.item.itemName.like("%pen%")BooleanExpression
where price < 1000QItem.item.price.lt(1000)BooleanExpression

searchSellStatusEq()

private BooleanExpression searchSellStatusEq(ItemSellStatus searchSellStatus) {
    return searchSellStatus == null ? null : 
    	QItem.item.itemSellStatus.eq(searchSellStatus);
}

판매 상태(ItemSellStatus)가 null이 아니면, 그 조건을 WHERE절에 넣고 null이면 조건 없이 전체 조회를 하는 메소드

regDtsAfter()

private BooleanExpression regDtsAfter(String searchDateType)

최근 1일, 1주, 1개월, 6개월 등록 상품만 조회한다.
all 또는 null 이면 필터링 X

StringUtils

문자열 처리에 유용한 유틸리티 메소드들을 모아놓은 클래스

String str = " ";
StringUtils.isBlank(str); // true: null, 빈 문자열 "", 공백만 있어도 true
StringUtils.isEmpty(str); // false: null 또는 ""만 true
StringUtils.equals("abc", "ABC"); // false
StringUtils.equalsIgnoreCase("abc", "ABC"); // true
StringUtils.capitalize("hello"); // "Hello"

.after()

Querydsl의 메소드로 "해당 날짜 이후" 조건을 만드는 BooleanExpression

SQL로 표현하면 WHERE reg_time > '기준 시간'

getAdminItemPage

관리자 페이지에서 상품 목록을 검색 조건에따라 페이징 + 동적 검색으로 조회

List<Item> content = queryFactory
    .selectFrom(QItem.item)
    .where(
        regDtsAfter(itemSearchDto.getSearchDateType()),           // 등록일 조건
        searchSellStatusEq(itemSearchDto.getSearchSellStatus()), // 판매 상태 조건
        searchByLike(itemSearchDto.getSearchBy(),                // itemName or createdBy like 검색
                     itemSearchDto.getSearchQuery())
    )
    .orderBy(QItem.item.id.desc())     // id 역순 정렬
    .offset(pageable.getOffset())      // 몇 번째부터 가져올지
    .limit(pageable.getPageSize())     // 몇 개 가져올지
    .fetch();                          // 결과 조회

여러 개의 조건을 ,로 구분했지만, 내부적으로 AND로 연결된다.

getMainItemPage

메인 페이지에 상품 카드 형식으로 보여줄 상품 리스트 조회

💙 전체 Repository 패키지 구성

🤍 회고

Repository 구조를 정리하며, 이해가 부족했던 부분과 헷갈렸던 개념 위주로 정리했다.
기본적인 CRUD는 JpaRepository가 처리하지만, 복잡한 조건 검색을 위해 Querydsl과 사용자 정의 리포지토리 구현체도 함께 사용된다.
특히 BooleanExpression을 활용한 동적 쿼리 구성 방식이 유용하게 쓰인다.

profile
친애하는 개발자

0개의 댓글