express介绍及实战

2015年09月11日 王兴龙

Express介绍

  • TJ Holowaychuk
  • Connect与Express
  • SSH与MEAN.js

Express的安装

$ npm install express

$ npm install -g express-generator

Express的入口


var express = require('express')
var app = express()
app.get('/', function (req, res) {
      res.send('Hello World')
})
app.listen(3000)
    

var http = require('http');
http.createServer(function(req, res) {
     res.write('hello world');
     res.end();
}).listen(8000);
    

理解app

Express模板引擎

  • Jade
  • Handlebars
  • EJS(与UTC一致)

中间件

app.use('/public',express.static(__dirname + '/public'));
app.use(logger());
app.use(function(req, res, next){
    console.log('hello middleware');
    next();
});
app.get('/', function(req, res){
res.send('Hello World');
});

URL组成部分

http:// m.sm.cn /s ?q=周杰伦
协议 主机名 路径 查询字符串

路由

  • 将请求路由到处理他们的代码去得一种机制
  • 路由处理器是中间件
  • 支持正则表达式
  • 路由参数

一个例子

app.get('staff/:city/:name', function(req, res){
    //req.params.city
})

路由组织

  • 给路由处理器用命令函数
  • 按逻辑分组
  • 路由的命名
  • 路由参数

路由组织例子

//route.js
module.exports = function(app) {
    app.get('/', function(req, res){

    })
}

//index.js
requrie('./route.js')(app)

自动化渲染视图

添加一个foo.ejs就可以通过/foo来访问 场景:适合不需要首屏的静态模板

var autoViews = {};
var fs = require('fs');

app.use(function(req, res, next) {
    var path = req.path.toLowerCase();
    //检查缓存
    if(autoView[path]) return res.render(autoViews[path]);
    //不在缓存
    if(fs.exitsSync(__dirname + '/views' + path + '.ejs')) {
        autoViews[path] = path.repalce(/^\//, '');
        reuturn res.render(autoViews[path]);
    }
    //没发现到404
    next();
})

持久化

  • 文件持久化
  • 云持久化
  • 数据库持久化

数据库持久化

一些框架

实战:动效平台

https://github.com/mingzhi22/inspiration/tree/master

架构图

jiagoutu

路由

// 新建组件页面
app.get('/component/create', ComponentController.renderCreationPage);

// 组件类的路由
app.post('/component/create', multipartMiddleware, ComponentController.create);

app.put('...', ...);
app.delete('...', ...);

控制器

create: function(req, res) {
    var data = req.body,
        files = req.files;
    //当组件存储完成、文件上传完成,才响应
    createComponent(data, files).then(function(data) {
        //渲染页面
        //res.render('index', data.componentHistory.componentHistoryID);
        res.send(JSON.stringify(data));
    }).catch(function(e) {
        console.error(e);
        res.redirect('error');
    });
}
//创建组件、组件项
function createComponent(data, files) {
    //组件
    var component = new Component(data.name, data.categoryID, 'userid', data.remarks); //用户ID后期通过session给值
    //历史版本
    var componentHistory = new ComponentHistory(component.componentID, data.html, data.js, data.css, 'userid', data.updata); //用户ID后期通过session给值

    //首先保存到数据然,然后再保存到文件中
    return Promise.all([
            ComponentDAL.createComponent(component),
            ComponentHistoryDAL.createComponentHistory(componentHistory),
            saveFile({
                files : files,
                component : component.componentID
            })
        ]);

}

DAL层

//创建组件
function createComponent(component) {
    return new Promise(function(resolve, reject) {
        ComponentTable.create([component],function(err, data) {
            if(err) {
                console.error(err);
                reject(err);
            }else {
                console.debug('上传组件成功', JSON.stringify(data));
                resolve(JSON.stringify(data));
            }
        });

    });
}

复杂SQL

var getComponentHistoryByComponentIDSQL = 'SELECT componentHistory.componentHistoryID, componentHistory.html, componentHistory.js, componentHistory.css, component.componentID , component.name, component.remarks FROM (SELECT componentID, name, remarks FROM component WHERE component.componentID = ?) component inner join componentHistory ON componentHistory.componentID = component.componentID ORDER BY componentHistory.createTime DESC LIMIT 1';
//找到某一个组件下最新版本的组件历史
function getComponentHistoryByComponentID(componentID) {
    return new Promise(function(resolve, reject) {
        db.driver.execQuery(getComponentHistoryByComponentIDSQL,  [componentID], function(err, data) {
            if(err) {
                console.error(err);
                throw err;
            }else {
                resolve(data);
            }
        });
    });
}

日志处理:Log4Js

var log4js = require('log4js');

log4js.configure({
    appenders: [
        //控制台输出
        {
            type: 'console',
            category: "console"
        }
        ////线上打开,否则没有这个软件会报错
        //{
        //    type: "dateFile",
        //    filename: 'logs/log.log',
        //    pattern: "_yyyy-MM-dd",
        //    alwaysIncludePattern: false,
        //    category: 'dateFileLog'
        //}//日期文件格式
    ],
    replaceConsole: true,   //替换console.log
    levels:{
        dateFileLog: 'ERROR',
        console : 'DEBUG'
    }
});

var dateFileLog = log4js.getLogger('dateFileLog');

module.exports = function(app) {
    //页面请求日志,用auto的话,默认级别是WARN
    app.use(log4js.connectLogger(dateFileLog, {level:dateFileLog.level.ERROR, format:':method :url'}));
};

效果展示

下一步要做的

脚手架

拥抱ES6(2015), ES7(2016)

Class, Generator ,async

class Component extend BaseClass {
    constructor(name) {
        this.name = name;
    }
    getComponentName() {
    }
}

回顾

想实现一个基于mvc的web系统

  • templet
  • route
  • controller
  • dal
  • model

Q&A

Powered By nodePPT v1.2.3