흰 스타렉스에서 내가 내리지

[Querydsl] 동적 쿼리, 성능 최적화 조회 - Builder 사용 + API 컨트롤러 본문

JPA

[Querydsl] 동적 쿼리, 성능 최적화 조회 - Builder 사용 + API 컨트롤러

주씨. 2024. 4. 20. 19:39
728x90

# 회원 검색 조건 클래스

@Data
public class MemberSearchCondition {
    //회원명, 팀명, 나이(ageGoe, ageLoe)

    private String username;
    private String teamName;
    private Integer ageGoe;
    private Integer ageLoe;
}

 

 

# 동적 쿼리 - Builder 사용

// Builder 사용
// 회원명, 팀명, 나이 (ageGoe, ageLoe)
public List<MemberTeamDto> searchByBuilder(MemberSearchCondition condition){
    BooleanBuilder builder = new BooleanBuilder();

    if(StringUtils.hasText(condition.getUsername())){
        builder.and(member.username.eq(condition.getUsername()));
    }
    if(StringUtils.hasText(condition.getTeamName())){
        builder.and(team.name.eq(condition.getTeamName()));
    }
    if(condition.getAgeGoe() != null){
        builder.and(member.age.goe(condition.getAgeGoe()));
    }
    if(condition.getAgeLoe() != null){
        builder.and(member.age.loe(condition.getAgeLoe()));
    }

    return queryFactory
            .select(new QMemberTeamDto(
                    member.id,
                    member.username,
                    member.age,
                    team.id,
                    team.name))
            .from(member)
            .leftJoin(member.team, team)
            .where(builder)
            .fetch();
}

 

 

# 조회 테스트

@Test
public void searchTest(){
	// em 등록...

    MemberSearchCondition condition = new MemberSearchCondition();
    condition.setAgeGoe(35);
    condition.setAgeLoe(40);
    condition.setTeamName("teamB");

    List<MemberTeamDto> result = memberJpaRepository.searchByBuilder(condition);

    assertThat(result).extracting("username").containsExactly("member4");
}

 

 

 

# Where 절 파라미터 사용

//회원명, 팀명, 나이(ageGoe, ageLoe)
public List<MemberTeamDto> search(MemberSearchCondition condition) {
    return queryFactory
            .select(new QMemberTeamDto(
                    member.id,
                    member.username,
                    member.age,
                    team.id,
                    team.name))
            .from(member)
            .leftJoin(member.team, team)
            .where(usernameEq(condition.getUsername()),
                    teamNameEq(condition.getTeamName()),
                    ageGoe(condition.getAgeGoe()),
                    ageLoe(condition.getAgeLoe()))
            .fetch();
}
private BooleanExpression usernameEq(String username) {
    return StringUtils.hasText(username) ? member.username.eq(username) : null;
}
private BooleanExpression teamNameEq(String teamName) {
    return StringUtils.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);
}

 

 

  • BooleanExpression 메서드를 만들면, 조건 재사용이 가능하다
  • 혹은 체인 메서드를 이용하여 다앙향 조건 메서드를 만들어낼 수 있다.
private BooleanExpression ageBetween(int ageLoe, int ageGoe){
    return ageGoe(ageGoe).and(ageLoe(ageLoe));
}
private BooleanExpression isValid(...){
    ...
}

 

 

 

# 조회 API 컨트롤러

@RestController
@RequiredArgsConstructor
public class MemberController {
    private final MemberJpaRepository memberJpaRepository;

    @GetMapping("/v1/members")
    public List<MemberTeamDto> searchMemberV1(MemberSearchCondition condition) {
        return memberJpaRepository.search(condition);
    }
}

 

  • Condition 객체를 컨트롤러 파라미터로 받으면, 쿼리로 데이터를 받아올 수 있다.

 

http://localhost:8080/v1/members?teamName=teamB