| 개요
1. Build.Gradle에 QueryDSL과 Jakarta를 함께 주입한다. 2. Config 클래스를 만들어 EntityManager를 생성하고 이를 JpaQueryFactory에 넣어준다. 3. ProductRepositoryCustom과 ProductRepositoryImpl을 만들고, ProductRepostory에서 Custom 인터페이스를 상속한다. |
| 상세
1. Build.Gradle에 QueryDSL를 추가한다.
* Jakarta를 추가하는 이유는, NoClassDefFoundError를 방지하기 위해서이다.
* NoClassDefFoundError는 컴파일 시에는 있었는데 실행 시에는 클래스를 찾을 수 없을 때 발생한다고 한다..
QueryDSL를 사용할 때 자주 나타나는 오류인 것 같다.
// queryDSL
implementation 'com.querydsl:querydsl-jpa'
annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jpa"
// Jakarta
// java.lang.NoClassDefFoundError(javax.annotation.Entity) 발생 대응
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
// java.lang.NoClassDefFoundError(javax.annotation.Generated) 발생 대응
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
2. Config 클래스
- EntityManager를 생성하고, 이를 JPAQueryFactory에 넣어준다.
@Configuration
public class QueryDslConfig {
@PersistenceContext
private EntityManager entityManager;
@Bean
public JPAQueryFactory jpaQueryFactory(){
return new JPAQueryFactory(entityManager);
}
}
3. 서비스 클래스
- 상품명을 통해 조회하는 메소드를 작성한다.
@Service
class XXXService{
/**
* 상품명을 통해 유사 상품 목록 조회
*/
public List<Product> searchByName(String name) {
return productRepository.searchByName(name);
}
}
4. JPQL를 적용할 커스텀 Repository 만들기
(1) Custom interface와 (2) Impl 구현체 클래스 * 이때, 이름은 ProductRepository에 Custom, Impl을 붙여 만들어 주어야 JPA가 인식할 수 있다. |
(1) ProductRepositoryCustom
public interface ProductRepositoryCustom {
List<Product> searchByName(String name);
}
(2) ProductRepositoryImpl
1) JPAQueryFactory를 주입한다.
2) QProduct를 생성한다.
(또는 이것을 private final로 뺄 수도 있다. --> 양식은 QMember, QProduct와 같이 이름을 맞추어야 한다.)
3) 1)의 JpaQueryFactory를 통해 커스텀 쿼리를 작성한다.
@Repository
@RequiredArgsConstructor
public class ProductRepositoryImpl implements ProductRepositoryCustom{
private final JPAQueryFactory queryFactory;
@Override
public List<Product> searchByName(String name){
String search = "%" + name + "%";
QProduct product = QProduct.product;
return queryFactory.selectFrom(product)
.where(product.name.like(search))
.fetch();
}
}
(3) ProductRepository에서 (1)에서 만든 interfacte를 extends한다.
* 참고로에 아래에 적은 @EntityGraph는 지연로딩 때문에 Proxy로 가져올 데이터들을 전부 로딩하기 위해 작업했던 것이었다. 따로 정리할 시간이 없을 것 같아 일단 노트해둔다..
public interface ProductRepository extends JpaRepository<Product, Long>, ProductRepositoryCustom {
@EntityGraph(attributePaths = {"productItems"}, type = EntityGraph.EntityGraphType.LOAD)
Optional<Product> findBySellerIdAndId(Long sellerId, Long id);
@EntityGraph(attributePaths = {"productItems"}, type = EntityGraph.EntityGraphType.LOAD)
Optional<Product> findWithProductItemsById(Long id);
}
5. 컨트롤러를 작성하고 테스트를 해본다.
@RestController
@RequestMapping("/search/product")
@RequiredArgsConstructor
public class SearchController {
private final ProductSearchService productSearchService;
@GetMapping
public ResponseEntity<List<ProductDto>> searchByName(@RequestParam String name) {
return ResponseEntity.ok(productSearchService.searchByName(name).stream()
.map(ProductDto::withoutItemsFrom).collect(Collectors.toList()));
}
}
[참고]
부트캠프 수업 내용 정리
@EntityGraph https://itmoon.tistory.com/77
'Framework > 프로젝트로 스프링 이해하기' 카테고리의 다른 글
[이커머스 프로젝트] 장바구니 구현하기 (RedisTemplate) (0) | 2022.12.15 |
---|---|
[이커머스 프로젝트] 이메일 전송 기능 구현 (Mailgun, Feign) (0) | 2022.11.25 |
[이커머스 프로젝트] Swagger2 적용 (0) | 2022.11.25 |
[이커머스 프로젝트] 멀티 모듈 생성하기 (0) | 2022.11.25 |
[이커머스 프로젝트] API Gateway를 활용한 MSA (Micro Service Architecture) (0) | 2022.11.25 |