MemberRepository 추가
public interface MemberRepository extends JpaRepository<Member,Long> {
    List<Member> findByUsername(String username);
}
기본적으로 주어지는 JpaRepository에 있는 findAll(), findById() 의 경우 사용하는데 아무 지장 없지만 우리가 만들었던 querydsl 전용 기능인 search() 는 작성할 수없다.

이미지로 이해하는게 빠르기 때문에 이미지를 가져왔다.
사용자 커스텀 인터페이스를 작성해서 내가 추가할 기능이 뭔지 적어준다.
public interface MemberRepositoryCustom {
    List<MemberTeamDto> search(MemberSearchCond cond);
}
적어둔 인터페이스를 구현할 구현부를 따로 만들어준다.
public class MemberRepositoryImpl implements MemberRepositoryCustom {
    private final JPAQueryFactory queryFactory;
    public MemberRepositoryImpl(EntityManager em) {
        this.queryFactory = new JPAQueryFactory(em);
    }
    @Override
    public List<MemberTeamDto> search(MemberSearchCond cond) {
        return queryFactory
                .select(new QMemberTeamDto(
                        member.id,
                        member.username,
                        member.age,
                        team.id,
                        team.name
                ))
                .from(member)
                .leftJoin(member.team, team)
                .where(usernameEq(cond.getUsername()),
                        teamNameEq(cond.getTeamName()),
                        ageGoe(cond.getAgeGoe()),
                        ageLoe(cond.getAgeLoe()))
                .fetch();
    }
    private BooleanExpression usernameEq(String username) {
        return hasText(username) ? member.username.eq(username) : null;
    }
    private BooleanExpression teamNameEq(String teamName) {
        return hasText(teamName) ? team.name.eq(teamName) : null;
    }
    private BooleanExpression ageGoe(Integer ageGoe) {
        return ageGoe == null ? null : member.age.goe(ageGoe);
    }
    private BooleanExpression ageLoe(Integer ageLoe) {
        return ageLoe == null ? null : member.age.loe(ageLoe);
    }
    private BooleanExpression ageBetween(int ageLoe, int ageGoe) {
        return ageGoe(ageGoe).and(ageLoe(ageLoe));
    }
}
public interface MemberRepository extends JpaRepository<Member,Long>,MemberRepositoryCustom {
    List<Member> findByUsername(String username);
}
이렇게 하면 search 함수를 사용할수 있게된다.
@Override
public Page<MemberTeamDto> searchPageComplex(MemberSearchCond cond, Pageable pageable) {
    List<MemberTeamDto> content = queryFactory
            .select(new QMemberTeamDto(
                    member.id,
                    member.username,
                    member.age,
                    team.id,
                    team.name
            ))
            .from(member)
            .leftJoin(member.team, team)
            .where(usernameEq(cond.getUsername()),
                    teamNameEq(cond.getTeamName()),
                    ageGoe(cond.getAgeGoe()),
                    ageLoe(cond.getAgeLoe()))
            .offset(pageable.getOffset())
            .limit(pageable.getPageSize())
            .fetch();
    Long total = queryFactory
            .select(member.count())
            .from(member)
            .leftJoin(member.team, team)
            .where(usernameEq(cond.getUsername()),
                    teamNameEq(cond.getTeamName()),
                    ageGoe(cond.getAgeGoe()),
                    ageLoe(cond.getAgeLoe()))
            .fetchOne();
    return new PageImpl<>(content,pageable,total);
}
pageableExecutionUtils.getPage()를 통한 최적화
Count 쿼리가 생략 가능한 경우 생략해서처리
CountQuery 추가 진행
    @Override
    public Page<MemberTeamDto> searchPageComplex(MemberSearchCond cond, Pageable pageable) {
        List<MemberTeamDto> content = queryFactory
                .select(new QMemberTeamDto(
                        member.id,
                        member.username,
                        member.age,
                        team.id,
                        team.name
                ))
                .from(member)
                .leftJoin(member.team, team)
                .where(usernameEq(cond.getUsername()),
                        teamNameEq(cond.getTeamName()),
                        ageGoe(cond.getAgeGoe()),
                        ageLoe(cond.getAgeLoe()))
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .fetch();
//        Long total = queryFactory
//                .select(member.count())
//                .from(member)
//                .leftJoin(member.team, team)
//                .where(usernameEq(cond.getUsername()),
//                        teamNameEq(cond.getTeamName()),
//                        ageGoe(cond.getAgeGoe()),
//                        ageLoe(cond.getAgeLoe()))
//                .fetchOne();
        //countQuery 추가
        JPAQuery<Member> countQuery = queryFactory
                .select(member)
                .from(member)
                .leftJoin(member.team, team)
                .where(usernameEq(cond.getUsername()),
                        teamNameEq(cond.getTeamName()),
                        ageGoe(cond.getAgeGoe()),
                        ageLoe(cond.getAgeLoe()));
//        return new PageImpl<>(content,pageable,total);
        return PageableExecutionUtils.getPage(content,pageable,countQuery::fetchCount);
    }