從零開始學習Node.js例子八 使用SQLite3和MongoDB


setup.js初始化數據庫

var util = require('util');
var async = require('async');   //npm install async
var notesdb = require('./nodesdb-sqlite3');
// var notesdb = require('./notesdb-mongoose');

notesdb.connect(function(error){
    if (error) throw error;
});
notesdb.setup(function(error){
    if (error){
        util.log('ERROR ' + error);
        throw error;
    }
    async.series([   //async.series函數可以控制函數按順序執行,從而保證最后的函數在所有其他函數完成之后執行
        function(cb){
            notesdb.add("test", "testtest",
            function(error){
                if (error) util.log('ERROR ' + error);
                cb(error);
            });
        }
    ],
        function(error, results){
            if (error) util.log('ERROR ' + error);
            notesdb.disconnect(function(err){});
        }
    );
});

nodesdb-sqlite3.js

SQLite3 是一個輕量級的進程內SQL引擎
它是一個無服務器且無需配置的SQL數據庫引擎,僅僅是作為一個獨立的庫被鏈接到應用程序上

npm install sqlite3 安裝此模塊之前先在系統上安裝sqlite3庫 http://www.sqlite.org/download.html 下載

//數據庫接口庫
var util = require('util');
var sqlite3 = require('sqlite3');

sqlite3.verbose();
var db = undefined;

/*
 數據庫名是直接硬編碼的,所以當調用connect和setup函數時,當前目錄中就會生成chap06.sqlite3文件
 */

exports.connect = function(callback){
    db = new sqlite3.Database("chap06.sqlite3", sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE,
        function(err){
            if (err){
                util.log('FAIL on creating database ' + err);
                callback(err);
            } else {
                callback(null);
            }
        });
}

//此處的disconnect函數是空的
exports.disconnect = function(callback){
    callback(null);
}

exports.setup = function(callback){
    db.run("CREATE TABLE IF NOT EXISTS notes " +
        "(ts DATETIME, author VARCHAR(255), note TEXT)",
        function(err){
            if (err){
                util.log('FAIL on creating table ' + err);
                callback(err);
            } else {
                callback(null);
            }
        });
}

exports.emptyNote = {"ts": "", author: "", note: ""};
exports.add = function(author, note, callback){
    db.run("INSERT INTO notes (ts, author, note) " +
        "VALUES (?, ?, ?);",
        [new Date(), author, note],
        function(error){
            if (error){
                util.log('FAIL on add ' + error);
                callback(error);
            } else {
                callback(null);
            }
        });
}
/*
run函數接受一個字符串參數,其中?表示占位符,占位符的值必須通過一個數組傳遞進來
調用者提供了一個回調函數,然后通過這個回調函數來聲明錯誤
 */

exports.delete = function(ts, callback){
    db.run("DELETE FROM notes WHERE ts = ?;",
        [ts],
        function(err){
            if (err){
                util.log('FAIL to delete ' + err);
                callback(err);
            } else {
                callback(null);
            }
        });
}

exports.edit = function(ts, author, note, callback){
    db.run("UPDATE notes " +
        "SET ts = ?, author = ?, note = ? " +
        "WHERE ts = ?",
        [ts, author, note, ts],
        function(err){
            if (err){
                util.log('FAIL on updating table ' + err);
                callback(err);
            } else {
                callback(null);
            }
        });
}

exports.allNotes = function(callback){
    util.log(' in allnote');
    db.all("SELECT * FROM notes", callback);
}
exports.forAll = function(doEach, done){
    db.each("SELECT * FROM notes", function(err, row){
        if (err){
            util.log('FAIL to retrieve row ' + err);
            done(err, null);
        } else {
            doEach(null, row);
        }
    }, done);
}
/*
allNotes和forAll函數是操作所有數據的兩種方法,allNotes把數據庫中所有的數據行收集到一個數組里,
而forAll方法可以接受兩個回調函數,每當從數據集中拿一行數據,回調函數doEach都會執行一遍,當讀完所有數據時,回調函數done就會執行
 */

exports.findNoteById = function(ts, callback){
    var didOne = false;
    db.each("SELECT * FROM notes WHERE ts = ?",
        [ts],
        function(err, row){
            if (err){
                util.log('FAIL to retrieve row ' + err);
                callback(err, null);
            } else {
                if (!didOne){
                    callback(null, row);
                    didOne = true;   //保證回調函數只被執行一次
                }
            }
        });
}

notesdb-mongoose.js

MongoDB是nosql數據庫的領頭羊之一,"可擴展、高性能、開源、面向文檔的數據庫",它使用JSON風格的文檔。
Mongoose是用於訪問MongoDB的模塊之一,它是一個對象建模工具,意味着你的程序負責定義模式對象來描述數據,
而Mongoose負責數據到MongoDB的存儲。
Mongoose對於Node和MongoDB而言是一個非常強大的對象建模工具,使用嵌入式文檔,是一個類型靈活的系統,
適用於字段輸入、字段驗證、虛擬字段等。

MongoDB Windows 下安裝部署 http://www.cnblogs.com/EricaMIN1987_IT/p/3571773.html
安裝Mongoose模塊 npm install mongoose

Mongoose不是唯一一個在node中使用MongoDB的工具。

var util = require('util');
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var dburl = 'mongodb://localhost/chap06';  //dburl用於連接已運行的MongoDB

exports.connect = function(callback){
    mongoose.connect(dburl);
}
exports.disconnect = function(callback){
    mongoose.disconnect(callback);
}

exports.setup = function(callback){callback(null);}

//定義模式
var NoteSchema = new Schema({
    ts: {type: Date, default: Date.now},  //默認值
    author: String,
    note: String
});
//將NoteSchema作為Mongoose的模型注冊進去
mongoose.model('Note', NoteSchema);
var Note = mongoose.model('Note');

exports.emptyNote = {"_id": "", author: "", note: ""};

exports.add = function(author, note, callback){
    var newNote = new Note();
    newNote.author = author;
    newNote.note = note;
    newNote.save(function(err){
        if (err){
            util.log('FATAL ' + err);
            callback(err);
        } else {
            callback(null);
        }
    });
}

exports.delete = function(id, callback){
    exports.findNoteById(id, function(err, doc){
        if (err){
            callback(err);
        } else {
            util.log(util.inspect(doc));
            doc.remove();
            callback(null);
        }
    });
}

exports.edit = function(id, author, note, callback){
    exports.findNoteById(id, function(err, doc){
        if (err){
            callback(err);
        } else {
            doc.ts = new Date();
            doc.author = author;
            doc.note = note;
            doc.save(function(err){
                if (err){
                    util.log('FATAL ' + err);
                    callback(err);
                } else {
                    callback(null);
                }
            });
        }
    });
}

exports.allNotes = function(callback){
    Note.find({}, callback);
}

exports.forAll = function(doEach, done){
    Note.find({}, function(err, docs){
        if (err){
            util.log('FATAL ' + err);
            done(err, null);
        }
        docs.forEach(function(doc){
            doEach(null, doc);
        });
        done(null);
    });
}

/*
_id字段是MongoDB提供的全局唯一的ID,用於標識存儲的文檔
 */
var findNoteById = exports.findNoteById = function(id, callback){
    Note.findOne({_id: id}, function(err, doc){
        if (err){
            util.log('FATAL ' + err);
            callback(err, null);
        }
        callback(null, doc);
    });
}

 

app.js

//在數據庫需要放置在一台計算機上時,應該考慮使用SQLite3
//控制器,在nodesdb-sqlite3.js和notesdb-mongoose.js模塊之間切換
var util = require('util');
var url = require('url');
var express = require('express');
var nmDbEngine = 'sqlite3';  //用於命名數據庫引擎、選擇合適的notesdb實現和選擇合適的views目錄
//var nmDbEngine = 'mongoose';
var notesdb = require('./nodesdb-' + nmDbEngine);
var app = express();
app.use(express.logger());
app.use(express.cookieParser()); //添加cookieParser中間件
app.use(express.bodyParser());
app.engine('.html', require('ejs').__express);   //3.X
//app.register('.html', require('ejs'));    //2.X
app.set('views', __dirname + '/views-' + nmDbEngine);
app.set('view engine', 'ejs');

//是一個路由中間件函數,用於在一些路由器函數中解析URL查詢參數
var parseUrlParams = function(req, res, next){
    req.urlP = url.parse(req.url, true);
    next();
}

//檢查用戶是否被允許訪問,這里只檢查cookie是否等於AOK,這個單詞通常意味着一切都沒問題
/*
 很多應用都需要用戶登錄,然后用戶才能進行一些特權操作。由於HTTP是一個無狀態的協議,
 驗證用戶的唯一方式就是發送一個cookie到瀏覽器上,然后驗證標識符。cookie包含了應用中用於驗證用戶的數據。

 cookieParser中間件在這里做了很多工作,查找cookie,解析cookie,然后將解析出來的值讓到req對象中。
 當存在cookie時,它的值會被放入req.cookies中。
 */
var checkAccess = function(req, res, next){
    if (!req.cookies || !req.cookies.notesaccess || req.cookies.notesaccess !== "AOK"){
        res.redirect('/login');
    } else {
        next();
    }
}

notesdb.connect(function(error){
    if (error) throw error;
})

app.on('close', function(error){
    notesdb.disconnect(function(err){});
});

app.get('/', function(req, res) {res.redirect('/view');});
app.get('/view', checkAccess, function(req, res){  //可以在每個路由上加checkAccess檢查
    notesdb.allNotes(function(err, notes){
        if (err){
            util.log('ERROR ' + err);
            throw err;
        } else {
            res.render('viewnotes.html', {title: "Notes ("+ nmDbEngine +")", notes: notes});
        }
    });
});

/*
當用戶點擊ADD按鈕時app.get('/add', ...)內的函數就會被調用,瀏覽器會發出一個發往/add的HTTP GET請求。
這個函數使用addedit.html模板來創建一個表單,讓用於通過這個表單輸入標簽,然后通過單擊SUBMIT按鈕提交,
當用戶提交表單,瀏覽器就會發出一個HTTP POST請求,app.post('/add', ...)內的函數就會被調用,
用戶輸入的數據會被存放在請求主體中,而請求主體會被bodyParser(app.use(express.bodyParser()))中間件處理並存放在req.body中
 */
app.get('/add', function(req, res){
    res.render('addedit.html', {title: "Notes ("+ nmDbEngine +")", postpath: '/add', note: notesdb.emptyNote});
});
app.post('/add', function(req, res){
    notesdb.add(req.body.author, req.body.note,
        function(error){
            if (error) throw error;
            res.redirect('/view');
        });
});

app.get('/del', parseUrlParams, function(req, res){
    notesdb.delete(req.urlP.query.id,
        function(error){
            if (error) throw error;
            res.redirect('/view');
        });
});

app.get('/edit', parseUrlParams, function(req, res){
    notesdb.findNoteById(req.urlP.query.id,
        function(error, note){
            if (error) throw error;
            res.render('addedit.html',
                {title: "Notes ("+ nmDbEngine +")", postpath: '/edit', note: note});
        });
});
app.post('/edit', function(req, res){
    notesdb.edit(req.body.id, req.body.author, req.body.note,
        function(error){
            if (error) throw error;
            res.redirect('/view');
        });
});

app.get('/login', function(req, res){
    res.render('login.html', {title: "Notes LOGIN ("+ nmDbEngine +")"});
});
app.post('/login', function(req, res){
    //此處可以添加檢查用戶信息的邏輯
    //...
    res.cookie('notesaccess', 'AOK');
    res.redirect('/view');
});

app.listen(3000);

show.js

//控制台顯示
var util = require('util');
var notesdb = require('./notesdb-sqlite3');
// var notesdb = require('./notesdb-mongoose');

notesdb.connect(function(error){
    if (error) throw error;
});
notesdb.forAll(function(error, row){
    util.log('ROW: ' + util.inspect(row));
}, function(error){
    if (error) throw error;
    util.log('ALL DONE');
    notesdb.disconnect(function(err){});
});

前台頁面在views-sqlite3目錄下

layout.html

<!DOCTYPE html>
<html>
<head>
    <title><%= title%></title>
</head>
<body>
    <h1><%= title%></h1>
    <p><a href='/view'>View</a> | <a href='/add'>Add</a></p>
</body>
</html>

viewnotes.html

<% include layout.html %>
<table><% notes.forEach(function(note){ %>
    <tr>
        <td>
            <p><%=new Date(note.ts).toString()%>: by <b><%=note.author%></b></p>
            <p><%=note.note%></p>
        </td>
        <td>
            <form method="get" action="/del">
                <input type="submit" value="Delete" />
                <input type="hidden" name="id" value="<%=note.ts%>" />
            </form>
            <br/>
            <form method="get" action="/edit">
                <input type="submit" value="Edit" />
                <input type="hidden" name="id" value="<%=note.ts%>" />
            </form>
        </td>
    </tr>
    <% }); %>
</table>

addedit.html

<% include layout.html %>
<form method="post" action="<%=postpath%>">
    <% if (note){ %>
    <input type="hidden" name="id" value="<%=note.ts%>" />
    <% } %>
    <input type="text" name="author" value="<%=note.author%>" />
    <br/>
    <textarea rows="5" cols="40" name="note">
        <%=note.note%>
    </textarea>
    <br/>
    <input type="submit" value="Submit" />
</form>

login.html

<% include layout.html %>
<form method="POST" action="/login">
    <p>Click the <i>Login</i> to log in.</p>
    <input type="submit" value="Login" />
</form>

node setup.js

node app.js


免責聲明!

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



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