QueryDSL로 검색 + 페이징하기

hyun·2022년 12월 3일
0
post-thumbnail
post-custom-banner

이번 포스팅은 QueryDSL 이용해서 목록 페이징 + 검색을 위한 데이터 조회 방법에 대해 다루고자 한다.

queryDSL 사용 설정은 다른 포스팅에서 다룰 예정이다. 그럼 시작해보자고~!


예로 사용자 목록 검색하는 코드를 queryDSL으로 짜보자!

검색 타입, 검색어를 담을 dto 생성

//SearchDto
@Getter
@Setter
public class SearchDto {
    private String searchType;
    private String searchText;
}

검색 결과를 담을 dto 생성

//UserDto
@Getter
@Setter
@RequiredArgsConstructor
public class UserDto {
	@NotNull
    private String id;
    
    @NotNull
    private String name;
    
    @NotNull
    private String tel;
    
    private int level;
    
}

CustomRepository 만들기

springJPA에서 제공하는 함수를 커스텀하거나 직접 쿼리를 짜고 싶을 때 이 방법을 이용한다.

//CustomRepository.java (interface)
public interface CustomRepository {
    Page<SearchResultDto> searchPageList(SearchDto search, Pageable pageable);
}
//CustomRepositoryImpl.java 
@Repository
@RequiredArgsConstructor 
public java CustomRepositoryImpl implements CustomRepository{
	
    QUserEntity user = new QUserEntity();
    
	private final JPAQueryFactory queryFactory;


	@Override
    Page<SearchResultDto> searchPageList(SearchDto search, Pageable pageable){
    	List<SearchResultDto> searchList = queryFactory
        	.select(Projection.contruct(UserDto.class,
            	user.id,
                user.name,
                user.tel)
            .from(user)
            .where(searchCondition(search)
            .orderBy(getOrderSpecifier(pageable, UserEntity.class))
            .orderBy(settingOrder(pageable)
            .offset(pageable.getOffset())   
            .limit(pageable.getPageSize()) 
            .fetch();
            
       Long count = queryFactory
       	.select(user.count())
        .from(user)
        .where(searchCondition(search)
        .fetchOne();
    	
        
        return PageImpl<>(searchList, pageable, count);
        
    }
    
    private BooleanBuilder searchCondition(Search search) {
    	BooleanBuilder booleanBuilder = null;
        
        if(search != null) {
        	if(!search.getSearchType().isEmpty() && !search.getSearchText().isEmpty() ) {
            	switch (search.getSearchType()) {
                	case "id":
                    	booleanBuilder = new BooleanBuilder(user.id.contains(searchText));
                    	break;
                    case "name":
                    	booleanBuilder = new BooleanBuilder(user.name.contains(searchText));
                    	break;
                	case "tel":
                    	booleanBuilder = new BooleanBuilder(user.tel.contains(searchText));
                    	break;
                
                }
            
            }
        
        }
        
        return booleanBuilder;
    
    }
    
    
    
    public OrderSpecifier getOrderSpecifier(Pageable paging, Class entityClass) {
        Sort.Order[] orderList = paging.getSort().stream().toArray(Sort.Order[]::new);

        for(Sort.Order order : orderList) {
            Order direction = order.getDirection().isAscending() ? Order.ASC : Order.DESC;

            PathBuilder pathBuilder = new PathBuilder(entityClass, order.getProperty());

            return new OrderSpecifier(direction, pathBuilder.get(order.getProperty()));
        }

        return null;
    }
    
    
}

getOrderSpecifier 함수는 여러 엔터티에서 사용할 수 있도록 짜봤다. 지금 예제에서는 엔터티 하나여서 한 CustomRepositoryImpl에서 해당 함수를 선언해서 사용해도 되지만 엔터티가 여러개인 경우 매번 같은 함수를 짜지 않도록하고자 했다.

검색 목록 기능을 이용하려면 CustomRepository 인터페이스를 UserRepository에서 상속받은 후 service단에서 호출하여 사용하면 된다.




참고자료

https://jddng.tistory.com/345
https://ttl-blog.tistory.com/216
https://kkambi.tistory.com/193

profile
크리스마스 캐럴을 좋아하는 사람!
post-custom-banner

0개의 댓글