🌸인트로


시간이 정말 빠르게 흘러 벌써 3주차가 되버렸습니다. 벚꽃 꽃잎도 서서히 떨어져가는 군요 이번주는 로그인 테스트를 위한 테스트 환경에서의 filter와 그리고 실제 환경에서는 firebase를 활용한 filter를 사용하게 끔 변경하고 테스트 코드 작성을 하고 엔티티 및 QueryDsl을 사용한 개발을 진행하였습니다.

@Profile을 사용하여 디버그와 실제 환경에서 사용되는 Filter 구분하기


로그인 기능을 구현하고 실제 테스트를 하기 위해서는 firebase를 사용하기 힘들어 다른 Filter를 사용하게 되었습니다. 그래서 필요한 것이 테스트를 수행할 때만 다른 필터를 사용하는 것입니다. 이를 위해서 우리는 @Profile 어노테이션을 사용할 수 있습니다. 테스트 상황에서 사용할 필터를 위해 @Profile({"default", "test"}) 이런 식으로 그리고 실제 환경에서 사용하기 위해서 @Profile("prod")을 사용합니다.

QueryDsl 사용해보기


우선 QueryDsl에 관한 지식을 얻기 위해서 아래의 블로그를 참조하였습니다.
https://madplay.github.io/post/introduction-to-querydsl

QueryDsl을 오늘 사용해보면서 느낀 것은 쿼리 마져도 객체지향 방식으로 설계하고 싶은 사람들을 위한 것이구나 라는 것을 느꼈습니다.

QueryDsl을 사용하기 위해서 build.gradle에 아래 코드를 추가하였습니다.

buildscript {
	ext {
		queryDslVersion = "5.0.0"
	}
}
	implementation "com.querydsl:querydsl-core:${queryDslVersion}"
	implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"

	/*
     * `NoClassDefFoundError` 관련 대응으로 필요하다.
     */
	annotationProcessor(
			"jakarta.persistence:jakarta.persistence-api",
			"jakarta.annotation:jakarta.annotation-api",
			"com.querydsl:querydsl-apt:${queryDslVersion}:jpa")

}

sourceSets {
	main {
		java {
			srcDirs = ["$projectDir/src/main/java", "$projectDir/build/generated"]
		}
	}
}

buildscript의 위치는 가장 위에 존재해야 됩니다. 그렇지 않으면 오류가 발생합니다.
queryDsl의 버전을 통일하기 위해서 변수를 사용했습니다.
그리고 queryDsl을 사용하기 위한 config 파일을 추가하였습니다.

package couch.forrest.config;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.querydsl.jpa.impl.JPAQueryFactory;

@Configuration
public class QuerydslConfig {
    @PersistenceContext
    private EntityManager entityManager;

    @Bean
    public JPAQueryFactory jpaQueryFactory() {
        return new JPAQueryFactory(entityManager);
    }
}

이제 필요한 셋업이 되었으니 오늘 작성해본 쿼리를 소개하겠습니다. 그 쿼리는 내가 좋아요를 누른 관광명소 리스트를 가져오는 쿼리입니다. 우선 쿼리dsl에 익숙하지 않기 때문에 먼저 쿼리를 작성해보았습니다.

select 
p.placeId ,
p.name ,
p. image ,
p.adderss ,
p.viewCount ,
p.likeCount ,
p.phone

from love 
left join place as p on love.placeId = p.id
left join member as m on love.memberId = m.id 

where 1=1
and m.memberId = @Id
and p.region1 = @region1
and p.region2 = @region2
and p.category = @category
 

select에서 가저오는 컬럼은 api 명세서를 다시 참고하였습니다. 사실 QueryDsl작성 하는 것이 어려우면 어쩌지 생각하였는데 생각보다 복잡한 쿼리문은 아니여서 그런지 간단하게 되었습니다.
그러면 이제 제가 작성한 QueryDsl을 보여드리겠습니다.

@Repository
@RequiredArgsConstructor
public class MemberRepositoryImpl implements MemberRepositoryCustom {

    private final JPAQueryFactory queryFactory;

    @Override
    public List<Place> findMyFavoritePlaces(Long memberId, String region1, String region2, String category) {
        QMember member = QMember.member;
        QLove love = QLove.love;
        QPlace place = QPlace.place;

        List<Place> result = queryFactory
                .selectFrom(place)
                .rightJoin(love)
                .on(place.id.eq(love.placeId))
                .join(member)
                .on(love.memberId.eq(member.id))
                .where(love.memberId.eq(memberId))
                .fetch();


        return result;
    }
}

엔티티 클래스 이름 앞에 Q가 붙은 것은 QueryDsl 쿼리 타입 객체를 사용해서 쿼리문을 작성해야 되기 때문입니다.
결과가 관광명소 장소 리스트로 나와야되기 때문에 selectFrom을 사용하였습니다. 읽다보면 rightJoin 사용한 것을 확인할 수 있습니다. 결과적으로 내가 좋아요를 누른 장소를 가져와야 되기 때문에 rightJoin을 사용하였습니다. 그리고 QueryDsl의 재밌는 점은 어떤 객체의 값이 무엇과 같다를 나타낼 때 eq()를 사용한다는 점입니다.

🌟자동 테스트를 위한 h2 db 사용하기



테스트를 위한 db 연결을 로컬 환경에서 사용하던 postgreSql url을 그대로 사용하니 CI가 실행되는 도중 오류를 만났습니다. 따라서 이를 h2 데이터베이스를 사용하여 해결 하려고 합니다!

이를 위한 h2 데이터베이스 설정은 아래와 같습니다.

spring.h2.console.enabled=true
spring.session.store-type=jdbc
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect

h2 설정을 postgreSQLDialect로 하였습니다.

테스트가 잘 되니 깃허브에 커밋을 해보았습니다.

허나, 오류는 아직 해결되지 않았습니다. 일단 오류가 해결되는데로 글을 포스팅 해야 겠습니다.

profile
개발에 재미를 느끼며 꾸준히 성장하는 개발자 김종완 입니다.

0개의 댓글