Node.js 学习笔记之五:使用 Express 框架

这部分示例将通过你好,Express留言板学生管理三个应用的实现来演示Express框架的基本使用。首先来搭建该示例项目的基本脚手架,为此我们需要在code目录下执行mkdir 07_Expressjs命令来创建用于存放这一组示例的目录,并执行一下步骤:

  1. code/07_Expressjs目录下执行npm init --yes命令来初始化本示例项目。

  2. code/07_Expressjs目录下执行npm install express body-parser sqlite3 mongodb async art-template express-art-template --save命令来安装本示例所要用到的扩展包。

  3. code/07_Expressjs目录下执行mkdir views命令来创建用于存放模板文件的目录。

  4. code/07_Expressjs目录下执行mkdir public命令创建public目录,并进入到该目录中,执行mkdir DB css js img命令来创建用于存放相应类型资源的目录。

  5. code/07_Expressjs目录下执行touch index.js命令,创建本示例的程序入口文件,具体代码如下:

    const path = require('path')
    const express = require('express')
    const bodyParser =require('body-parser')
    const router = require(path.join(__dirname, 'router'))
    const app = express()
    
    // 配置public目录
    app.use('/public/', express.static(path.join(__dirname, 'public')))
    
    //配置body-parser中间件`,以便获取post请求数据。`
    app.use(bodyParser.urlencoded({extended : false}));
    app.use(bodyParser.json());
    
    // 配置模板引擎为art-template
    app.engine('htm', require('express-art-template'))
    app.set('views', path.join(__dirname, 'views'))
    app.set('view engine', 'art')
    
    // 调用路由表函数
    app.(router)
    
    // 监听8080端口
    app.listen(8080, function(){
        console.log('请访问http://localhost:8080/,按Ctrl+C终止服务!')
    })
    
  6. code/07_Expressjs目录下执行touch router.js命令,创建本示例的程序路由文件,具体代码如下:

    const path = require('path')
    const express = require('express')
    const sayHello = require(path.join(__dirname, 'sayHello'))
    const student = require(path.join(__dirname, 'student'))
    const board = require(path.join(__dirname, 'board'))
    
    const router = express.Router()
    
    // Hello,Express!
    sayHello(router)
    // 学生管理
    student(router)
    // 留言板
    board(router)
    
    module.exports = router
    
  7. code/07_Expressjs目录下执行touch baseTpl.js命令,创建该项目的基础模版文件,并在其中输入以下代码:

     <!DOCTYPE html>
     <html lang="zh-CN">
         <head>
             <meta charset="utf-8">
             <meta http-equiv="X-UA-Compatible" content="IE=edge">
             <meta name="viewport" content="width=device-width, initial-scale=1">
             <meta name="description" content="">
             <meta name="author" content="">
    
             <!-- Bootstrap CSS -->
             <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    
             <!-- 自定义 CSS -->
             <link href="/public/css/main.css" rel="stylesheet">
    
             <title>Express使用示例</title>
         </head>
         <body>
             <div class="container">
                 <!-- 导航栏部分开始 -->
                 <nav class="navbar navbar-default">
                     <div class="container-fluid">
                         <div class="navbar-header">
                             <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                                 <span class="sr-only">切换导航栏</span>
                                 <span class="icon-bar"></span>
                                 <span class="icon-bar"></span>
                                 <span class="icon-bar"></span>
                             </button>
                             <a class="navbar-brand" href="#">Express使用示例</a>
                         </div>
                         {{ block 'navbar' }}
                         {{ /block }}
                     </div>
                 </nav>
                 <!-- 导航栏部分结束 -->
                 <!-- 主体部分开始 -->
                 {{ block 'main' }}
                 {{ /block }}
                 <!-- 主体部分结束 -->
    
             </div>
             <!-- Bootstrap的核心JavaScript
             ================================================== -->
             <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
             <script> window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')</script>
             <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
         </body>
     </html>
    
  8. code/07_Expressjs/public/css/目录创建一个名为main.css的样式文件,内容如下:

    body {
        padding-top: 10px;
    }
    

下面,我们要在这个脚手架上逐一来创建之前所说的三个应用示例。

1. 你好,Express

这个应用示例主要用于示范如何用Express框架来创建一个 Web 页面,并使用art-template模板引擎。其主要步骤如下:

  1. code/07_Expressjs/public/img/目录下放置一张Express官网首页的截图,将其命名为express.jpeg

  2. code/07_Expressjs/views/目录创建一个名为hello.htm的模版文件,内容如下:

    {{ extend './baseTpl.art' }}
    
    {{ block 'navbar' }}
    <div id="navbar" class="collapse navbar-collapse">
        <ul class="nav navbar-nav">
            <li class="active"><a href="/">你好,Express!</a></li>
            <li><a href="/student">学生管理</a></li>
            <li><a href="/board">留言板</a></li>
        </ul>
    </div>
    {{ /block }}
    
    {{ block 'main' }}
    <div class="jumbotron">
        <h1>你好,{{ name }}!</h1>
        <img src="/public/img/express.jpeg" class="img-responsive">
    </div>
    {{ /block }}
    
  3. code/07_Expressjs目录下执行mkdir sayHello命令来创建该应用的目录,并在其中创建一个名为index.js的脚本文件,内容如下:

    module.exports = function(app) {
        app.get('/', function (req, res) {
            res.render('hello.htm', {name : 'Express'})
        })
    }
    
  4. 保存所有文件后,在code/07_Expressjs目录下执行node index.js命令,结果如下:

2. 学生管理

这个应用示例主要用于演示如何用Express框架实现学生管理系统,并使用SQLite3作为数据库,其具体步骤如下:

  1. code/07_Expressjs/views/目录创建一个名为student.htm的模版文件,内容如下:

    {{ extend './baseTpl.art' }}
    
    {{ block 'navbar' }}
    <div id="navbar" class="collapse navbar-collapse">
        <ul class="nav navbar-nav">
            <li><a href="/">你好,Express!</a></li>
            <li class="active"><a href="/student">学生管理</a></li>
            <li><a href="/board">留言板</a></li>
        </ul>
    </div>
    {{ /block }}
    
    {{ block 'main' }}
    <div class="jumbotron">
        <h2>学生信息表</h2>
        <a class="btn btn-success" href="/student/add">添加学生</a>
        <table class="table table-striped">
            <tr>
                <th>姓名</th>
                <th>年龄</th>
                <th>性别</th>
                <th>爱好</th>
                <th>操作</th>
            </tr>
            {{ each db }}
            <tr>
                <td>{{ $value.name }} </td>
                <td>{{ $value.age }} </td>
                <td>{{ $value.sex }} </td>
                <td>{{ $value.items }}</td>
                <td>
                    <a href="/student/edit?name={{ $value.name}}">编辑</a>
                    <a href="/student/delete?name={{ $value.name}}">删除</a>
                </td>
            </tr>
            {{ /each }}
        </table>
    </div>
    {{ /block }}
    
  2. code/07_Expressjs/views/目录创建一个名为add.htm的模版文件,内容如下:

    {{ extend './baseTpl.art' }}
    
    {{ block 'navbar' }}
    <div id="navbar" class="collapse navbar-collapse">
        <ul class="nav navbar-nav">
            <li><a href="/">你好,Express!</a></li>
            <li class="active"><a href="/student">学生管理</a></li>
            <li><a href="/board">留言板</a></li>
        </ul>
    </div>
    {{ /block }}
    
    {{ block 'main' }}
    <div class="jumbotron">
        <h2>注册新学生:</h2>
        <form action="/student/add" method="POST" class="form-horizontal" role="form">
            <div class="form-group">
                <label for="firstname" class="col-sm-2 control-label">姓名:</label>
                <div class="col-sm-10">
                <input type="text" class="form-control" name="name" placeholder="请输入名字">
                </div>
            </div>
            <div class="form-group">
                <label for="lastname" class="col-sm-2 control-label">年龄:</label>
                <div class="col-sm-10">
                <input type="text" class="form-control" name="age" placeholder="请输入年龄">
                </div>
            </div>
            <div class="form-group">
                <label for="lastname" class="col-sm-2 control-label">性别:</label>
                <div class="col-sm-10">
                <input type="text" class="form-control" name="sex" placeholder="请输入性别">
                </div>
            </div>
            <div class="form-group">
                <label for="lastname" class="col-sm-2 control-label">爱好:</label>
                <div class="col-sm-10">
                <input type="text" class="form-control" name="items" placeholder="请输入爱好">
                </div>
            </div>
            <div class="form-group">
                <div class="col-sm-offset-2 col-sm-10">
                <button type="submit" class="btn btn-default">加入</button>
                </div>
            </div>
        </form>
    </div>
    {{ /block }}
    
  3. code/07_Expressjs/views/目录创建一个名为edit.htm的模版文件,内容如下:

    {{ extend './baseTpl.art' }}
    
    {{ block 'navbar' }}
    <div id="navbar" class="collapse navbar-collapse">
        <ul class="nav navbar-nav">
            <li><a href="/">你好,Express!</a></li>
            <li class="active"><a href="/student">学生管理</a></li>
            <li><a href="/board">留言板</a></li>
        </ul>
    </div>
    {{ /block }}
    
    {{ block 'main' }}
    <div class="jumbotron">
        <h2>编辑 {{ name }} 的信息:</h2>
        <form action="/student/edit" method="POST" class="form-horizontal" role="form">
            <div class="form-group">
                <label for="firstname" class="col-sm-2 control-label">姓名:</label>
                <div class="col-sm-10">
                <input type="text" class="form-control" name="name" value="{{ name }}" placeholder="请输入名字">
                </div>
            </div>
            <div class="form-group">
                <label for="lastname" class="col-sm-2 control-label">年龄:</label>
                <div class="col-sm-10">
                <input type="text" class="form-control" name="age" value="{{ age }}" placeholder="请输入年龄">
                </div>
            </div>
            <div class="form-group">
                <label for="lastname" class="col-sm-2 control-label">性别:</label>
                <div class="col-sm-10">
                <input type="text" class="form-control" name="sex" value="{{ sex }}" placeholder="请输入性别">
                </div>
            </div>
            <div class="form-group">
                <label for="lastname" class="col-sm-2 control-label">爱好:</label>
                <div class="col-sm-10">
                <input type="text" class="form-control" name="items" value="{{ items }}" placeholder="请输入爱好">
                </div>
            </div>
            <div class="form-group">
                <div class="col-sm-offset-2 col-sm-10">
                <button type="submit" class="btn btn-default">更新数据</button>
                </div>
            </div>
        </form>
    </div>
    {{ /block }}
    
  4. code/07_Expressjs目录下执行mkdir student命令来创建该应用的目录,并在其中创建一个名为index.jsSqlite.js的两个脚本文件,内容如下:

    • index.js
    const fs = require('fs')
    const path = require('path')
    const async = require('async')
    const SqliteDB = require(path.join(__dirname,'Sqlite'))
    const dbPath = path.join(__dirname, '../public/DB/studentsDB.db')
    
    // 配置数据库
    if ( !fs.existsSync(dbPath) ) {
        const studentsDB = new SqliteDB(dbPath)
    
        async.series([
            function(callback) {
                const createTableSql = `
                create table if not exists STUDENT_TABLE (
                    name  TEXT,
                    age   TEXT,
                    sex   TEXT,
                    items TEXT
                )`
                studentsDB.createTable(createTableSql)
                callback()
            },
    
            function(callback) {
                const insertTileSql = `
                    insert into STUDENT_TABLE
                        (name, age, sex, items)
                        values(?, ?, ?, ?)`
                const arr = [
                    ['凌杰', '24', '男', '看书、看电影、旅游'],
                    ['蔓儿', '25', '女', '看书、看电影、写作'],
                    ['张语', '32', '女', '看书、旅游、绘画']
                ]
                studentsDB.insertData(insertTileSql, arr)  
                callback()
            }
        ])
        studentsDB.close()
    }
    
    module.exports = function(app) {
        app.get('/student', function (req, res) {
            const studentsDB = new SqliteDB(dbPath)
    
            const querySql = 'select * from STUDENT_TABLE'
            studentsDB.queryData(querySql, function(data) {
                if ( data === null ) {
                    return console.log('数据查询错误!')
                }
                res.render('student.htm', { db : data })
            })
    
            studentsDB.close()
        })
    
        app.get('/student/add', function  (req, res) {
            res.render('add.htm', { })
        })
    
        app.post('/student/add', function (req, res) {
            const studentsDB = new SqliteDB(dbPath)
    
            const arr = [
                [req.body['name'],req.body['age'],req.body['sex'],req.body['items']]
            ]
    
            const insertTileSql = `
                insert into STUDENT_TABLE
                    (name, age, sex, items)
                    values(?, ?, ?, ?)`
            studentsDB.insertData(insertTileSql, arr)
    
            studentsDB.close()
            res.redirect('/student')
        })
    
        app.get('/student/delete', function (req, res) {
            const studentsDB = new SqliteDB(dbPath)
    
            const deleteSql = `
                delete from STUDENT_TABLE where name = '`
                + req.query['name']
                + `'`
            studentsDB.executeSql(deleteSql)
    
            studentsDB.close()
            res.redirect('/student')
        })
    
        app.get('/student/edit', function (req, res) {
            const studentsDB = new SqliteDB(dbPath)
    
            const querySql = `
                select * from STUDENT_TABLE where name = '`
                + req.query['name']
                + `'`
            studentsDB.queryData(querySql, function(data) {
                if ( data === null ) {
                    return console.log('数据查询错误!')
                }
                res.render('edit.htm', {
                    name  : data[0]['name'],
                    age   : data[0]['age'],
                    sex   : data[0]['sex'],
                    items : data[0]['items']
                })
            })
    
            studentsDB.close()
        })
    
        app.post('/student/edit', function (req, res) {
            const studentsDB = new SqliteDB(dbPath)
    
            const updateSql =
                `update STUDENT_TABLE set name = '`
                + req.body['name']
                + `', `
                + `age = '`
                + req.body['age']
                + `', `
                + `sex = '`
                + req.body['sex']
                + `', `
                + `items = '`
                + req.body['items']
                + `' `
                + ` where name = '`
                + req.body['name']
                + `'`
    
            studentsDB.executeSql(updateSql)
    
            studentsDB.close()
            res.redirect('/student')
        })
    }
    
    • Sqlite.js
    const fs = require('fs')
    const sqlite3 = require('sqlite3').verbose()
    
    class SqliteDB {
        constructor(file) {
            this.db = new sqlite3.Database(file)
            const db_exist = fs.existsSync(file)
    
            if ( !db_exist ) {
                fs.openSync(file, 'w')
            }
        }
    
        createTable(sql) {
            this.db.serialize(function() {
                this.run(sql, function(err) {
                    if( err !== null ) {
                        return console.error('错误信息:' + err.message)
                    }
                })
            })
        }
    
        insertData(sql, objects) {
            this.db.serialize(function() {
                const stmt = this.prepare(sql)
                for ( const i = 0; i < objects.length; ++i ) {
                    stmt.run(objects[i])
                }
    
                stmt.finalize()
            })
        }
    
        queryData(sql, callback) {
            this.db.all(sql, function(err, rows) {
                if( err !== null ) {
                    return console.error('错误信息:' + err.message)
                }
    
                if( callback ) {
                    callback(rows)
                }
            })
        }
    
        executeSql(sql) {
            this.db.run(sql, function(err) {
                if( err !== null ) {
                    return console.error('错误信息:' + err.message)
                }
            })
        }
    
        close() {
            this.db.close()
        }
    }
    
    module.exports = SqliteDB
    
  5. 保存所有文件后,在code/07_Expressjs目录下执行node index.js命令,结果如下:

3. 留言板

这个应用示例主要用于演示如何用Express框架实现留言板应用,并使用MongoDB作为数据库,其具体步骤如下:

  1. code/07_Expressjs/views/目录创建一个名为board.htm的模版文件,内容如下:

    {{ extend './baseTpl.art' }}
    
    {{ block 'navbar' }}
    <div id="navbar" class="collapse navbar-collapse">
        <ul class="nav navbar-nav">
            <li><a href="/">你好,Express!</a></li>
            <li><a href="/student">学生管理</a></li>
            <li class="active"><a href="/board">留言板</a></li>
        </ul>
    </div>
    {{ /block }}
    
    {{ block 'main' }}
    <div class="jumbotron">
        <h2>留言板</h2>
        <form action="/board" method="POST" class="form-horizontal" role="form">
            <div class="form-group">
                <label for="firstname" class="col-sm-2 control-label">你的姓名:</label>
                <div class="col-sm-10">
                <input type="text" class="form-control" name="name" placeholder="请输入名字">
                </div>
            </div>
            <div class="form-group">
                <label for="lastname" class="col-sm-2 control-label">留言信息:</label>
                <div class="col-sm-10">
                <textarea class="form-control" name="message" placeholder="请输入留言"></textarea>
                </div>
            </div>
            <div class="form-group">
                <div class="col-sm-offset-2 col-sm-10">
                <button type="submit" class="btn btn-default">提交留言</button>
                </div>
            </div>
        </form>
    </div>
    <div class="jumbotron">
        <h3>最新留言({{ num }} 则):</h3>
        <table class="table">
            {{ each db }}
            <tr>
                <td>{{ $value.name }} </td>
                <td>{{ $value.message }} </td>
                <td>{{ $value.time }}</td>
            </tr>
            {{ /each }}
        </table>
    </div>
    {{ /block }}
    
  2. code/07_Expressjs目录下执行mkdir board命令来创建该应用的目录,并在其中创建一个名为index.js的脚本文件,内容如下:

    const MongoClient = require('mongodb').MongoClient
    const async = require('async')
    const server = 'mongodb://localhost:27017'
    const dbName = 'boardDB'
    const collName = 'message_table'
    const dbPath = server + '/' + dbName
    
    module.exports = function(app) {
        app.get('/board', function (req, res) {
            MongoClient.connect(dbPath, { useNewUrlParser: true },
                                                function(err, db) {
                if ( err !== null ) {
                    return console.error('错误信息:' + err.message)
                }
                const dbo = db.db(dbName)
                const collect = dbo.collection(collName)
                collect. find({}).toArray(function(err, result) {
                    if ( err !== null ) {
                        return console.error('错误信息:' + err.message)
                    }
                    const num =result.length
                    res.render('board.htm', {
                        num : num,
                        db  : result
                    })
                })
            })
        })
    
        app.post('/board', function (req, res) {
            MongoClient.connect(dbPath, { useNewUrlParser: true },
                                                function(err, db) {
                if ( err !== null ) {
                    return console.error('错误信息:' + err.message)
                }
                const dbo = db.db(dbName)
                const collect = dbo.collection(collName)
                const data = {
                    name    : req.body['name'],
                    message : req.body['message'],
                    time    : Date()
                }
                collect.insertOne(data, function(err, res) {
                    if ( err !== null ) {
                        return console.error('错误信息:' + err.message)
                    }
                })
                res.redirect('/board')
            })
        })
    }
    
  3. 保存所有文件后,在code/07_Expressjs目录下执行node index.js命令,结果如下:

posted @ 2020-09-01 11:27  凌杰  阅读(66)  评论(0编辑  收藏