DevKim
[ Webtooniverse ] 웹툰 상세 페이지 개발 - 비슷한 장르 웹툰 추천 ( feat. Querydsl ) 본문
[ Webtooniverse ] 웹툰 상세 페이지 개발 - 비슷한 장르 웹툰 추천 ( feat. Querydsl )
on_doing 2021. 8. 3. 00:07[ 요구 사항 분석 ]
- 현재 페이지의 웹툰과 비슷한 장르의 웹툰들의 정보를 랜덤으로 뿌려준다.
[Querydsl 세팅 ]
매번 2개의 Repository를 의존성으로 받지 않기 위해서,
Data Jpa에서는 Custom Repository를 JpaRepository 상속 클래스에서 사용할 수 있게끔 지원한다.
사실 기본 CRUD도 Querydsl만을 사용하여, 상속/구현 없는 Repository를 만들어 사용할 수 있지만
빠르게 개발하기 위해 기본 CRUD는 JpaRepository의 도움을 받아서 코드를 작성하였다.
리팩토링 단계에서 Querydsl만을 가져가는 것에 대해 고려해보기로하자.
1. 어느 곳에서나 JPAQueryFactory를 주입받아 Querydsl을 사용할 수 있게끔 Config 파일을 하나 생성한다.
@Configuration
public class QuerydslConfiguration {
@PersistenceContext
private EntityManager entityManager;
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(entityManager);
}
}
2. 이어서 Custom을 생성해주고,
public interface WebtoonRepositoryCustom {
List<Webtoon> findSimilarWebtoonByGenre(String genre,Webtoon webtoon);
}
3. 쿼리문을 작성한다.
현재 웹툰의 장르와 같은 웹툰 중에서, random으로 웹툰을 10개씩 뽑아준다.
이때 현재 웹툰과 같은 웹툰을 추천해주면 안되기 때문에, ne 조건에 현재 웹툰을 넣어주었다.
@RequiredArgsConstructor
public class WebtoonRepositoryImpl implements WebtoonRepositoryCustom{
private final JPAQueryFactory queryFactory;
@Override
public List<Webtoon> findSimilarWebtoonByGenre(String genre,Webtoon webtoon) {
QWebtoon w = new QWebtoon("w");
QWebtoonGenre wg = new QWebtoonGenre("wg");
return queryFactory
.select(wg.webtoon)
.from(wg)
.join(wg.genre)
.on(wg.genre.genreType.eq(genre),wg.webtoon.ne(webtoon))
.orderBy(NumberExpression.random().asc())
.limit(10)
.fetch();
}
}
[ 비즈니스 로직 ]
네이버 웹툰의 장르는 다음과 같다.
- 에피소드,옴니버스,스토리 라는 다소 포괄적인 장르와
- 일상,개그,판타지.. 등 세부적인 장르로 나뉜다.
전자가 추천 장르에 들어가게될 경우,
스토리가 엄청난 비중을 차지하고 있어서 연관된 장르의 웹툰을 보여주긴 힘들 것 같다는 생각이 들어서,
후자의 세부 장르로 필터링하여 추천해주기로했다.
public List<SimilarGenreToonDto> getSimilarGenre(Long id) {
//웹툰 찾기
Webtoon webtoon = webtoonRepository.findById(id).orElseThrow(
() -> new IllegalArgumentException("해당 id의 웹툰은 존재하지 않습니다.")
);
List<Genre> genre = webtoonRepository.findWebToonGenre(webtoon);
List<SimilarGenreToonDto> similarGenreToonDtoList = new ArrayList<>();
//비슷한 장르의 웹툰 찾기
List<Webtoon> webtoonList = webtoonRepository.findSimilarWebtoonByGenre(genre.get(1).getGenreType(),webtoon);
for (Webtoon w : webtoonList) {
SimilarGenreToonDto similarGenreToonDto = SimilarGenreToonDto.builder()
.toonAuthor(w.getToonAuthor())
.toonTitle(w.getToonTitle())
.toonImg(w.getToonImg())
.toonAvgPoint(w.getToonAvgPoint())
.toonFlatform(w.getToonFlatform())
.toonWeekday(w.getToonWeekday())
.totalPointCount(w.getTotalPointCount())
.build();
similarGenreToonDtoList.add(similarGenreToonDto);
}
return similarGenreToonDtoList;
}
[ 통합 테스트 코드 ]
- 더미 데이터가 좀 많은 느낌이 있지만.. 랜덤으로 쏙쏙 골라서 잘 뿌려주는지 확인해보고 싶었다.
이제 기능들이 작동하는 것을 확인했으니, 다음은 단위 테스트로 변경해보자!
@DisplayName("비슷한 장르의 웹툰을 랜덤으로 추천 테스트")
@Test
public void test() throws Exception{
//given
//웹툰
Webtoon w1 = createWebtoon("제목1", "작가1", "내용1");
Webtoon w2 = createWebtoon("제목2", "작가2", "내용2");
Webtoon w3 = createWebtoon("제목3", "작가3", "내용3");
Webtoon w4 = createWebtoon("제목4", "작가4", "내용4");
Webtoon w5 = createWebtoon("제목5", "작가5", "내용5");
em.persist(w1);
em.persist(w2);
em.persist(w3);
em.persist(w4);
em.persist(w5);
//장르 저장
Genre g1 = createGenre("일상");
Genre g2 = createGenre("개그");
Genre g3 = createGenre("판타지");
em.persist(g1);
em.persist(g2);
em.persist(g3);
//웹툰_장르 설정
WebtoonGenre wg1 = createWebToonGenre(w1, g1);
WebtoonGenre wg2 = createWebToonGenre(w1, g2);
WebtoonGenre wg3 = createWebToonGenre(w2, g1);
WebtoonGenre wg4 = createWebToonGenre(w2, g2);
WebtoonGenre wg5 = createWebToonGenre(w3, g3);
WebtoonGenre wg6 = createWebToonGenre(w3, g2);
WebtoonGenre wg7 = createWebToonGenre(w4, g1);
WebtoonGenre wg8 = createWebToonGenre(w4, g3);
WebtoonGenre wg9 = createWebToonGenre(w5, g1);
WebtoonGenre wg10 = createWebToonGenre(w5, g2);
em.persist(wg1);
em.persist(wg2);
em.persist(wg3);
em.persist(wg4);
em.persist(wg5);
em.persist(wg6);
em.persist(wg7);
em.persist(wg8);
em.persist(wg9);
em.persist(wg10);
//when
List<SimilarGenreToonDto> toonDtos = webtoonService.getSimilarGenre(w1.getId());
//then
assertThat(toonDtos.size()).isEqualTo(2);
assertThat(toonDtos.get(0).getToonTitle()).isNotEqualTo(w1.getToonTitle());
for (SimilarGenreToonDto toonDto : toonDtos) {
System.out.println("toonDto.getToonTitle() = " + toonDto.getToonTitle());
}
}
'Spring Project > Webtooniverse' 카테고리의 다른 글
[ Webtooniverse ] 2차 DB 구축- 카카오 웹툰 크롤링 (0) | 2021.08.05 |
---|---|
[ Webtooniverse ] Refactor - 정적 팩토리 메서드 (0) | 2021.08.03 |
[ Webtooniverse ] 웹툰 상세 페이지 개발 - 웹툰 별점 등록하기 (0) | 2021.08.02 |
[ Webtooniverse ] 웹툰 상세 페이지 개발 - 리뷰 좋아요 기능 & 리뷰 수정 및 삭제 (0) | 2021.08.01 |
[ Webtooniverse ] 웹툰 상세 페이지 개발 - 웹툰 장르, Review 리스트 (0) | 2021.07.30 |