본문 바로가기
Spring/프로젝트 코드 리뷰

Spring WatchaPedia 클론코딩 프로젝트 취향 분석(선호 배우, 국가, 장르, 감상 시간)

by code2772 2023. 3. 8.

[ 목차 ]

    728x90
    반응형

    🎬 선호배우 분석 Service

    public List<Map.Entry<String, String>> peopleCnt(Long userIdx){
        Map<Long, Integer> peopleMap = new HashMap<>();
        List<Long> movIdxs = starRepository.findStarMovie(userIdx);
        List<String> peopleList = List.of(movieRepository.findPeopleList(movIdxs).toString()
                .split("\\[")[1].split("]")[0].split(", "));
        for(String str: peopleList){
            String[] personList = str.split(",");
            for(String per : personList){
                if(per.contains("주연")){
                    Long personIdx = 0L;
                    try {
                        if (per.contains("(")) {
                            personIdx = Long.valueOf(per.split("\\(")[0]);
                        } else personIdx = Long.valueOf(per);
    
                        if (peopleMap.get(personIdx) != null) {
                            peopleMap.put(personIdx, 1 + peopleMap.get(personIdx));
                        } else {
                            peopleMap.put(personIdx, 1);
                        }
                    }catch(NumberFormatException e){}
                }
            }
        }
        List<Map.Entry<Long, Integer>> entryList = new LinkedList<>(peopleMap.entrySet());
        entryList.sort(((o1, o2) -> o2.getValue() - o1.getValue()));
    
        Pageable pageable = PageRequest.of(0, 1);
        Map<String, String> resultMap = new HashMap<String, String>();
        for(int i=0; i<=5; i++){
            try{
                Person person = personRepository.findById(entryList.get(i).getKey()).get();
                resultMap.put((person.getPerPhoto()!=null?person.getPerPhoto()+"|":"")+person.getPerName()+","+person.getPerIdx()
                        ,entryList.get(i).getValue()+","+movieRepository.actorMovie("%,"+person.getPerIdx()+"(주연%",pageable).get(0));
            }catch (IndexOutOfBoundsException e){
                System.out.println("인물 부족");
            }
        }
        List<Map.Entry<String, String>> result = new LinkedList<>(resultMap.entrySet());
        result.sort(((o1, o2) -> Integer.parseInt(o2.getValue().split(",")[0]) - Integer.parseInt(o1.getValue().split(",")[0])));
        return result;
    }

    사용자가 감상한 또는 평가한 tb_star 테이블의 idx를 찾는다. 이 후 이 tb_star의 idx와 콘텐츠 idx의 연관성을 찾아들어가 해당 콘텐츠의 출연/제작, 국가, 장르, 런닝타임 등을 뽑아와 카운트를 하여 나의 취향을 분석하는 부분이다.
     
    🎬 콘텐츠(영화) Repository

    @Query(value = "SELECT movCountry, COUNT(movCountry) FROM tbMovie WHERE movIdx in :idxs GROUP BY movCountry HAVING COUNT(movCountry) > 0")
    List<String> findCountryCnt(@Param("idxs") List<Long> idxs);
    @Query(value = "SELECT movGenre, COUNT(movGenre) FROM tbMovie WHERE movIdx in :idxs GROUP BY movGenre HAVING COUNT(movGenre) > 0")
    List<String> findGenreCnt(@Param("idxs") List<Long> idxs);
    @Query(value = "SELECT movPeople FROM tbMovie WHERE movIdx in :idxs")
    List<String> findPeopleList(@Param("idxs") List<Long> idxs);
    @Query(value = "SELECT movTime FROM tbMovie WHERE movIdx in :idxs")
    List<String> timeList(@Param("idxs") List<Long> idxs);
    @Query(value = "SELECT movTitle FROM tbMovie WHERE movPeople LIKE :idx ORDER BY movIdx DESC")
    List<String> actorMovie(@Param("idx") String idx, Pageable pageable);

    @Query는 domain model이 아닌 Repository안에있는 메서드에 위치, 테이블이 아닌 엔티티 객체를 대상으로 검색하는 객체지향 쿼리, SQL 추상화로 인해 특정 db sql 에 의존하지 않음. @Param 을 통해 매개변수로 넘어온 값을 JPQL에 들어갈 변수로 지정한다. 더 복잡한 SQL 문을 스프링에서 사용하기 위해 Query 엔티티를 사용하였다.
     
    🎬 선호배우 타임리프

    <ul class="css-1m9zbc5-VisualUl" th:remove="all-but-first">
      <li class="css-wj6fn0" th:each="person : ${actorMap}">
        <a th:title="${#strings.contains(person.getKey(), '|')}?
          (${#strings.arraySplit((#strings.arraySplit(person.getKey(),',')[0]),'|')[1]})
          :${#strings.arraySplit(person.getKey(),',')[0]}" class="css-1aaqvgs-InnerPartOfListWithImage"
          th:href="'/personDetail/'+${#strings.arraySplit(person.getKey(),',')[1]}">
          <div class="css-cssveg">
            <div class="css-13zlig9">
              <div class="css-1q751em-ProfilePhotoImage"
                  th:styleappend="'background:url('+${#strings.arraySplit(person.getKey(),'|')[0]}+') no-repeat center;repeat center; background-size: cover;'"></div>
            </div>
          </div>
          <div class="css-zoy7di">
            <div class="css-qkf9j">
              <div class="css-17vuhtq">
                <div class="css-1pfpne2-PersonTitle e72a1w70"><span
                    class="css-1neatfa-PersonName e72a1w71" th:text="${#strings.contains(person.getKey(), '|')}?
                    (${#strings.arraySplit((#strings.arraySplit(person.getKey(),',')[0]),'|')[1]})
                    :${#strings.arraySplit(person.getKey(),',')[0]}">김태리</span><span
                    class="css-104v25a-PersonDetail e72a1w72" th:text="${#strings.arraySplit(person.getValue(),',')[0]}+'편'">100점 • 3편</span></div>
              </div>
              <div class="css-1evnpxk-StyledSubtitle" th:text="${#strings.arraySplit(person.getValue(),',')[1]}">리틀 포레스트</div>
            </div>
            <div></div>
          </div>
        </a></li>

    1. 선호 배우는 먼저 HTML 내에 타임리프를 적용하였다. all-but-first와  th:each를 사용하여 리스트의 첫 번째 부분을 반복하였다.
    2. 이전 디테일 페이지와 유사하게 먼저 DB에 있는 인물의 정보를 나누기 위해 split을 이용하여 나눠 인물들을 출력시켰다. 
    3. 선호배우와 유사하게 선호국가, 장르, 감상시간 모두 유사하게 추출하였다.
     
     
    🎬 선호배우 웹페이지 출력화면 

    🎬 선호국가, 선호장르 웹페이지 출력화면 

    🎬 감상 시간 웹페이지 출력화면 

     

    반응형