1.Mongoose連接配接池
-
npm install mongoose
- 在config目錄下建立mongoDB檔案,将資料庫相關的資訊放至這個檔案夾内
- 在mongoDB下建立mongo.js
//mongo.js
const mongoose = require('mongoose');
const mongodbConfig = require('./config').mongodb //擷取mongo配置
console.log(mongodbConfig)
/**
* 使用 Node 自帶 Promise 代替 mongoose 的 Promise,否則會報錯
*/
mongoose.Promise = global.Promise;
/**
* 配置 MongoDb options
*/
function getMongodbConfig() {
let options = {
useNewUrlParser: true,
poolSize: 5, // 連接配接池中維護的連接配接數
reconnectTries: Number.MAX_VALUE,
keepAlive: 120,
}
return options;
}
/**
* 拼接 MongoDb Uri
*
*/
function getMongoUrl() {
let mongoUrl = 'mongodb://';
let dbName = mongodbConfig.db;
mongoUrl += `${mongodbConfig.host}:${mongodbConfig.port}`;
mongoUrl += `/${dbName}`;
return mongoUrl;
}
/**
* 建立 Mongo 連接配接,内部維護了一個連接配接池,全局共享
*/
console.log(new Date().getTime())
let mongoClient = mongoose.createConnection(getMongoUrl(), getMongodbConfig());
/**
* Mongo 連接配接成功回調
*/
mongoClient.on('connected', function() {
console.log(new Date().getTime())
console.log('Mongoose連接配接至 :' + getMongoUrl());
});
/**
* Mongo 連接配接失敗回調
*/
mongoClient.on('error', function(err) {
console.log('Mongoose 連接配接失敗,原因: ' + err);
});
/**
* Mongo 關閉連接配接回調
*/
mongoClient.on('disconnected', function() {
console.log('Mongoose 連接配接關閉');
});
/**
* 關閉 Mongo 連接配接
*/
function close() {
mongoClient.close();
}
module.exports = {
mongoClient: mongoClient,
close: close,
};
- 在mongoDB下建立config.js,裡面存放我們資料庫的名稱、位址
//config.js
module.exports = {
"mongodb": {
"user": "",
"pass": "",
"host": "localhost",
"port": "27017",
"db": "blog"
}
}
2.Model
- 在config下建立models,存放我們的資料模型,一個model對應一個dao
Model介紹:
比如我們人類有一雙手,一雙眼睛,一個腦袋,沒有尾巴,這就是模型,Model定義了這個子產品的資料模型。
在代碼中展現為資料管理者,Model負責對資料進行擷取及存放。
資料不可能憑空生成的,要麼是從伺服器上面擷取到的資料,要麼是本地資料庫中的資料,
也有可能是使用者在UI上填寫的表單即将上傳到伺服器上面存放,是以需要有資料來源。
既然Model是資料管理者,則自然由它來負責擷取資料。
Controller不需要關心Model是如何拿到資料的,隻管調用就行了。
資料存放的地方是在Model,而使用資料的地方是在Controller,
是以Model應該提供接口供controller通路其存放的資料(通常通過.h裡面的隻讀屬性)
- 在models下建立user.js,這是使用者表的實體類,我們用mongoose的Schema建立
let { Schema } = require('mongoose');
let { mongoClient } = require('../mongoDB/mongo');
/**
* 操作 MongoDb 時需要建立兩個檔案 model.js 和 modelDao.js
*
* 一. 對于 Model.js 以下幾部分:
* 1. Schema 必要
* 2. plugin 可選
* 3. hook 可選
* 4. 調用 mongoClient.model() 建立 Model,此處注意,Model 名稱與 js 檔案名一樣,但首字母大寫
*
* 二. 對于 modelDao.js
* 我們需要聲明一個 ModelDao 的 class 繼承自 BaseDao, BaseDao 中包含基本的 crud 操作,也可以根據需求自行定義
*
* 三. 外部使用
* var dao = new ModelDao()
* dao.crud();
*/
const userSchema = new Schema({
name: String,
psw: String, // lowercase 都屬于 setters
}, {
runSettersOnQuery: true // 查詢時是否執行 setters
});
/**
* 參數一要求與 Model 名稱一緻
* 參數二為 Schema
* 參數三為映射到 MongoDB 的 Collection 名
*/
console.log('實體類',new Date().getTime())
let User = mongoClient.model(`User`, userSchema, 'user');
module.exports = User;
3.DAO
- DAO的概念:
資料通路對象(data access object,DAO)是為某種類型的資料庫或其他持久性機制提供一個抽象接口的對象。
通過映射應用程式對持久層的調用,DAO提供一些特定的資料操作,而無需暴露資料庫細節。
- 在config檔案下建立dao檔案夾,dao檔案夾存放一個模型對應的資料庫操作
由于所有的資料庫操作都是在【增删查改】的基礎上進行操作,是以我們寫了給basedao一個公共js
讓其他的dao繼承這個basedao
- 在dao檔案下建立basedao.js
//basedao.js
class BaseDao {
/**
* 子類構造傳入對應的 Model 類
*
* @param Model
*/
constructor(Model) {
this.Model = Model;
}
/**
* 使用 Model 的 靜态方法 create() 添加 doc
*
* @param obj 構造實體的對象
* @returns {Promise}
*/
create(obj) {
return new Promise((resolve, reject) => {
let entity = new this.Model(obj);
this.Model.create(entity, (error, result) => {
if (error) {
console.log('create error--> ', error);
reject(error);
} else {
console.log('create result--> ', result);
resolve(result)
}
});
});
}
/**
* 使用 Model save() 添加 doc
*
* @param obj 構造實體的對象
* @returns {Promise}
*/
save(obj) {
return new Promise((resolve, reject) => {
let entity = new this.Model(obj);
entity.save((error, result) => {
if (error) {
console.log('save error--> ', error);
reject(error);
} else {
console.log('save result--> ', result);
resolve(result)
}
});
});
}
/**
* 查詢所有符合條件 docs
*
* @param condition 查找條件
* @param constraints
* @returns {Promise}
*/
findAll(condition, constraints) {
return new Promise((resolve, reject) => {
this.Model.find(condition, constraints ? constraints : null, (error, results) => {
if (error) {
console.log('findAll error--> ', error);
reject(error);
} else {
console.log('findAll results--> ', results);
resolve(results);
}
});
});
}
/**
* 查找符合條件的第一條 doc
*
* @param condition
* @param constraints
* @returns {Promise}
*/
findOne(condition, constraints) {
return new Promise((resolve, reject) => {
this.Model.findOne(condition, constraints ? constraints : null, (error, results) => {
if (error) {
console.log('findOne error--> ', error);
reject(error);
} else {
console.log('findOne results--> ', results);
resolve(results);
}
});
});
}
/**
* 查找排序之後的第一條
*
* @param condition
* @param orderColumn
* @param orderType
* @returns {Promise}
*/
findOneByOrder(condition, orderColumn, orderType) {
return new Promise((resolve, reject) => {
this.Model.findOne(condition)
.sort({
[orderColumn]: orderType })
.exec(function(err, record) {
console.log(record);
if (err) {
reject(err);
} else {
resolve(record);
}
});
});
}
/**
* 更新 docs
*
* @param condition 查找條件
* @param updater 更新操作
* @returns {Promise}
*/
update(condition, updater) {
return new Promise((resolve, reject) => {
this.Model.update(condition, updater, (error, results) => {
if (error) {
console.log('update error--> ', error);
reject(error);
} else {
console.log('update results--> ', results);
resolve(results);
}
});
});
}
/**
* 移除 doc
*
* @param condition 查找條件
* @returns {Promise}
*/
remove(condition) {
return new Promise((resolve, reject) => {
this.Model.remove(condition, (error, result) => {
if (error) {
console.log('remove error--> ', error);
reject(error);
} else {
console.log('remove result--> ', result);
resolve(result);
}
});
});
}
}
module.exports = BaseDao;
- 在dao檔案下建立userdao.js用來繼承basedao.js
//userdao.js
const BaseDao = require('./basedao')
const User = require('../models/user')
class UserDao extends BaseDao {
constructor() {
super(User)
}
}
module.exports = UserDao;
4.以上就是mongoose連接配接池、MVC模式設計
有了連接配接池、資料操作,接下來就是調用
- 在routes 下建立 userAPI.js
//userAPI.js
var express = require('express');
const User = require('../config/models/user')
const UserDao = require('../config/dao/userdao');
const JwtUtil = require('../config/jwt/jwt.js'); //token工具
const AesUtil = require('../config/aes/aes.js'); //aes加密
var router = express.Router();
var userdao = new UserDao()
router.post('/login', (req, res) => {
let name = req.body.name // 前端請求頭用json發送的話用 req.query 或者 req.params
//接收不到就下載下傳一個body-parse插件來解析
let psw = req.body.psw
userdao.findOne({ name: name }).then((results) => {
console.log('findOne dao --> ', results)
if (results) {
//解密
let password = AesUtil.decryption(results.psw)
console.log('密碼為:' + password)
if (psw == password) {
//登入成功,添加token
let _id = results._id.toString()
let jwt = new JwtUtil(_id)
let token = jwt.generateToken()
res.send(token)//登入成功,傳回token
} else {
res.send('密碼錯誤')
}
} else {
res.send('賬号不存在')
}
});
})
5.API寫好了,在app.js中引入userAPI.js
//app.js
const express = require("express");
const bodyParser = require("body-parser")
const app = express();
// 跨域設定
app.all("*", function(req, res, next) {
res.header("Access-Control-Allow-Credentials", true);
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With,Content-Type");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("Access-Control-Expose-Headers", "*");
res.header("Content-Type", "application/json; charset=utf-8");
next();
});
// 擷取内容
app.use(bodyParser.json())// 解析 application/json
app.use(bodyParser.urlencoded({ extended: true }))// 解析 application/x-www-form-urlencoded
app.use("/user", require("./routes/userAPI.js"));
app.get('/', (req, res) => {
res.send('api');
});
const port = process.env.PORT || 3001;
app.listen(port, () => {
console.log('Express server listening on port ' + port);
});
module.exports = app;
使用http://localhost:3001/user/login就可以通路了