大家知道js現在不僅僅可以寫前端界面而且可以寫后端的業務了,這樣js就可以寫一個全棧的項目。這里介紹一個nodejs + express + mongodb + bootstap 的全棧項目。
1、安裝必要的包,npm install express npm install mongodb npm install ejs (需要使用什么工具,就安裝哪個工具)
2、建一個入口文件,index.js,這里主要是做路由的分發。啟動: node index.js
var express = require("express");// require express 的框架 var app = express(); // 實例化一個 express的對象 var router = require("./router/router.js"); // 引用 router 的文件,下面將介紹這個router var session = require('express-session');// 使用了 express 一個 session 的工具,主要用作注冊登錄使用 var config = require("./config.js");// 引用一個配置文件 //使用session app.use(session({ secret: 'keyboard cat', resave: false, saveUninitialized: true, }));
//設置跨域訪問 在做前后端分離,nodejs提供接口的時候,這個設置跨域請求必不可少
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*"); // 表示任意的源
// res.header("Access-Control-Allow-Origin", "http://www.wtapi.wang"); // 只有這個網址
res.header("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By",'unknown')
res.header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
next();
});
app.set("view engine","ejs");
app.set('views', path.join(__dirname, 'views'));
app.use(express.static("./assets"));// 靜態一個文件夾,實用的好處這里的文件的路徑就可以 用 / 表示
app.get("/",router.index); // 后端分發的路由 "/" 表示主頁 主頁的業務代碼邏輯在 router里的 index 的函數里 //我的發布 // app.get("/mypost", routerUser.list); //search // app.get("/search",routerSearch.list); //執行登陸業務 app.post("/doLogin",router.doLogin); app.post("/doCinemaSubmit",router.doCinemaSubmit); //個人中心頁 // app.get("/usercenter",router.showUserCenter); app.get("/cinema/:targetId",router.showSelectPage); app.post('/seatHandle', router.seatHandle) //退出 app.get("/user_exit",router.logout); //提交修改密碼 app.post("/reviseMyMsg",router.reviseMyMsg); app.listen(config.port, function () { console.log("項目啟動成功: " + config.port); });
3、處理后端業務數據邏輯的router,這里router 名字可以隨便取,貼切的話可以 命名為 controller 或者 model ,兩個命名規范的業務划分,我統統集合在這個一個文件里。
//又提交,引入formidable var formidable = require("formidable"); // 一個前台提交到后端接受數據的一個包,缺點: 沒辦法接受前端傳來的數組數據 //引入封裝好的db.js,從config走 var db = require("../model/db.js"); // 這里的解釋轉到4
var path = require("path"); var fs = require("fs");var mongo = require('mongodb'); var Ob = mongo.ObjectID; var userData = {};
// post 請求的一種方式 //注冊業務 這是一個post 的請求,接受前端傳來的數據做業務處理,處理后返回前端 res.send('....') 前端ajax 獲得一個返回狀態,做前端數據處理 exports.doRegist = function (req,res,next) { var form = new formidable.IncomingForm(); form.parse(req, function(err, fields, files) { var username = fields.username; var userpassword = fields.userpassword; var sharecode = fields.sharecode; // 邀請碼 if (!sharecode){ res.send("-11"); return; } if (!Ob.isValid(sharecode)){ res.send("-11"); return; } // sharecode = "59ac32bbab6a439ed60ebb74"; 測試用 db.find(ds.SHARECODE, {"_id":mongo.ObjectID(sharecode)}, function(err, result){ if (err){ res.send("-11"); return; } if (result.length == 0){ res.send("-11"); return; } db.find("users",{"username": username},function (err,result) { if(err) { res.send("-3"); return; } if(result.length !=0) {//數據庫查詢到有數據占用 res.send("-1");//被占用 return; } //設置MD5加密 userpassword = md5(md5(userpassword)+"adou"); //返回result.length的長度為0,說明數據庫中沒有此名字 db.insertOne("users",{ "msgnum" : 0, "username" : username, "userpassword" : userpassword, "nickname" : '', "avatar" : "/user/default.jpg" },function(err,result){ if(err){ res.send("-3");//服務器錯誤 return; } refresh(req,res,username); // 刪除此邀請碼 db.deleteMany(ds.SHARECODE, {"_id":mongo.ObjectID(sharecode)}, function(err, result){}); }); }); }); }); } // //執行登錄 exports.doLogin = function (req,res,next) { var form = new formidable.IncomingForm(); form.parse(req, function(err, fields, files) { //表單數據 var username = fields.username; var userpassword = fields.userpassword; userpassword_handel= md5(md5(userpassword)+"adou"); db.find("users",{"username" : username},function(err,result){ if(err){ res.send("-5");//隨便去,服務器錯誤 return; } if(result.length == 0){ res.send("-1");//用戶名不存在 return; } if(userpassword_handel == result[0].userpassword){ req.session.login = "1"; req.session.username= username; req.session.uid = result[0]._id; console.log(req.session.uid, "login", Math.floor(new Date().getTime()/1000)); res.send("1"); return; }else{ res.send("-2");//密碼錯誤 return; } }); }) }
// get 請求的一個方式
//訪問首頁
exports.index = function (req,res,next) {
console.log("router: [/]:exports.index");
var login = req.session.login;
var username = req.session.username;
var userinfo = util.getLoginUser(req);
// 渲染一個頁面,將相關的數據渲染到頁面上
res.render('url',{data})
res.render('index',{ //
index 是一個頁面轉到 5
userinfo:{'login':login,'username':username}
})
}
4、上面引入的 db.js 是有關操作數據庫的操作,對原始的mongdb 的語法,做了一下封裝。
//這個模塊里面封裝了所有對數據庫的常用操作 var MongoClient = require('mongodb').MongoClient; var config = require("../config.js"); //不管數據庫什么操作,都是先連接數據庫,所以我們可以把連接數據庫 //封裝成為內部函數 function _connectDB(callback) { var url = config.dburl; //從 config.js 文件中,都數據庫地址 //連接數據庫 MongoClient.connect(url, function (err, db) { if (err) { callback(err, null); return; } callback(err, db); }); } //插入數據 exports.insertOne = function (collectionName, json, callback) { _connectDB(function (err, db) { db.collection(collectionName).insertOne(json, function (err, result) { callback(err, result); db.close(); //關閉數據庫 }) }); }; // insertmany exports.insertMany = function(cname, arr){ _connectDB(function (err, db) { db.collection(cname).insertMany(arr, function (err, result) { db.close(); }); }); } exports.removeAll = function(cname, cb){ _connectDB(function (err, db) { db.collection(cname).deleteMany({}, function (err, result){ cb(err, result); db.close(); }); }); } //查找數據,找到所有數據。args是個對象{"pageamount":10,"page":10} exports.find = function (collectionName, json, C, D) { var result = []; //結果數組 if (arguments.length == 3) { //那么參數C就是callback,參數D沒有傳。 var callback = C; var skipnumber = 0; //數目限制 var limit = 0; } else if (arguments.length == 4) { var callback = D; var args = C; //應該省略的條數 var skipnumber = args.pageamount * args.page || 0; //數目限制 var limit = args.pageamount || 0; //排序方式 var sort = args.sort || {}; } else { throw new Error("find函數的參數個數,必須是3個,或者4個。"); return; } //連接數據庫,連接之后查找所有 _connectDB(function (err, db) { var cursor = db.collection(collectionName).find(json).skip(skipnumber).limit(limit).sort(sort); cursor.each(function (err, doc) { if (err) { callback(err, null); db.close(); //關閉數據庫 return; } if (doc != null) { result.push(doc); //放入結果數組 } else { //遍歷結束,沒有更多的文檔了 callback(null, result); db.close(); //關閉數據庫 } }); }); } //刪除 exports.deleteMany = function (collectionName, json, callback) { _connectDB(function (err, db) { //刪除 db.collection(collectionName).deleteMany( json, function (err, results) { callback(err, results); db.close(); //關閉數據庫 } ); }); } // findmany exports.findmany = function(cname, con, filter, cb){ _connectDB(function (err, db) { db.collection(cname).find(con, filter).toArray(function(err, docs){ cb(err, docs); db.close(); }); }); }; // findone exports.findone = function(cname, con, op, cb){ _connectDB(function (err, db) { db.collection(cname).findOne(con,{fields:op}, function(err, doc){ cb(err, doc); db.close(); }); }); }; //修改 exports.updateMany = function (collectionName, json1, json2, callback) { _connectDB(function (err, db) { db.collection(collectionName).updateMany( json1, json2, function (err, results) { callback(err, results); db.close(); }); }) }; exports.getAllCount = function (collectionName,callback) { _connectDB(function (err, db) { db.collection(collectionName).count({}).then(function(count) { callback(count); db.close(); }); }) } exports.count = function(cname,cond,cb){ _connectDB(function (err, db) { db.collection(cname).count(cond).then(function(count) { cb(count); db.close(); }); }); } exports.one = function(cname, cond, cb){ _connectDB(function (err, db) { db.collection(cname).count(cond).then(function(err, one) { cb(err, one); db.close(); }); }); }
5、具體到前端頁面
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>管理系統</title> <% include component/css.ejs %> // ejs 的一個模版,把相同的東西,封裝在一個 模板里,然后各個頁面 include 這個模板 </head> <body class="index-body"> <div><%= userinfo.login%></div> // ejs 模板渲染 渲染的數據 直接用 <%= data%> 表示
<div><%= userinfo.username%></div> //
</body> </html>
這樣的話,一個前端到后端,后端處理前端傳來的數據,nodejs 操作數據庫,並返回數據給前端的流程就走通了。
這里不是前后端分離,這里采用的是后端渲染的方式,也就是,后台將頁面渲染好,然后返回到前端。