Spring Boot + JPA + Querydsl을 활용해
결제 트랜잭션 조회를 위한 동적 조건 검색 API를 구현한 포트폴리오 프로젝트입니다.
실제 결제/운영 도메인을 가정해
조건 검색, 페이징, 정렬, DTO 반환 구조를 중심으로
조회 API 기본기와 Querydsl 활용 패턴을 정리하는 데 초점을 두었습니다.
- 이 프로젝트는 JPA + Querydsl 기반 조회 API를 어떻게 구조화할 것인가를 보여주기 위해 설계했습니다.
TransactionSearchCondition을 기준으로 동적 조건 검색 / 페이징 / 정렬 / DTO 반환 흐름을 분리했습니다.- Spring Data JPA 기본 Repository와 Querydsl 전용 Query Repository를 나눠 조회 책임을 명확하게 분리했습니다.
flowchart TD
A[Client Request] --> B[TransactionController]
B --> C[TransactionService]
C --> D[TransactionQueryRepository]
D --> E[BooleanBuilder Dynamic Conditions]
E --> F[Querydsl Search]
F --> G[DTO Mapping]
G --> H[Page Response]
GET /transactions/search?storeId=1&status=APPROVED&page=0&size=20{
"storeId": 1,
"method": "CARD",
"status": "APPROVED",
"from": "2024-01-01T00:00:00+09:00",
"to": "2024-01-31T23:59:59+09:00",
"minAmount": 1000,
"maxAmount": 50000,
"keyword": "ORDER"
}{
"content": [
{
"txId": "TX202401010001",
"storeId": 1,
"terminalId": 3,
"amount": 15000,
"currency": "KRW",
"method": "CARD",
"status": "APPROVED",
"buyerId": "user_123",
"description": "POS 결제",
"requestedAt": "2024-01-10T10:15:30+09:00",
"approvedAt": "2024-01-10T10:15:35+09:00"
}
],
"pageable": {
"pageNumber": 0,
"pageSize": 20
},
"totalElements": 1,
"totalPages": 1
}- 조회 API는 단순 조회보다 조건 조합과 반환 구조를 어떻게 관리할 것인가가 중요합니다.
- Querydsl을 활용해 조건이 있는 항목만 동적으로 적용하는 검색 구조를 구현했습니다.
- 조회 전용 책임을 분리해 확장 가능한 Custom Repository 패턴을 정리했습니다.
운영 환경의 조회 API는 단순 단건 조회보다
다양한 검색 조건을 조합하고, 결과를 페이지 단위로 반환하며, 정렬 기준까지 일관되게 제공하는 구조가 중요합니다.
특히 결제/운영 도메인에서는 아래와 같은 요구가 자주 발생합니다.
- store, method, status, 기간, 금액 범위를 조합한 검색
- txId, buyerId, description 기준 키워드 검색
- 조건이 없는 항목은 제외한 동적 검색
- 페이징과 정렬을 포함한 운영 친화적인 응답 구조
- Entity 직접 노출이 아닌 DTO 기준 반환
이 프로젝트는 이러한 요구를 기준으로,
Querydsl 기반 조건 검색 API를 명확한 계층 구조로 정리하는 것을 목표로 했습니다.
TransactionSearchCondition DTO를 통해 검색 조건을 전달하고,
BooleanBuilder를 사용해 값이 있는 조건만 동적으로 적용하도록 구성했습니다.
핵심은 조건을 많이 넣는 것이 아니라,
조건 조합이 늘어나도 조회 코드가 무너지지 않도록 만드는 것입니다.
Spring Data JPA 기본 Repository와 Querydsl 전용 Repository를 분리했습니다.
- 기본 Repository: 저장 / 기본 조회
- Query Repository: 조건 검색 / 조회 전용 로직
- Service 계층: 요청 해석과 흐름 조정
이를 통해 조회 전용 로직을 한 곳에 모아
유지보수성과 확장성을 높이도록 구성했습니다.
운영성 조회 API에서 자주 필요한 페이징과 정렬을 기본 구조에 포함했습니다.
Pageable기반 페이지 처리- 기본 정렬:
requestedAt DESC - Page 응답 구조 유지
즉, 이 프로젝트는 단순 Querydsl 예제가 아니라
실무형 조회 API 패턴을 정리한 프로젝트에 가깝습니다.
Entity를 직접 반환하지 않고
조회 전용 DTO로 응답을 구성해 API 계약을 분리했습니다.
- 외부 응답 구조 고정
- 내부 Entity 변경 영향 최소화
- 조회 목적에 맞는 필드만 노출
com.github.gseobi.kpos
├─ config
│ └─ QuerydslConfig.java
├─ controller
│ ├─ StoreController.java
│ └─ TransactionController.java
├─ domain
│ ├─ enumtype
│ │ ├─ PaymentMethod.java
│ │ └─ TxStatus.java
│ ├─ BaseTimeEntity.java
│ ├─ PaymentTransaction.java
│ ├─ Store.java
│ └─ Terminal.java
├─ dto
│ ├─ store
│ │ ├─ StoreCreateRequest.java
│ │ └─ StoreResponse.java
│ └─ tx
│ ├─ TransactionCreateRequest.java
│ ├─ TransactionResponse.java
│ └─ TransactionSearchCondition.java
├─ repository
│ ├─ query
│ │ ├─ TransactionQueryRepository.java
│ │ ├─ TransactionQueryRepositoryBean.java
│ │ └─ TransactionQueryRepositoryImpl.java
│ ├─ StoreRepository.java
│ ├─ TerminalRepository.java
│ └─ TransactionRepository.java
├─ service
│ ├─ StoreService.java
│ └─ TransactionService.java
└─ KposApplication.java
GET /transactions/search
- Java 17 + Spring Boot 3.x: 계층형 API 구조와 기본 웹 애플리케이션 구성을 명확하게 가져가기 적합했습니다.
- Spring Data JPA: 기본 영속성과 Repository 패턴을 간결하게 구성하기 위해 사용했습니다.
- Querydsl: 동적 조건 검색을 타입 세이프하게 작성하고 조회 의도를 분명하게 표현하기 위해 사용했습니다.
- Pageable / PageImpl: 운영성 조회 API에서 필요한 페이징 구조를 일관되게 제공하기 위해 사용했습니다.
- H2: 로컬 개발 및 테스트용 경량 DB로 사용했습니다.
- Logback: API 흐름과 검색 조건을 로그 기준으로 확인하기 위해 사용했습니다.
- Java 17
- Spring Boot 3.x
- Spring Data JPA
- Querydsl
- Pageable / PageImpl
- H2
- Logback
- 잘못된 enum 값이나 조건 조합은 Controller / Service 계층에서 사전 검증 가능하도록 구성했습니다.
- 검색 조건이 비어 있는 경우에도 기본 조회 흐름이 동작하도록 고려했습니다.
- 조회 결과가 없더라도 Page 응답 구조를 유지하도록 설계했습니다.
이 구조는 이후 다음과 같은 방향으로 확장할 수 있습니다.
- 복합 정렬 조건 추가
- Store / Terminal / 정산 도메인 확장
- 조회 전용 Projection 최적화
- 운영성 필터 조건 추가
- 테스트 코드 및 API 문서 보강
핵심은 단순 검색 API 구현보다,
조건 검색이 늘어나도 일관된 조회 구조를 유지하는 것입니다.
이 프로젝트는 Querydsl 조건 검색, Custom Repository 분리, 페이징 응답 구조처럼
실무에서 자주 사용하는 조회 API 패턴을 포트폴리오용으로 정리한 보조 프로젝트입니다.
대표 포트폴리오 프로젝트들처럼 운영형 장애 대응이나 복구 흐름보다는,
JPA / Querydsl 기반 조회 API 기본기를 보여주는 데 목적이 있습니다.