ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Vue, Express] Vue와 Express로 간단한 웹 개발하기 1
    programing/Language 2019. 1. 26. 17:30


    안녕하세요, Einere입니다.

    (ADblock을 꺼주시면 감사하겠습니다.)


    오늘은 Vue와 Express.js를 활용하여 간단한 웹 페이지를 구현해보도록 하겠습니다.

    프론트엔드는 Vue를 사용하며, 백엔드는 Express를 사용합니다.




    Structure


    브라우저에서 Vue앱으로 http request(요청)을 보내면, Vue앱에서 다시 http request로 Express서버에게 요청을 보냅니다.

    Express서버에서는 자신이 가지고 있는 json형식의 영화 데이터를 Vue앱으로 전송합니다.

    Vue앱은 Express서버에서 받은 데이터를 받아서 렌더링합니다.

    브라우저는 Vue앱이 렌더링 한 화면을 모니터에 띄워줍니다.




    Directory


    디렉토리 구조는 위와 같이 프로젝트 파일 밑에 Express용 폴더와 Vue용 폴더를 만드시면 됩니다.

    제 기준으로 doit폴더는 Express프로젝트 폴더이며, frontend폴더는 Vue프로젝트 폴더입니다.

    코드상의 이름과 사진의 이름이 다르므로, 사진은 그냥 "저런식으로 생겼구나~"하는 정도로만 생각하시면 됩니다.


    이와 같이 디렉토리를 구성하기 위해서, 

    npm install express-generator -g #express-generator를 글로벌하게 설치 
    express --view=jade backend
    cd backend
    npm install #필요한 모듈 설치
    DEBUG=backend:* npm start #서버 시작

    위와 같이 명령어를 입력합니다.

    express-generator를 글로벌로 설치하고, backend라는 프로젝트명으로 폴더를 만드는 것입니다. 제 기준으로는 doit이 되겠네요.

    그리고 backend폴더에 들어가서 필요한 module들을 설치합니다.


    npm install -g vue-cli  #vue-cli를 글로벌하게 설치
    vue init webpack frontend
    #프롬프트마다 필요한 설정을 합니다. 
    #vue-router 추가에 대한 질문은 꼭 Y를 해주세요
    cd frontend
    npm install #필요한 module 설치

    위의 명령어를 입력하여 Vue프로젝트 폴더도 만들어 줍니다.




    Backend implement

    [
        {
            "id": 1,
            "name": "공조",
            "year": 2017,
            "director": "김성훈",
            "poster": "http://img.cgv.co.kr/Movie/Thumbnail/Poster/000079/79416/79416_185.jpg",
            "description" : "공조 입니다."
        },
        {
            "id": 2,
            "name": "컨택트",
            "year": 2017,
            "director": "드니 빌뇌브",
            "poster": "http://img.cgv.co.kr/Movie/Thumbnail/Poster/000079/79437/79437_185.jpg",
            "description" : "컨택트 입니다."
        },
        {
            "id": 3,
            "name": "더킹",
            "year": 2017,
            "director": "한재림",
            "poster": "http://img.cgv.co.kr/Movie/Thumbnail/Poster/000079/79423/79423_185.jpg",
            "description" : "더킹 입니다."
        },
        {
            "id": 4,
            "name": "모아나",
            "year": 2017,
            "director": "론 클레멘츠, 존 머스커",
            "poster": "http://img.cgv.co.kr/Movie/Thumbnail/Poster/000079/79316/79316_185.jpg",
            "description" : "모아나 입니다."
        },
        {
            "id": 5,
            "name": "라이언",
            "year": 2017,
            "director": "가스 데이비스",
            "poster": "http://img.cgv.co.kr/Movie/Thumbnail/Poster/000079/79396/79396_185.jpg",
            "description" : "라이언 입니다."
        },
        {
            "id": 6,
            "name": "너의 이름은",
            "year": 2017,
            "director": "신카이 마코토",
            "poster": "http://img.cgv.co.kr/Movie/Thumbnail/Poster/000079/79313/79313_1000.jpg",
            "description" : "너의 이름은 입니다."
        }
    ]
    backend/data에 movie.json라는 파일을 만든 뒤, 위의 코드를 입력합니다.
    기본적으로 data라는 폴더는 없으므로, 직접 만드셔야 합니다.

    const express = require('express');
    const router = express.Router();
    const movies = require('../data/movie.json');
    
    router.get('/', function(req, res){
        res.send(movies);
    });
    
    router.get('/:id', function(req, res){
        const id = parseInt(req.params.id, 10);
        const movie = movies.filter(function(movie){
            return movie.id === id;
        });
        res.send(movie);
    });
    
    module.exports = router;
    backend/routes에 movie.js를 만든 후, 위의 코드를 입력합니다.
    "/movies/"로 get요청이 오면 모든 영화 리스트를 반환합니다.
    "/movies/:id"로 get요청이 오면 특정 id를 가진 영화의 정보를 반환합니다.

    var createError = require('http-errors');
    var express = require('express');
    var path = require('path');
    var cookieParser = require('cookie-parser');
    var logger = require('morgan');
    
    // get movie router
    const movieRouter = require('./routes/movie');
    
    var app = express();
    
    // view engine setup
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'jade');
    
    // use middleware
    app.use(logger('dev'));
    app.use(express.json());
    app.use(express.urlencoded({
        extended: false
    }));
    app.use(cookieParser());
    app.use(express.static(path.join(__dirname, 'public')));
    
    // route
    app.use('/movies', movieRouter);
    
    // catch 404 and forward to error handler
    app.use(function (req, res, next) {
        next(createError(404));
    });
    
    // error handler
    app.use(function (err, req, res, next) {
        // set locals, only providing error in development
        res.locals.message = err.message;
        res.locals.error = req.app.get('env') === 'development' ? err : {};
    
        // render the error page
        res.status(err.status || 500);
        res.render('error');
    });
    
    module.exports = app;
    backend/app.js을 위와 같이 수정합니다. 
    확장성을 위해서 라우팅으로 구현하도록 하겠습니다.
    require()를 통해 backend/routes/movie에 있는 movie.js를 가져옵니다.
    app.use()를 이용해서 /movies경로에 대해서는 movieRouter를 사용하도록 합니다.
    나머지 코드는 express-generator를 이용해 프로젝트를 생성하면 자동으로 생성되는 코드입니다.

    이로서 backend구현은 끝났습니다. 이제 frontend를 구현하도록 합니다.



    Frontend implement

    proxyTable: {
        '/movies': {
            target: 'http://localhost:3000/movies',
            changeOrigin: true,
            pathRewrite: {
                '^/movies': ''
            }
        }
    },

    frontend/config/index.js에서, proxyTable객체를 찾아서 위와 같이 수정합니다.

    이 코드는, Vue에서 "...:8080/movies"으로 요청이 오면, "...:3000/movies"를 프록시로 사용하는 코드입니다.

    대충 Vue의 포트는 8080이며 Express의 포트는 3000이니, 이 포트를 포함한 url을 유연하게 연결시켜주는 부분입니다.

    여튼 하라는대로 합시다. ㅎㅎ


    ...
    import axios from 'axios'
    ...
    Vue.prototype.$http = axios

    frontend/src/main.js에 위 코드를 추가해줍니다.

    이로써 Vue앱에서 this.$http를 통해 http request를 할 수 있게 됩니다.


    전체 영화 목록을 조회하는 페이지와 특정 영화를 조회하는 페이지를 구현하기 위해 두가지 컴포넌트를 만듭니다.


    <template> <div class="movies"> <h1>영화 목록</h1> <div class="container"> <div class="outer"> <div class="inner"> <div class="centered" v-for="movie in movies" :key="movie.id"> <img v-bind:src="movie.poster" class="poster"> <div> <strong>{{movie.name}}</strong> - <i>{{movie.director}}</i> [{{movie.year}}] <router-link :to="{ name: 'detailmovie', params: { id: movie.id }}">더보기</router-link> </div> </div> </div> </div> </div> </div> </template> <script> /* eslint-disable */ export default { created() { this.$http.get("/movies").then(response => { this.movies = response.data; }); }, data() { return { movies: [] }; } }; </script> <style> .outer { display: table; width: 100%; height: 100%; } .inner { display: table-cell; vertical-align: middle; text-align: center; } .centered { position: relative; display: inline-block; width: 50%; padding: 1em; font-size: 1.5em; /* background: orange; */ /* color: white; */ } .poster{ width: 30%; height: 40%; } </style>

    frontend/src/components에 MovieListPage.vue을 만들어 위와 같이 작성합니다.

    http request를 통해 Express서버에 모든 영화 목록 데이터를 요청한 뒤, 데이터를 받아서 랜더링 하는 코드입니다.

    <router-link :to="{ name: 'detailmovie', params: { id: movie.id }}">더보기</router-link>에서 name의 값은 frontend/src/router/index.js에서 정의할 name의 값과 같습니다.


    <template> <div> <h1>상세 내용</h1> <div class="container"> <div class="outer"> <div class="inner"> <div class="centered"> <img v-bind:src="movie.poster" class="poster"> <div> <strong>{{movie.name}}</strong> - <i>{{movie.director}}</i> [{{movie.year}}] <p>{{movie.description}}</p> <router-link :to="{ name: 'movielist' }">돌아가기</router-link> </div> </div> </div> </div> </div> </div> </template> <script> /* eslint-disable */ export default { created: function() { var id = this.$route.params.id; this.$http.get(`/movies/${id}`).then(response => { this.movie = response.data[0]; }); }, data: function() { return { movie: {} }; } }; </script>

    같은 위치에 DetailMoviePage.vue를 만들어 위와 같이 작성합니다.

    http request를 통해 Express서버에 특정 영화 데이터를 요청한 뒤, 데이터를 받아서 랜더링 하는 코드입니다.

    <router-link :to="{ name: 'movielist' }">돌아가기</router-link>에서 name의 값은 frontend/src/router/index.js에서 정의할 name의 값과 같습니다.


    /* eslint-disable */
    import Vue from 'vue'
    import Router from 'vue-router'
    import MovieListPage from '@/components/MovieListPage'
    import DetailMoviePage from '@/components/DetailMoviePage'
    
    Vue.use(Router)
    
    export default new Router({
      routes: [{
          path: '/',
          name: 'movielist',
          component: MovieListPage
        },
        {
          path: '/:id',
          name: 'detailmovie',
          component: DetailMoviePage
        }
      ]
    })

    frontend/src/router/index.js를 위와 같이 수정합니다.

    위에서 만든 컴포넌트를 라우터에 연결하는 코드입니다.

    즉, Vue앱에 ".../"로 요청이 오면 MovieListPage.vue를 보여주며, ".../:id"로 요청이 오면 DetailMoviePage.vue를 보여줍니다.




    Run Express and Vue

    npm start #backend에서 실행
    npm run dev #frontend에서 

    콘솔창 하나를 띄워서, Express서버를 시작합니다.

    또 다른 콘솔창 하나를 띄워서, Vue앱을 시작합니다.




    "http://localhost:8080/"으로 접속하면 위와 같이 영화 목록들이 뜹니다.




    더보기를 클릭하여 자세히 볼 수 있습니다.

    돌아가기를 클릭하면 이전 페이지으로 돌아갈 수 있습니다.




    참고


    댓글

Designed by black7375.