Node.js(express) + MongoDB(mongoose) 簡單開發(一)


前言:

express作為一個Node框架,很適合新學習Node的同學,加上mongoose的數據處理,堪稱完美~ 閑話少說,步入正題。

我的系統環境:

  • Win7 64bit
  • Nodejs: v0.10.35
  • Npm: 1.4.28
  • IDE:webstorm

    1. 建立項目

    Node及express的安裝這里就不再贅述,網上有很多安裝的教程,不會的同學可以自行查找,這里我們采用express4.x版本

    安裝express庫完成之后,我們可以使用express命令來建立一個自己的項目: express -e vlan

    可以看到express幫我們創建了一個完整的項目級目錄

    1_thumb5

    express默認的是jade的模版, -e代表使用ejs, 這里我們使用ejs

    接下來進入項目目錄並安裝express所需的依賴

    3_thumb2

    2.目錄結構

    2_thumb3

    www文件就是啟動文件

    node_modules 存放所有項目的依賴

    public為靜態資源存放目錄,可以修改

    routes為路由文件

    views就是視圖了(頁面文件,ejs模板)

    3. app.js核心文件

    一般可能會改動的地方我都注釋了出來, 完整的app.js文件如下

    var express = require('express');
    var path = require('path');
    var favicon = require('serve-favicon');
    var logger = require('morgan');
    var cookieParser = require('cookie-parser');
    var bodyParser = require('body-parser');
    
    var routes = require('./routes/index');
    //var users = require('./routes/users');
    var ejs = require("ejs");
    var app = express();
    
    // 視圖目錄
    app.set('views', path.join(__dirname, 'views'));
    // 使用ejs模板 (替換為html文件)
    app.engine('.html', ejs.__express);
    app.set('view engine', 'html');
    //app.set('view engine', 'ejs');
    
    // uncomment after placing your favicon in /public
    //app.use(favicon(__dirname + '/public/favicon.ico'));
    app.use(logger('dev'));
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: false }));
    app.use(cookieParser());
    // 靜態資源存放目錄
    app.use(express.static(path.join(__dirname, 'public')));
    
    app.use('/', routes);
    //app.use('/users', users);
    
    // catch 404 and forward to error handler
    app.use(function(req, res, next) {
      var err = new Error('Not Found');
      err.status = 404;
      next(err);
    });
    
    // error handlers
    
    // development error handler
    // will print stacktrace
    if (app.get('env') === 'development') {
      app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
          message: err.message,
          error: err
        });
      });
    }
    
    // production error handler
    // no stacktraces leaked to user
    app.use(function(err, req, res, next) {
      res.status(err.status || 500);
      res.render('error', {
        message: err.message,
        error: {}
      });
    });
    
    
    module.exports = app;
     

    查看./bin/www文件。

    #!/usr/bin/env node
    
    /**
     * Module dependencies.
     */
    
    var app = require('../app');
    var debug = require('debug')('vlan:server');
    var http = require('http');
    
    /**
     * Get port from environment and store in Express.
     */
    
    /*
    * 定義啟動端口
    * */
    var port = normalizePort(process.env.PORT || '8080');
    app.set('port', port);
    
    /**
     * Create HTTP server.
     */
    
    var server = http.createServer(app);
    
    /**
     * Listen on provided port, on all network interfaces.
     */
    
    server.listen(port);
    server.on('error', onError);
    server.on('listening', onListening);
    
    /**
     * Normalize a port into a number, string, or false.
     */
    
    function normalizePort(val) {
      var port = parseInt(val, 10);
    
      if (isNaN(port)) {
        // named pipe
        return val;
      }
    
      if (port >= 0) {
        // port number
        return port;
      }
    
      return false;
    }
    
    /**
     * Event listener for HTTP server "error" event.
     */
    
    function onError(error) {
      if (error.syscall !== 'listen') {
        throw error;
      }
    
      var bind = typeof port === 'string'
        ? 'Pipe ' + port
        : 'Port ' + port;
    
      // handle specific listen errors with friendly messages
      switch (error.code) {
        case 'EACCES':
          console.error(bind + ' requires elevated privileges');
          process.exit(1);
          break;
        case 'EADDRINUSE':
          console.error(bind + ' is already in use');
          process.exit(1);
          break;
        default:
          throw error;
      }
    }
    
    /**
     * Event listener for HTTP server "listening" event.
     */
    
    function onListening() {
      var addr = server.address();
      var bind = typeof addr === 'string'
        ? 'pipe ' + addr
        : 'port ' + addr.port;
      debug('Listening on ' + bind);
    }

    4.路由功能

    首先在項目目錄里創建一個controller即控制層

    在controller下新建index.js 這里面我們簡單的返回一個title來進行測試

    exports.index = function (){
        return {title: "歡迎來到我的首頁!"};
    };

    接下來我們在路由層里面設置index.js

    var express = require('express');
    var router = express.Router();
    
    // 引入c層的各個控制器
    var indexController = require("../controller/index");
    
    /* GET index page. */
    router.get('/index', function(req, res, next) {
      res.render('index', indexController.index());
    });
    
    module.exports = router;

    然后對V層的index.html模板進行修改

    <!DOCTYPE html>
    <html>
      <head>
        <title><%= title %></title>
        <link rel='stylesheet' href='/css/style.css' />
      </head>
      <body>
        <h1><%= title %></h1>
        <p>Welcome to <%= title %></p>
      </body>
    </html>

    這里我們采用的是ejs模板,所以要嚴格按照ejs的模板規則,當然也可以用其他模版引擎,比如jade等等

    另外我對靜態資源目錄進行了一些小修改,主要是個人習慣,

    原本的靜態資源目錄:

    4_thumb1

    改過后的靜態資源目錄:

    image_thumb1

    所以頁面引用的時候要稍微注意下,當資源加載的時候,默認從public下查找,所以引用的路徑:<link rel='stylesheet' href='/css/style.css' />

    一切大功告成,接下來我們可以啟動服務,來訪問我們的測試頁面,終端可以用npm start進行訪問,我用的webstorm直接debug就可以看到效果

    image_thumb3

    image_thumb5

    可以看到我們可以成功訪問頁面,並且css也成功加載。

    到這為止,其實一個簡單的express的搭建就已經完成,感覺很簡單,對不對? 只要整站的架構思維理順,一切都能迎刃而解!

    5.完整的項目

    接下來我們做一個簡單的登錄注冊,使用MongoDB做為我們的數據庫。

    做之前我們先來規划一下思路:

    ①新建兩個頁面,一個登錄頁(login.html), 登錄成功后的跳轉頁(home.html)

    ②照葫蘆畫瓢,按照剛剛的順序,先跑通這兩個頁面

    ③寫登錄和注冊的接口,這個時候我們就需要用到數據庫了,注冊之前先進行查詢,數據庫里是否有這個用戶名,然后是登錄,賬戶與密碼是否匹配

    ④前端的注冊和登錄的功能實現

    大體上就這個思路,讓我們來一步步進行。

    1.創建登錄頁以及登錄成功頁

    在路由層的index.js里面新增代碼:

    var loginController = require("../controller/login");
    
    /* GET login page. */
    router.get('/login', function(req, res, next) {
      res.render('login', loginController.login());
    });

    C層的login.js:

    exports.login = function (){
        return {title: "這里是登錄頁"};
    };

    V層的login.html:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title><%=title%></title>
        <script></script>
        <link rel="stylesheet" href="/css/login.css"/>
    </head>
    <body>
    <h1>~<%=title%>~</h1>
    <form id="myForm">
        帳號:<input type="text" name="username"/><br/><br/>
        密碼:<input type="password" name="password"/><br/><br/>
        <input type="button" value="注冊" node-type="register" /> &nbsp; <input type="button" value="登錄" node-type="submit"/>
    </form>
    <script src="/js/jquery.js"></script>
    <script src="/js/login.js"></script>
    </body>
    </html>

    樣式簡單的寫寫就可以啦~

    重啟服務,訪問login:

    image_thumb8

    image_thumb11

    全部OK,接下來是home頁面,由於home頁是登陸成功頁,所以我們做個假的帳號進行測試:

    路由層的index.js添加訪問home的方法:

    /* GET home page. */
    router.get('/home', function(req, res, next) {
      res.render('home', {
        title: "登錄成功頁",
        username: "測試帳號"
      });
    });

    V層的home.html:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>恭喜~<%= title %>~恭喜</title>
        <link rel="stylesheet" href="/css/home.css"/>
    </head>
    <body>
    <h1>尊敬的<%= username %>,歡迎您!</h1>
    <a class="logout" href="/logout">退出登錄</a>
    </body>
    </html>

    同樣樣式簡單寫寫就可以了

    重啟服務,訪問home頁:

    image_thumb13

    image_thumb16

    可以看到訪問成功,這里其實我們應該有一個退出登錄的頁面,我就不再單寫一個頁面了,退出登陸后直接跳轉到登錄頁就可以了~~~

    路由層曾加一個訪問logout的方法就可以:

    /*GET logout page.*/
    router.get('/logout', function (req, res){
      res.redirect("/login");
    });

    重啟服務后我們點退出登錄按鈕,可以看到直接跳轉到了登錄頁~

    image_thumb19

    好了,接下來該實現前端登錄注冊的功能了,這里先來寫登錄的功能,我們先來規定下接口的格式:{“code”: 200, “msg”: “登錄成功”}

    code等於200的時候,為登錄成功,201為登錄失敗。我們先用get方式來測試頁面,跑通頁面以后再用post方式提交

    在C層新建getLogin.js:

    var userList = {};
    
    exports.getLogin = function (req, res){
        res.send({
            code:200,
            msg: "登錄成功(本條消息來自后台)"
        });
        userList = {
            username: req.param("username")
        }
    };
    
    exports.userList = function (){
        return userList;
    };

    userList用來存儲登錄時所填寫的用戶信息(可以理解成一個數據庫,從數據庫里讀取內容)

    在路由層的index.js做如下改動:

    var getLoginController = require("../controller/getLogin");
    
    /* GET home page. */
    router.get('/home', function (req, res){
      res.render('home', {
          title: "登錄成功頁",
          username: getLoginController.userList().username
      });
    });
    
    router.get('/userData', getLoginController.getLogin);

    userData即前端的接口地址

    現在就可以來寫寫前端登錄的功能了:

    ;(function ($){
        var foo = function (options){
            var self = this;
                self.options = $.extend({
                    parent: $("#myForm"),
                    register: $("[node-type=register]"),
                    submit: $("[node-type=submit]")
                }, options);
            self.bindEvent();
        };
    
        foo.prototype = {
            bindEvent: function (){
                var self = this;
                self.login();
            },
            login: function (){
                var self = this,
                    parent = self.options.parent,
                    submit = self.options.submit;
    
    
                submit.on("click", function (){
                    var jqXML = $.ajax({
                        url: "/userData",
                        dataType: "json",
                        type: "get",
                        data: parent.serialize()
                    });
    
                    jqXML.done(function (data){
                        if(data.code == 200){
                            location.href = "/home";
                        }
                    });
                });
            }
        };
    
        new foo();
    })(jQuery);

    簡單的get提交方式,記得在login.html頁面上引用~

    一切OK,重啟服務,訪問login頁面

    image_thumb23

    輸入用戶名以后點擊登錄:

    image_thumb29

    image_thumb32

    恭喜!訪問成功!

    下一節我們將跟數據庫連接起來,做一個真正意義上的登錄注冊。

     

  • 免責聲明!

    本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



     
    粵ICP備18138465號   © 2018-2025 CODEPRJ.COM