[SI]영화진흥위원회 오픈 api 사용하여 데이터(영화순위, 영화명, 개봉일, 누적관객수, 상영관수, 영화 정보) 불러오기

Open api를 사용하여 데이터를 불러오기

 

ReadME.md

# 설치 패키지 
# 1) 메뉴 라이브러리 설치
npm i react-router-dom

# 2) 벡엔드 연동 라이브러리 설치
npm i axios

# 3) pre css 컴파일러 : node-sass -> 더이상 안씀 : sass 설치할것
<!-- npm i node-sass -->
npm install sass
# 4) Material Page component 업그레이드 
# 과거 v4 -> v5 변경 설치
npm i @mui/material @emotion/react @emotion/styled

# 4-1) 소스에서 임포트 사용법 : <Pagination />
import Pagination from '@mui/material/Pagination';

# 5) typescript jquery, jqueryui type 넣기
# 5-1) typescript jquery 사용
npm i --save-dev @types/jquery
npm i @types/jqueryui

# 6) 공통코드 : 프로젝트 시작 시 코드체계를 정의하고
# 각가의 테이블에서사용하는 목적으로 씀
# 예) 온라인 쇼핑몰 프로젝트 :
# - 공통 코드 대상: 주문 -> 결재 -> 배송 -> 확정 : 상태들
# - 예시 테이블 : 상품명(아우터) - 상태명(결재) : 컬럼명
# - 공통 코드 : 주문 == 10001
#               결재 == 10002
#               배송 == 10003
#               확정 == 10004
# - 관리 개선(공통 코드 적용) : 상품명(아우터) - 상태명(10002)

 

 

src - pages - cinema - Cinema.tsx 만들기

Cinema.tsx

// Cinema.tsx : rfce
import React, { useEffect, useState } from "react";
import TitleCom from "../../../components/common/TitleCom";
import { useParams } from "react-router-dom";
import ICinemaDetail from "../../../types/shop/ICinemaDetail";
import CinemaService from "../../../services/shop/CinemaService";

function Cinema() {
  // todo: 변수 정의
  // 전체조회 페이지에서 전송한 기본키(movieCd)
  const { movieCd } = useParams();


  // 객체 초기화(상세조회 : 기본키 있음)
  const initialCinema = {
    movieCd: "", // 영화코드
    movieNm: "", // 영화명
    prdtYear: "", // 제작년도
    showTm: "", // 상영시간
    openDt: "", // 개봉연도
    actors: [], // 배우들 배열
    directors: [], // 감독들 배열
    prdtStatNm: "", // 제작상태명
  };

  // cinemaDetail 객체
  const [cinemaDetail, setCinemaDetail] =
    useState<ICinemaDetail>(initialCinema);

  // todo: 함수 정의
  // 상세조회 함수
  const getCinema = (movieCd: string) => {
    CinemaService.get(movieCd) // 벡엔드로 상세조회 요청
      .then((response: any) => {
        // todo: 영화 상세정보 받기
        const { movieInfo } = response.data.movieInfoResult;
        setCinemaDetail(movieInfo);
        console.log(response.data.movieInfoResult);
      })
      .catch((e: Error) => {
        console.log(e);
      });
  };

  // 화면이 뜰때 실행되는 이벤트 + movieCd 값이 바뀌면 실행
  useEffect(() => {
    if (movieCd) getCinema(movieCd);
  }, [movieCd]);

  return (
    // 여기
    <>
      {/* 제목 start */}
      <TitleCom title="Cinema Detail" />
      {/* 제목 end */}

      <>
        {cinemaDetail ? (
          <div className="card mb-3">
            <div className="row g-0">
              <div className="col-md-4 p-2">
                <img
                  src="http://placehold.it/800x1000"
                  className="img-fluid rounded-start"
                  alt="..."
                />
              </div>
              <div className="col-md-8">
                <div className="card-body">
                  <span className="badge text-bg-primary">
                    {cinemaDetail.movieCd}
                  </span>
                  <h2 className="card-title mt-3">{cinemaDetail.movieNm}</h2>
                  <p className="card-text mt-5">
                    제작년도 : {cinemaDetail.prdtYear}
                  </p>
                  <p className="card-text">
                    상영시간 : {cinemaDetail.showTm}
                  </p>
                  <p className="card-text">개봉일 : {cinemaDetail.openDt}</p>
                  <p className="card-text">상태 : {cinemaDetail.prdtStatNm}</p>
                  {/* <span className="badge text-bg-primary">{cinemaDetail.kindCode}</span> */}
                  <div className="card-text">
                    <div className="row g-3 align-items-center mb-3">
                      <div className="col-3">
                        <label htmlFor="directors" className="col-form-label">
                          directors
                        </label>
                      </div>
                      {cinemaDetail.directors &&
                        cinemaDetail.directors.map((data, index) => (
                          <div
                            className="col-3 bg-warning bg-gradient me-2"
                            key={index}
                          >
                            <label htmlFor="actors" className="col-form-label">
                              {data.peopleNm}
                            </label>
                          </div>
                        ))}
                    </div>
                    <div className="row g-3 align-items-center mb-3">
                      <div className="col-3">
                        <label htmlFor="actors" className="col-form-label">
                          actors
                        </label>
                      </div>
                      {cinemaDetail.actors &&
                        cinemaDetail.actors.map((data, index) => (
                          <div
                            className="col-3 bg-secondary bg-gradient text-white me-2"
                            key={index}
                          >
                            <label htmlFor="actors" className="col-form-label">
                              {data.peopleNm}
                            </label>
                          </div>
                        ))}
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        ) : (
          <div className="col-6 mx-auto">
            <br />
            <p>Please click on a Cinema...</p>
          </div>
        )}
      </>
    </>
  );
}

export default Cinema;

 


src - pages - cinema - CinemaList.tsx 만들기

CinemaList.tsx

// CinemaList.tsx : rfce
import React, { useEffect, useRef, useState } from "react";
import TitleCom from "../../../components/common/TitleCom";
import { Link } from "react-router-dom";
import ICinema from "../../../types/shop/ICinema";
import CinemaService from "../../../services/shop/CinemaService";
// 달력 이미지 경로
import imgCalendar from "../../../assets/img/calendar.png";

function CinemaList() {
  // todo: 변수 정의
  // cinema 배열 변수
  const [cinema, setCinema] = useState<Array<ICinema>>([]);
  // nationCode(K : 한국영화, F : 외국영화) 검색어 변수
  const [searchNationCode, setSearchNationCode] = useState<string>("");

  // todo: 공통 변수 : pageSize(3,6,9 배열)
  const [pageSize, setPageSize] = useState<number>(3); // 1페이지당개수
  // todo: 공통 pageSizes : 배열 (셀렉트 박스 사용)
  const pageSizes = [3, 6, 9];

  //   todo: 달력변수 정의
  //   useRef() : html 태그에 직접접근하게 하는 함수
  //   datepicker.current.value : 그 html 태그의 값
  const datepicker = useRef<any>();

  // todo: 함수 정의
  useEffect(() => {
    // todo: 달력(jquery-ui) 초기화
    $("#datepicker").datepicker({
      dateFormat: "yymmdd",
      showOn: "button", // 버튼을 클릭하면 달력보이기
      buttonImage: imgCalendar, // 버튼에 달력 이미지 보이기
    });
    retrieveCinema(); // 전체 조회
  }, [pageSize]);

  //   전체조회 함수
  const retrieveCinema = () => {
    // getAll(현재선택된날짜, 영화구분, 페이지크기)
    CinemaService.getAll(datepicker.current.value, searchNationCode, pageSize) // 벡엔드 전체조회요청
      .then((response: any) => {
        const { dailyBoxOfficeList } = response.data.boxOfficeResult;
        setCinema(dailyBoxOfficeList);
        console.log("response", response.data);
      })
      .catch((e: Error) => {
        console.log(e);
      });
  };

  //  검색어 수동 바인딩 함수
  const onChangeSearchNationCode = (e: any) => {
    setSearchNationCode(e.target.value);
  };

  // todo: handlePageSizeChange(공통) : pageSize 값 변경시 실행되는 함수
  //  select 태그 수동 바인딩 : 화면값 -> 변수에 저장
  const handlePageSizeChange = (event: any) => {
    setPageSize(event.target.value); // 1페이지당 개수저장(3,6,9)
  };
  return (
    // 여기
    <>
      {/* 제목 start */}
      <TitleCom title="Cinema List" />
      {/* 제목 end */}

      <div className="row mb-3"></div>

      {/* rankOldAndNew start */}
      <div className="row mb-1">
        <div className="col-1">
          <label htmlFor="inputPassword6" className="col-form-label">
            영화구분 :
          </label>
        </div>

        <div className="col-2">
          <select
            className="form-select"
            onChange={onChangeSearchNationCode}
            value={searchNationCode}
          >
            <option key="all" value="">
              전체
            </option>
            <option key="korea" value="K">
              국내영화
            </option>
            <option key="foreign" value="F">
              외국영화
            </option>
          </select>
        </div>

        {/* w-50 : 크기 조정, mx-auto : 중앙정렬(margin: 0 auto), justify-content-center */}
        <div className="col-auto w-25 input-group mb-3">
          <div className="input-group">
            <span className="input-group-addon me-2">
              <label htmlFor="inputPassword6" className="col-form-label">
                달력 :
              </label>
            </span>
            <input
              type="text"
              id="datepicker"
              className="form-control"
              disabled
              ref={datepicker}
            />
            <button className="btn btn-primary ms-5" onClick={retrieveCinema}>
              조회
            </button>
          </div>
        </div>
      </div>
      {/* rankOldAndNew end */}
      {/* paging 시작 */}
      <div className="mb-1">
        {"Items per Page: "}
        <select onChange={handlePageSizeChange} value={pageSize}>
          {pageSizes.map((size) => (
            <option key={size} value={size}>
              {size}
            </option>
          ))}
        </select>
      </div>
      {/* paging 끝 */}
      {/* table start */}
      <div className="col-md-12">
        {/* table start */}
        <table className="table">
          <thead className="table-light">
            <tr>
              <th scope="col">순위</th>
              <th scope="col">영화명</th>
              <th scope="col">개봉일</th>
              <th scope="col">누적관객수</th>
              <th scope="col">상영관수</th>
              <th scope="col">Actions</th>
            </tr>
          </thead>
          <tbody>
            {cinema &&
              cinema.map((data) => (
                <tr key={data.movieCd}>
                  <td>{data.rank}</td>
                  <td>
                    {data.movieNm}
                    <span className="badge rounded-pill text-bg-warning ms-2">
                      {data.rankOldAndNew == "NEW" ? data.rankOldAndNew : ""}
                    </span>
                  </td>
                  <td>{data.openDt}</td>
                  <td>{parseInt(data.audiAcc).toLocaleString()}</td>
                  <td>{parseInt(data.scrnCnt).toLocaleString()}</td>
                  <td>
                    <Link to={"/cinema/" + data.movieCd}>
                      <span className="badge bg-success">Edit</span>
                    </Link>
                  </td>
                </tr>
              ))}
          </tbody>
        </table>
        {/* table end */}
      </div>
      {/* table end */}
    </>
  );
}

export default CinemaList;


app.tsx 수정 cinema 

CinemaList(영화 리스트) Cineam (영화 상세조회) 추가

app.tsx

import React from "react";
// app css import
import "./assets/css/app.css";

import HeaderCom from "./components/common/HeaderCom";
import { Route, Routes } from "react-router-dom";
import Home from "./pages/Home";
import Login from "./pages/auth/Login";
import Register from "./pages/auth/Register";
import ForgotPassword from "./pages/auth/ForgotPassword";
import NotFound from "./pages/common/NotFound";
import DeptList from "./pages/basic/dept/DeptList";
import EmpList from "./pages/basic/emp/EmpList";
import AddDept from "./pages/basic/dept/AddDept";
import AddEmp from "./pages/basic/emp/AddEmp";
import Dept from "./pages/basic/dept/Dept";
import Emp from "./pages/basic/emp/Emp";
import QnaList from "./pages/basic/qna/QnaList";
import CustomerList from "./pages/basic/customer/CustomerList";
import AddQna from "./pages/basic/qna/AddQna";
import AddCustomer from "./pages/basic/customer/AddCustomer";
import Qna from "./pages/basic/qna/Qna";
import Customer from "./pages/basic/customer/Customer";
import FaqList from "./pages/normal/faq/FaqList";
import CinemaFaqList from "./pages/normal/cinema/CinemaFaqList";
import AddFaq from "./pages/normal/faq/AddFaq";
import AddCinemaFaq from "./pages/normal/cinema/AddCinemaFaq";
import Faq from "./pages/normal/faq/Faq";
import CinemaFaq from "./pages/normal/cinema/CinemaFaq";
import ReplyBoardList from "./pages/normal/reply-board/ReplyBoardList";
import ThreadBoardList from "./pages/normal/thread-board/ThreadBoardList";
import AddReplyBoard from "./pages/normal/reply-board/AddReplyBoard";
import AddThreadBoard from "./pages/normal/thread-board/AddThreadBoard";
import ReplyBoard from "./pages/normal/reply-board/ReplyBoard";
import ThreadBoard from "./pages/normal/thread-board/ThreadBoard";
import CodeCategoryList from "./pages/admin/CodeCategoryList";
import AddCodeCategory from "./pages/admin/AddCodeCategory";
import CodeList from "./pages/admin/CodeList";
import AddCode from "./pages/admin/AddCode";
import Code from "./pages/admin/Code";
import SimpleProductList from "./pages/shop/simple-product/SimpleProductList";
import ProductList from "./pages/shop/product/ProductList";
import AddSimpleProduct from "./pages/shop/simple-product/AddSimpleProduct";
import SimpleProduct from "./pages/shop/simple-product/SimpleProduct";
import SimpleCart from "./pages/shop/simple-product/SimpleCart";
import AddProduct from "./pages/shop/product/AddProduct";
import Product from "./pages/shop/product/Product";
import SimpleCartList from "./pages/shop/simple-product/SimpleCartList";
import CinemaList from "./pages/shop/cinema/CinemaList";
import Cinema from "./pages/shop/cinema/Cinema";
import ThemaLoadList from "./pages/shop/thema-load/ThemaLoadList";
import FileDbList from "./pages/advanced/FileDbList";

function App() {
  return (
    <div className="App">
      <HeaderCom />

      {/* <!-- 구분 막대 시작 --> */}
      <div className="gutter text-center text-muted fade-in-box">
        <div>클론 코딩 예제 사이트에 오신 것을 환영합니다.</div>
      </div>
      {/* <!-- 구분 막대 끝 --> */}

      <div id="content-wrapper">
        {/* 라우터 정의 시작 */}
        <Routes>
          {/* login */}
          <Route path="/" element={<Home />} />
          <Route path="/login" element={<Login />} />
          <Route path="/register" element={<Register />} />
          <Route path="/forgot-password" element={<ForgotPassword />} />

          {/* dept */}
          <Route path="/dept" element={<DeptList />} />
          <Route path="/add-dept" element={<AddDept />} />
          <Route path="/dept/:dno" element={<Dept />} />

          {/* emp(연습) */}
          <Route path="/emp" element={<EmpList />} />
          <Route path="/add-emp" element={<AddEmp />} />
          <Route path="/emp/:eno" element={<Emp />} />

          {/* qna */}
          <Route path="/qna" element={<QnaList />} />
          <Route path="/add-qna" element={<AddQna />} />
          <Route path="/qna/:qno" element={<Qna />} />

          {/* customer */}
          <Route path="/customer" element={<CustomerList />} />
          <Route path="/add-customer" element={<AddCustomer />} />
          <Route path="/customer/:cid" element={<Customer />} />

          {/* faq */}
          <Route path="/faq" element={<FaqList />} />
          <Route path="/add-faq" element={<AddFaq />} />
          <Route path="/faq/:no" element={<Faq />} />

          {/* cinema faq */}
          <Route path="/cinema-faq" element={<CinemaFaqList />} />
          <Route path="/add-cinema-faq" element={<AddCinemaFaq />} />
          <Route path="/cinema-faq/:cfno" element={<CinemaFaq />} />

          {/* reply-board */}
          <Route path="/reply-board" element={<ReplyBoardList />} />
          <Route path="/add-reply-board" element={<AddReplyBoard />} />
          {/* 정리 : boardParent = 0 이면 부모글을 클릭 */}
          {/* 정리 : boardParent = 0 아니면 자식글을 클릭 */}
          <Route
            path="/reply-board/bid/:bid/boardParent/:boardParent"
            element={<ReplyBoard />}
          />

          {/* thread-board */}
          <Route path="/thread-board" element={<ThreadBoardList />} />
          <Route path="/add-thread-board" element={<AddThreadBoard />} />
          <Route
            path="/thread-board/tid/:tid/tparent/:tparent"
            element={<ThreadBoard />}
          />

          {/* codeCategory(대분류 공통코드(부모)) */}
          <Route path="/code-category" element={<CodeCategoryList />} />
          <Route path="/add-code-category" element={<AddCodeCategory />} />

          {/* code(소분류 공통코드(자식)) */}
          <Route path="/code" element={<CodeList />} />
          <Route path="/add-code" element={<AddCode />} />
          <Route path="/code/:codeId" element={<Code />} />

          {/* simple-product */}
          <Route path="/simple-product" element={<SimpleProductList />} />
          <Route path="/add-simple-product" element={<AddSimpleProduct />} />
          <Route path="/simple-product/:spno" element={<SimpleProduct />} />
          {/* 장바구니 상세 */}
          <Route path="/simple-cart/:spno" element={<SimpleCart />} />
          {/* 장바구니 전체 조회 */}
          <Route path="/simple-cart" element={<SimpleCartList />} />

          {/* product(연습) */}
          <Route path="/product" element={<ProductList />} />
          <Route path="/add-product" element={<AddProduct />} />
          <Route path="/product/:pno" element={<Product />} />

          {/* cinema */}
          {/* 박스오피스 순위 전체조회 */}
          <Route path="/cinema" element={<CinemaList />} />
          {/* 영화 상세조회 */}
          <Route path="/cinema/:movieCd" element={<Cinema />} />

          {/* NotFound */}
          <Route path="*" element={<NotFound />} />
        </Routes>
        {/* 라우터 정의 끝 */}
      </div>
    </div>
  );
}

export default App;

 

영화 진흥위원회 오픈 API 회원가입

 

https://www.kobis.or.kr/kobisopenapi/homepg/main/main.do

 

영화진흥위원회 오픈API

OPEN API 서비스 영화진흥위원회 영화관입장권통합전산망에서 제공하는 오픈API 서비스로 더욱 풍요롭고 편안한 영화 서비스를 즐겨보세요.

www.kobis.or.kr

 

키 발급받기

사용 목적 : 학습

관리명 : 아이디

서비스 사용 URL : 비움

 

src - types - shop - ICinema.ts 생성

영화진흥위원회 제공서비스에 많은 속성 들 중 몇개만 사용

ICinema.ts

// ICinema.ts : 인터페이스
// 영화진흥 위원회 응답필드 중 일부 : 화면에 출력됨
export default interface ICinema {
    movieCd:string,         // 영화코드
    rank: string,           // 해당일자의 박스오피스 순위를 출력합니다.
    rankOldAndNew: string,  // 랭킹에 신규진입여부를 출력합니다.(“OLD” : 기존 , “NEW” : 신규)
    movieNm: string,        // 영화명(국문)을 출력합니다.
    openDt: string,         // 영화의 개봉일을 출력합니다.
    audiAcc: string,        // 누적관객수를 출력합니다.
    scrnCnt: string,        // 해당일자에 상영한 스크린수를 출력합니다.
}


src - services - shop - CinemaService.ts 생성

// CinemaService.ts
// 영화진흥 위원회의 오픈 API 통신 함수들 정의
// 전체조회 또는 상세조회

import axios from "axios";
import { Console } from "console";
import ICinema from "../../types/shop/ICinema";

// 영화진흥 위원회 기본 주소
// /boxoffice/searchDailyBoxOfficeList.json

// 발급 받은 api key 변수
let apiKey = "004399a654227ec5064e8d748b271196";

// 전체 조회
// 요청필드(조건)
// key : 위의 인증키 넣기(필수)
// targetDt : 조회하고자 하는 날짜를 yyyymmdd 형식(필수)
// repNationCd : “K: : 한국영화 “F” : 외국영화 ("" : 전체)
// itemPerPage : 결과 ROW 의 개수를 지정
// 변수 사용 : 쿼리스트링 방식 (?변수명=값&변수명2=값2...)
const getAll = (targetDt: string, repNationCd: string, itemPerPage:number) => {
    // 주소 조합 : 기본주소 + 추가주소 + 변수명
    let url = `${baseUrl}/boxoffice/searchDailyBoxOfficeList.json?key=${apiKey}&targetDt=${targetDt}&repNationCd=${repNationCd}&itemPerPage=${itemPerPage}&serviceKey=${apiKey}`;
    console.log("url", url);

    return axios.get<Array<ICinema>>(url);
 }

// 영화 상세조회(1건조회)
// ${baseUrl}/movie/searchMovieInfo.json
// 요청필드(조건) :
// key : 인증키(위에 있음) : 필수
// movieCd (영화코드)
const get = (movieCd: string) => {
    // 기본주소 + 추가주소 + 변수명(쿼리스트링)
    let url = `${baseUrl}/movie/searchMovieInfo.json?key=${apiKey}&movieCd=${movieCd}`;
    console.log("상세조회 url", url);

    return axios.get<ICinema>(url);
 }

 const CinemaService = {
    getAll,
    get
 }

 export default CinemaService;

 



src - types - shop - ICinemaDetail.ts 생성

ICinemaDetail.ts

// ICinemaDetail.ts : 인터페이스
export default interface ICinemaDetail {
    movieCd:string,        // 영화코드를 출력합니다.
    movieNm: string,       // 영화명(국문)을 출력합니다.
    prdtYear: string,      // 제작연도를 출력합니다.
    showTm: string,        // 상영시간을 출력합니다.
    openDt: string,        // 개봉연도를 출력합니다.
    directors: Array<any>, // 감독을 나타냅니다.
    actors: Array<any>,    // 배우를 나타냅니다.
    prdtStatNm: string,    // 제작상태명을 출력합니다.
};

 

결과

영화 리스트

 

상세조회