zoukankan      html  css  js  c++  java
  • express 应用创建及app.js详解

    #1 express 应用创建

    1、安装node.js (自行百度)

    2、npm install express -g 

    3、全局安装express生成器 express-generator 

      npm install express-generator -g 

    4、查看 express 版本,可以检查生成器 express-generator  是否安装成功

       express -v 

    5、(可选)查看express 所有帮助指令及用法

      express -h

    6、cd 进入指定目录 workspace(任意命名)--------------这是系统cmd指令,不是node指令

    7、在指定目录 workspace(任意命名) 创建项目 nodejs-demo(任意命名)

      express -e nodejs-demo

    8、由当前目录 workspace(任意命名)  进入 项目目录 nodejs-demo(任意命名)--------------这是系统cmd指令,不是node指令

      cd workspace

    9、安装依赖

      npm install 

    10、启动项目

      npm start

    #2 目录结构# 接下来,我们详细看一下Express4项目的结构、配置和使用。

    bin, 存放启动项目的脚本文件

    node_modules, 存放所有的项目依赖库。

    public,静态文件(css,js,img)

    routes,路由文件(MVC中的C,controller)

    views,页面文件(Ejs模板)

    package.json,项目依赖配置及开发者信息

    app.js,应用核心配置文件

    输入图片说明

    #3 package.json项目配置# package.json用于项目依赖配置及开发者信息,scripts属性是用于定义操作命令的,可以非常方便的增加启动命令,比如默认的start,用npm start代表执行node ./bin/www命令。查看package.json文件。

    {
      "name": "express4-demo",
      "version": "0.0.0",
      "private": true,
      "scripts": {
        "start": "node ./bin/www"
      },
      "dependencies": {
        "body-parser": "~1.10.2",
        "cookie-parser": "~1.3.3",
        "debug": "~2.1.1",
        "ejs": "~2.2.3",
        "express": "~4.11.1",
        "morgan": "~1.5.1",
        "serve-favicon": "~2.2.0"
      }
    }
    

    #4 app.js核心文件# 从Express3.x升级到Express4.x,主要的变化就在app.js文件中。查看app.js文件,我已经增加注释说明。

    // 加载依赖库,原来这个类库都封装在connect中,现在需地注单独加载
    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 app = express();
    
    // 定义EJS模板引擎和模板文件位置,也可以使用jade或其他模型引擎
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'ejs');
    
    // 定义icon图标
    app.use(favicon(__dirname + '/public/favicon.ico'));
    // 定义日志和输出级别
    app.use(logger('dev'));
    // 定义数据解析器
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: false }));
    // 定义cookie解析器
    app.use(cookieParser());
    // 定义静态文件目录
    app.use(express.static(path.join(__dirname, 'public')));
    
    // 匹配路径和路由
    app.use('/', routes);
    //app.use('/users', users);
    
    // 404错误处理
    app.use(function(req, res, next) {
        var err = new Error('Not Found');
        err.status = 404;
        next(err);
    });
    
    // 开发环境,500错误处理和错误堆栈跟踪
    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
            });
        });
    }
    
    // 生产环境,500错误处理
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: {}
        });
    });
    
    // 输出模型app
    module.exports = app;
    

    我们看到在app.js中,原来调用connect库的部分都被其他的库所代替,serve-favicon、morgan、cookie-parser、body-parser,默认项目中,只用到了最基本的几个库,还没有其他需要替换的库,在本文最后有详细列出。

    另外,原来用于项目启动代码也被移到./bin/www的文件,www文件也是一个node的脚本,用于分离配置和启动程序。查看./bin/www文件。

    #!/usr/bin/env node   
    
    /**
     * 依赖加载
     */
    var app = require('../app');
    var debug = require('debug')('nodejs-demo:server');
    var http = require('http');
    
    /**
     * 定义启动端口
     */
    var port = normalizePort(process.env.PORT || '3000');
    app.set('port', port);
    
    /**
     * 创建HTTP服务器实例
     */
    var server = http.createServer(app);
    
    /**
     * 启动网络服务监听端口
     */
    server.listen(port);
    server.on('error', onError);
    server.on('listening', onListening);
    
    /**
     * 端口标准化函数
     */
    function normalizePort(val) {
      var port = parseInt(val, 10);
      if (isNaN(port)) {
        return val;
      }
      if (port >= 0) {
        return port;
      }
      return false;
    }
    
    /**
     * HTTP异常事件处理函数
     */
    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;
      }
    }
    
    /**
     * 事件绑定函数
     */
    function onListening() {
      var addr = server.address();
      var bind = typeof addr === 'string'
        ? 'pipe ' + addr
        : 'port ' + addr.port;
      debug('Listening on ' + bind);
    }
    

    #5 Bootstrap界面框架# 创建Bootstrap界面框架,直接在index.ejs文件上面做修改。可以手动下载Bootstrap库放到项目中对应的位置引用,也可以通过bower来管理前端的Javascript库,参考文章 bower解决js的依赖管理另外还可以直接使用免费的CDN源加载Bootstrap的css和js文件。下面我就直接使用bower来管理前端的JavaScript库的方式。编辑views/index.ejs文件:

    <!DOCTYPE html>
    <html lang="zh-CN">
      <head>
        <title><%= title %></title>
        <link rel="stylesheet" href="/bower_components/bootstrap/dist/css/bootstrap.min.css">
        <link rel='stylesheet' href='/stylesheets/style.css' />
      </head>
      <body>
        <div class="well jumbotron">
          <h1><%= title %></h1>
          <p>This is a simple hero unit, a simple jumbotron-style component for calling extra attention to featured content or information.</p>
          <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
        </div>
        <script src="/bower_components/jquery/dist/jquery.min.js"></script>
        <script src="/bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
      </body>
    </html>
    

    效果如下,已经加入了bootstrap的样式了。

    输入图片说明

    接下来,我们把index.ejs页面切分成3个部分:header.ejs, index.ejs, footer.ejs,用于网站页面的模块化

    header.ejs, 为页面的头部区域

    index.ejs, 为内容显示区域

    footer.ejs, 为页面底部区域

    编辑header.ejs:

    <!DOCTYPE html>
    <html lang="zh-CN">
      <head>
        <title><%= title %></title>
        <link rel="stylesheet" href="/bower_components/bootstrap/dist/css/bootstrap.min.css">
        <link rel='stylesheet' href='/stylesheets/style.css' />
      </head>
      <body>
    

    编辑footer.ejs:

        <script src="/bower_components/jquery/dist/jquery.min.js"></script>
        <script src="/bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
      </body>
    </html>
    

    编辑index.ejs:

    <% include header.ejs %>
    
    <div class="well jumbotron">
    <h1><%= title %></h1>
    <p>This is a simple hero unit, a simple jumbotron-style component for calling extra attention to featured content or information.</p>
    <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
    </div>
    
    <% include footer.ejs %>
    

    把页表和页底的代码分离后,让index.ejs页面的核心代码更少,更容易维护。

    #6 路由功能# 路由功能,是Express4以后全面改版的功能。在应用程序加载隐含路由中间件,不用担心在中间件被装载相对于路由器中间件的顺序。定义路由的方式是不变的,路由系统中增加2个新的功能。

    app.route()函数,创建可链接的途径处理程序的路由路径。

    express.Router类,创建模块化安装路径的处理程序。

    app.route方法会返回一个Route实例,它可以继续使用所有的HTTP方法,包括get,post,all,put,delete,head等。

    app.route('/users')
      .get(function(req, res, next) {})
      .post(function(req, res, next) {})
    

    express.Router类,则可以帮助我们更好的组织代码结构。在app.js文件中,定义了app.use(‘/’, routes); routes是指向了routes目录下的index.js文件,./routes/index.js文件中,express.Router被定义使用,路径/*处理都会由routes/index.js文件里的Router来处理。如果我们要管理不同的路径,那么可以直接配置为多个不同的Router。

    app.use('/user', require('./routes/user').user);
    app.use('/admin', require('./routes/admin').admin);
    app.use('/', require('./routes'));
    

    #7 Ejs模板使用# 让ejs模板文件,使用扩展名为html的文件。修改:app.js

    app.engine('.html', ejs.__express);
    app.set('view engine', 'html');
    // app.set('view engine', 'ejs');
    

    修改后,ejs变量没有定义,supervisor的程序会一直报错

    ReferenceError: ejs is not defined
    at Object. (D:workspaceprojectnodejs-demoapp.js:17:21)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:901:3
    DEBUG: Program node app.js exited with code 8
    

    在app.js中增加ejs变量:

    var express = require('express')
    , routes = require('./routes')
    , user = require('./routes/user')
    , http = require('http')
    , path = require('path')
    , ejs = require('ejs');
    

    #8 Session使用# session这个问题,其实是涉及到服务器的底层处理方式。像Java的web服务器,是多线程调用模型。每用户请求会打开一个线程,每个线程在内容中维护着用户的状态。

    像PHP的web服务器,是交行CGI的程序处理,CGI是无状态的,所以一般用cookie在客户的浏览器是维护用户的状态。但cookie在客户端维护的信息是不够的,所以CGI应用要模仿用户session,就需要在服务器端生成一个session文件存储起来,让原本无状态的CGI应用,通过中间文件的方式,达到session的效果。

    Nodejs的web服务器,也是CGI的程序无状态的,与PHP不同的地方在于,单线程应用,所有请求都是异步响应,通过callback方式返回数据。如果我们想保存session数据,也是需要找到一个存储,通过文件存储,redis,Mongdb都可以。

    接下来,我将演示如何通过mongodb来保存session,并实现登陆后用户对象传递。

    app.js文件:

    var express = require('express')
    , routes = require('./routes')
    , user = require('./routes/user')
    , http = require('http')
    , path = require('path')
    , ejs = require('ejs')
    , SessionStore = require("session-mongoose")(express);
    
    var store = new SessionStore({
        url: "mongodb://localhost/session",
        interval: 120000
    });
    
    ....
    app.use(express.favicon());
    app.use(express.logger('dev'));
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(express.cookieParser());
    app.use(express.cookieSession({secret : 'fens.me'}));
    
    app.use(express.session({
        secret : 'fens.me',
        store: store,
        cookie: { maxAge: 900000 }
    }));
    
    app.use(function(req, res, next){
        res.locals.user = req.session.user;
        next();
    });
    app.use(app.router);
    app.use(express.static(path.join(__dirname, 'public')));
    

    注:app.js文件有顺序要求,一定要注意!!!

    安装session-mongoose依赖库:

    D:workspaceprojectnodejs-demo>npm install session-mongoose
    D:workspaceprojectnodejs-demonode_modulessession-mongoosenode_modulesmongoosenode_modulesmongodbnode_modulesbson>node "D:toolkitnodejsnode_modulesnpmbinnode-gyp-bin\....node_modulesnode-gypbinnode-gyp.js" rebuild
    C:Program Files (x86)MSBuildMicrosoft.Cppv4.0Microsoft.Cpp.InvalidPlatform.Targets(23,7): error MSB8007: 项目“kerberos.vcxproj”的平台无效。平台为“x64”。您会看到此消息的可能原因是,您尝试在没有解决方案文件的情况下生成项目,并且为
    oosenode_modulesmongoosenode_modulesmongodbnode_modulesbsonbuildbson.vcxproj]
    session-mongoose@0.2.2 node_modulessession-mongoose
    └── mongoose@3.6.10 (mpath@0.1.1, ms@0.1.0, hooks@0.2.1, sliced@0.0.3, muri@0.3.1, mpromise@0.2.1, mongodb@1.3.3)
    

    安装有错误但是没关系。访问:http://localhost:3000/login,正常

    修改routes/index.js文件,exports.doLogin方法:

    exports.doLogin = function(req, res){
        var user={
            username:'admin',
            password:'admin'
        }
        if(req.body.username===user.username && req.body.password===user.password){
            req.session.user=user;
            return res.redirect('/home');
        } else {
            return res.redirect('/login');
        }
    };
    

    exports.logout方法:

    exports.logout = function(req, res){
        req.session.user=null;
        res.redirect('/');
    };
    

    exports.home方法:

    exports.home = function(req, res){
        res.render('home', { title: 'Home'});
    };
    

    这个时候session已经起作用了,exports.home的user显示传值已经被去掉了。 是通过app.js中app.use的res.locals变量,通过框架进行的赋值。

    app.use(function(req, res, next){
        res.locals.user = req.session.user;
        next();
    });
    

    注:这个session是express3.0的写法,与express2.x是不一样的。原理是在框架内每次赋值,把我们刚才手动传值的过程,让框架去完成了

      

  • 相关阅读:
    Median Value
    237. Delete Node in a Linked List
    206. Reverse Linked List
    160. Intersection of Two Linked Lists
    83. Remove Duplicates from Sorted List
    21. Merge Two Sorted Lists
    477. Total Hamming Distance
    421. Maximum XOR of Two Numbers in an Array
    397. Integer Replacement
    318. Maximum Product of Word Lengths
  • 原文地址:https://www.cnblogs.com/qinlongqiang/p/11444882.html
Copyright © 2011-2022 走看看