인터 페이스 기반 프로젝선(Interface-Based Projecttion)
Spring Data JPA에서 엔티티의 전체가 아닌 일부 필드만 선택적으로 조회할 수 있게 해주는 기능입니다.
리뷰를 작성하는 사용자와 다른 사용자가 비슷한 피부 타입을 가지고 있을 때 리뷰를 분석하여 어떤 태그를 사용했는지를 통해
다른 사용자가 상품구매를 하기 전 판단을 할 수 있게 하는 기능을 만들고자 했습니다.
Tag에 모든 엔티티를 조회하지 않고 필요한 필드만 조회할 수 있는 인터페이스 기반 프로젝션을 사용하고자 했습니다.
인터피에스 기반 프로젝션이란?
기본 개념
- 일반적으로 JPA Repository 쿼리는 엔티티 전체를 조회합니다.
- 하지만 인터페이스 기반 프로젝션을 사용하게 되면, 원하는 필드만 SELECT 하도록 JPA가 쿼리를 최적하 하여 필요 없는
데이터를 제외하고 경량 DTO 역할을 하게 만듭니다.

이 Interface는 Repository 안에서 선언 한 것이며 따로 만든 Tag 관련 Entity나 DTO 하고는 전혀 상관없는 코드입니다.
프로젝션 인터페이스는 JPA가 쿼리 결과를 매핑해주는 임시 DTO 역할(조회 전용, 일시적 데이터 받기)만 합니다.

@Query 인터페이스를 사용하여 JPA가 기본으로 제공하는 쿼리문이 아닌 직접 쿼리문을 작성할 수 있는 어노테이션입니다.
특정 상품과 특정 피부타입인 리뷰들의 태그별 개수를 구하는 쿼리문을 작성항 것입니다.
쿼리문을 작성할 때 주의해야 하는 점은 인터페이스 프로젝션을 미리 만들어 놨기 때문에 필드 이름과 SELECT 별칭은 일치해야 합니다.
JPA가 SQL 실행을 하고 결과를 인터페이스에 맞춰 프록시 객체로 생성하여 반환하게 됩니다.
프락시 객체란?
- 실제 엔티티의 "가짜 대리 객체"로 실제 데이터를 즉시 메모리에 올리지 않고, 필요할 때 데이터베이스에서 객체를 조회하는 방식입니다.
위 코드에서 보면 TagStatSimple 타입으로 프록시가 생성이 됩니다.
TagStatSimple은 직접 구현한 실체 클래스가 아니라 동적으로 getter만 존재하는 임시 익명 프록시 객체를 만들어 각 row의 값을 할당합니다.
개발자는 .getTagName, getCount(), getTagStatus를 부르면 프록시 객체가 내부에 저장된 값을 그대로 돌려줍니다.

특정 사용자가 쓴 총 리뷰 수를 구해서 백분율을 계산을 할 때 분모를 사용하고자 했습니다.
리뷰 개수를 조회하는데 있어서 혹시 모를 중복 방지를 위해 DISTINCT를 걸었습니다.
JOIN을 통해서 원하는 테이블까지 경로를 만들고 oi.product.prdNo = :prdNo 를 통해서 리뷰가 달린 주문 항목의 상품 번호가
현재 상품 번호와 같은 경우 와 s.skinType = :skinType 회원이 설정한 skinType이 조건과 동일한 경우를
Where 절로 하여 분모를 정했습니다.

현재 로그인한 사용자의 피부 타입을 가져오기 위해서 userSkin에 로그인한 사용자를 넣어주고, 그 사용자의 피부타입을 가져옵니다.
Repository에서 만든 총 리뷰 수를 구하는 메서드를 불러 값을 넣어주고, 만약 리뷰수가 없다면 빈 값을 넣어 주는 작업을 진행했습니다.

분자 계산에서는 상위 3개의 태그를 가져올 예정이기 때문에 Pageable를 사용했습니다.
Pageable이란 페이징을 위한 설정 정보를 담는 인터페이스 입니다.
PageRequest.of() 메서드를 사용해서 첫 번째부터 3개 데이터 만들 가져오도록 Pageable를 구현합니다.

여기서 Proejction을 매핑하여 TagStat DTO로 변환하는 작업을 합니다.
percantage에 각 태그마다의 빈도수를 백분율로 변환하고 dto 객체를 생성합니다.

이런 식으로 데이터를 사용해서 원하는 기능을 완성할 수 있었습니다.
'개발 > 백엔드' 카테고리의 다른 글
| [JPA/Spring] 엔티티 설계의 정석: @NoArgsConstructor(access = AccessLevel.PROTECTED)와 @Builder의 조화 (0) | 2026.03.11 |
|---|---|
| 멀티캠퍼스 [현대 이지웰] Spring Boot 활용하여 기본 CRUD 기능 구현 (0) | 2025.12.01 |
| 멀티캠퍼스 [현대 이지웰] Spring 어노테이션 기록하기 (0) | 2025.11.18 |
| 멀티캠퍼스 [현대 이지웰] Spring Security Login에 대해서 알아보자! (0) | 2025.10.21 |
| 멀티캠퍼스 [현대 이지웰] Spring에서는 로그인과 회원가입을 어떻게 사용할 수 있을까? (0) | 2025.10.13 |