개발/백엔드

멀티캠퍼스 [현대 이지웰] 인터페이스 기반 프로젝션이란?

taecostudy76 2025. 11. 24. 20:03

 

인터 페이스 기반 프로젝선(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 객체를 생성합니다.

 

 

이런 식으로 데이터를 사용해서 원하는 기능을 완성할 수 있었습니다.