컬쥐네 다락방

항해 99, spring을 이용한 NETFLIX 클론코딩 본문

공부방/항해 99

항해 99, spring을 이용한 NETFLIX 클론코딩

코딩하는 갱얼쥐 2021. 4. 12. 01:54

[해당 레포는 이미 너무 오래됐고 기초적인 내용만을 담고 있어 삭제했음을 미리 알려드립니다 😥😥 이제 공유해드릴 수가 없어요.. ! 공부하시다가 막혔거나 질문사항이 있으시면 도움을 드리겠습니다 .. ! ]

 

😆지난 일주일은 팀마다 하고싶은 서비스를 정해서 클론코딩하는 주간이었어요.

 

우리 팀은 평소에 즐겨보던 넷플릭스 서비스를 클론코딩하기로 정했습니다 ! .

우리 팀의 스택은 Spring(백앤드)과 React(프론트앤드) !  

이미 만들어진 페이지를 따라 만드는 것이기에 와이어 프레임은 생략하고 우리들이 구현하고 싶은 API를 설계하는 단계에서 시작했어요. 

 

API 설계

일단 시간이 일주일뿐이기에 먼저 최우선으로 만들 목표를 정했어요. 메인 페이지와 상세 페이지 구현, 그리고 회원가입과 로그인. 그리고 그에 해당하는 API를 나누고 데이터의 형태를 정했습니다. (이때 API를 더 상세하게 적었어야 했는데, 다들 처음 맞춰보는 팀 프로젝트여서 큼직 큼직하게 만들어놨는데 나중에 수정해주는 작업이 필요했어요.)

 

카카오 로그인은 중요도가 낮다고 생각해서 일단은 보류 처리 해뒀어요. 

 

페이지를 만들고 시간이 남으면 좋아요 기능과 프로필 페이지, 프로필 수정 기능을 추가하고 싶어서 작성해놨습니다. 

하지만 시간이 많이 부족해서 여기까지 갈 수 없었어요... 😥

THE Movie DB OPEN API 

넷플릭스 페이지를 만들기는 하지만 넷플릭스의 모든 영화와 드라마 자료를 크롤링하기에는 어렵다고 판단해서 팀원들과 The Movie DB Open API를 이용하기로 했습니다. 

www.themoviedb.org/

 

The Movie Database (TMDb)

Welcome. Millions of movies, TV shows and people to discover. Explore now.

www.themoviedb.org

developers.themoviedb.org/3/getting-started/introduction

위의 링크에 보면 다양한 방식으로 api를 이용해 정보를 받아올 수 있었어요. 

넷플릭스 화면을 만들기 위해 인기있는 영화, 드라마 순위를 받아와서 저희 DB에 업데이트 시켜 페이지를 나타낼 기초 데이터를 수집했어요. 

그리고 각 컨텐츠를 선택했을 때 해당하는 컨텐츠를 open api에서 상세 검색을 진행해 다시 필요한 데이터를 돌려주는 방식을 이용했습니다. 

API 예시 :
https://api.themoviedb.org/3/movie/popular?api_key=127d1ec8dfd28bfe9f6b8d15f689cdd4&language=ko-KR&page=1
데이터 예시 : 
{

- **adult**: false,
- **backdrop_path**: "/drulhSX7P5TQlEMQZ3JoXKSDEfz.jpg",
- **genre_ids**: [],
    - 18,
    - 14,
    - 878
- **id**: 581389,
- **original_language**: "ko",
- **original_title**: "승리호",
- **overview**: "2092년, 지구는 병들고 우주 위성궤도에 인류의 새로운 보금자리인 UTS가 만들어졌다. 돈 되는 일이라면 뭐든 하는 조종사 태호, 과거 우주 해적단을 이끌었던 장선장, 갱단 두목이었지만 이제는 기관사가 된 타이거 박, 평생 이루고 싶은 꿈을 가진 작살잡이 로봇 업동이, 이들은 우주쓰레기를 주워 돈을 버는 청소선 승리호의 선원들이다. 어느 날 사고 우주정을 수거한 승리호는 그 안에 숨어있던 대량살상무기로 알려진 인간형 로봇 도로시를 발견한다. 돈이 절실한 선원들은 도로시를 거액의 돈과 맞바꾸기 위한 위험한 거래를 계획하는데...",
- **popularity**: 2840.416,
- **poster_path**: "/vq2cqGRmhEFQ2wS4D3BMcYRoUK4.jpg",
- **release_date**: "2021-02-05",
- **title**: "승리호",
- **video**: false,
- **vote_average**: 7.2,
- **vote_count**: 456

}

 

 

인기 영화를 검색했을 때 다음과 같은 데이터를 받아 올 수 있었는데, 프론트 엔드에서 원하는 데이터 형식으로 바꿔 우리 DB 저장하는 과정을 거쳤어요. 

저장하는 과정에서 AJax 통신을 이용해서 Open API에서 준 데이터를 문자열로 바꿔주고, 한번 더 JSON 형식으로 바꿔준 다음 우리가 원하는 데이터만 KEY값을 이용해서 분리시켜줬습니다. 이때 가장 문제가 발생했던 부분은 다음과 같습니다. 

1. Open API에서 보내주는 데이터의 형식이 일정하지 않다. 

 - 항상 똑같은 key값과 데이터를 가지고 있는게 아니라, key값이 없거나 데이터가 비어있는 경우가 굉장히 많았다.

2. 하나의 key값에 배열의 데이터가 존재하는 경우가 있었다.

 - 장르의 경우 숫자로 이루어진 배열이 데이터로 존재했다.

    public ContentDto(JSONObject contentJson){


        if(contentJson.isNull("id")){
            this.contentId = null;
        } else{
            this.contentId = contentJson.getLong("id");
        }
        if(contentJson.isNull("title")){
            this.title = "";
        } else{
            this.title = contentJson.getString("title");
        }
        if(contentJson.isNull("overview")){
            this.overview = "";
        } else{
            this.overview = contentJson.getString("overview");
        }
        if(contentJson.isNull("poster_path")){
            this.poster_path = "";
        } else{
            this.poster_path = contentJson.getString("poster_path");
        }

        if(contentJson.isNull("release_date")){
            this.releaseDate = "";
        } else{
            this.releaseDate = contentJson.getString("release_date");
        }
        if(contentJson.isNull("vote_average")){
            this.average = null;
        } else{
            this.average = contentJson.getDouble("vote_average");
        }

        if(contentJson.isNull("backdrop_path")){
            this.backdrop_path = "";
        } else{
            this.backdrop_path = contentJson.getString("backdrop_path");
        }
        if(contentJson.isNull("genre_ids")){
            this.genre = null;
        } else{
            this.genre = new ArrayList<>();
            JSONArray genre_ids_array = contentJson.getJSONArray("genre_ids");

            if( genre_ids_array.length() >0){
                this.genre.add(genre_ids_array.getLong(0));
            }else {
                this.genre = null;
            }
        }
    }

이를 해결하기 위해서 내가 원하는 정보를 가져오기 전에 항상 그 값이 null인지 아닌지 확인하도록 만들어줬다. 처음에는 .has(key)를 사용해서 키의 유무를 확인했지만, 데이터가 비어있는 경우에는 오류가 발생해서 널인지 확인하게 만들자 작동에 성공했다. 

또 장르의 경우 ArrayList를 만들어서 배열 형태로 받아주고, for문을 돌려서 테이블에 추가해줬다. (처음에는 이런 방식을 사용했지만 인기 순으로 나열하다보니 메인 페이지에 똑같은 영화나 드라마가 너무 겹치는 현상이 발생할 것 같아서 장르를 하나만 선택해서 넣어주는 형식으로 변경했다.)

 

그리고 이렇게 만들어진 테이블을 이용해 메인 페이지를 구성했고, 상세 페이지를 열기위해 포스터를 누르거나, 상세 페이지에서 영상을 보기위해 재생 버튼을 누르면, 서버에서 해당하는 컨텐츠의 ID를 이용해서 실시간으로 Open API에 상세 검색을 진행하고 바로 값을 전달해주도록 구성해줘서 페이지 구성을 마무리했다. 

 

아쉬운 점

나는 백엔드를 담당했기에 서버측에서 정보를 처리하는 과정만 구현했는데, 이러다보니 프론트 엔드와 속도를 완벽히 맞출 수 없어서 내가 기능을 구현했더라도 바로 추가하기가 어려웠다. 

실제로 로그인, 회원가입 기능과 찜하기 기능을 대부분 만들어뒀지만, 프론트 쪽에서 페이지를 만들 시간이 너무 부족해서 이를 추가하지 못했는데, 너무 아쉬웠다. 이 기능들은 스스로 Mock API를 통해서 기능을 실험 해봤을 때는 완벽히 작동했지만, 프론트와 연동했을 때 제대로 돌아가는지는 확인이 어려웠다

 

느낀 점

평소에는 혼자 프론트와 백 둘 다 설계해야 했기 때문에 프로젝트를 진행할 때 정말 정신이 없었는데 분업을 하니까 굉장히 색다른 느낌이었다. 

또 평소에 코딩을 혼자 할 땐 변수의 이름이나 데이터 구조를 내가 그때 그때 하고싶은 형태로 만들고 수정했는데 협업을 해야하니 이 부분에 대해서 미리 확실하게 정해두고 지켜야해서 처음에는 조금 답답한 느낌이 들었다. 

물론 진행하다보니 익숙해졌고, 미리 정해둔 형식으로 만들다보니 후반부에는 오히려 더 편했다. 복잡하지 않고 쉽게 데이터를 찾을 수 있었기 때문.😄

 

또 나는 처음에 내가 만드는 화면이 바로바로 보이는 프론트앤드가 더 재밌어보여 흥미가 갔고, 그래서 백과 프론트 사이에서 주특기를 선택할 때 굉장히 고민했는데, 코드가 지저분하던 말던 내가 원하는 기능으로 동작만 하게 만드는 백엔드가 나와 더 잘어울린다고 생각했다. (물론 계속해서 어떤 방식이, 어떤 코드가 더 효율적일지 고민해야 하겠지만)

Comments