前面用exprss搭建了一個簡單的后臺管理系統(tǒng),現(xiàn)在用koa來的搭建一個同樣的后臺系統(tǒng),除了基本語法稍有不同外,其實大部分思路是一樣的,話不多說,上代碼
準備工作:
為了檢測代碼改變,安裝一個nodemon
cnpm install nodemon -D
//在package.josn添加配置
"scripts": {
"start": "nodemon app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
好了:開干
1:安裝koa
cnpm install koa -D
2:安裝koa-router
const router = require('koa-router')();
3:初始化一個koa
const app = new koa();
4:添加一個配置,啟動路由,重要很容易漏掉的哦
app.use(router.routes()); /*啟動路由*/
app.use(router.allowedMethods());
app.listen('3333',()=>console.log('server init'));
這樣一個基本的koa服務就搭建完成了,下面來講解模板引擎的使用
express中我們使用了ejs,現(xiàn)在用一個比ejs性能更好的模板koa-art-template。
上代碼
1:安裝koa-art-template(https://www.npmjs.com/
不會的可以上去npm查看)
cnpm install koa-art-template
2:引入使用
const render = require('koa-art-template');
//配置模板引擎
render(app, {
root: path.join(__dirname, 'views'),
extname: '.html',
debug: process.env.NODE_ENV !== 'production'
});
具體使用
router.get('/add',async (ctx)=>{
await ctx.render('admin/user/add');
})

ps:這里注意views不能修改文件名,后綴可以用我們熟悉的html
添加一個static公共靜態(tài)資源
//配置 靜態(tài)資源的中間件
1:cnpm install koa-static -D
2:引入 const static = require('koa-static');
3:使用 app.use(static(__dirname + '/public'));
接下來介紹一下session,方便用于用戶登錄判斷、權限等一系列的使用哦
1:安裝cnpm install koa-session -D
2:引入const session = require('koa-session');
3:使用
//配置session的中間件
app.keys = ['some secret hurr'];
const CONFIG = {
key: 'koa:sess',
maxAge: 864000,
overwrite: true,
httpOnly: true,
signed: true,
rolling: true, /*每次請求都重新設置session*/
renew: false,
};
app.use(session(CONFIG, app));
那么如何測試和使用了?
我們用一個登錄頁面模擬登錄成功后寫入session,然后后續(xù)訪問其他頁面,用這個來判斷,有session才可以訪問,沒有就跳轉(zhuǎn)到登錄頁面,進行登錄判斷才可以后續(xù)的操作
思路如下
1:登錄頁面
2:定義后臺api接口,獲取數(shù)據(jù)
3:在數(shù)據(jù)庫查詢匹配,成功就寫入
4:路由跳轉(zhuǎn)指定頁面
好,開始
1:定義一個login.html頁面
2:定義一個提交接口
<form action="{{__HOST__}}/admin/login/doLogin" method="post" id="loginForm">
ps:這里host,使用了一個全局變量定義
方法如下
定義一個全局中間件 ctx.state.host來實現(xiàn)的
//全局路由訪問的中間件
router.use(async (ctx,next)=>{
//獲取url的地址 設置http://localost:3333
ctx.state.__HOST__='http://'+ ctx.request.header.host;
//console.log(ctx.request.header.host);
console.log('userinfo='+ctx.session.userinfo)
//這里做權限控制 已經(jīng)登錄直接跳轉(zhuǎn)后臺首頁
if(ctx.session.userinfo){
await next(); //已經(jīng)登錄 繼續(xù)向下執(zhí)行
}else{ //沒有登錄
console.log(ctx.request.url);
if(ctx.request.url =='/admin/login' || ctx.request.url =='/admin/login/doLogin'){ // 登錄頁面和登錄接口向下執(zhí)行
await next();
}else{ //判斷不是登錄頁面和登錄接口 就跳轉(zhuǎn)必須去登錄頁面
ctx.redirect('/admin/login');
}
}
next();
});
好了現(xiàn)在來看登錄接口提交
//post 提交
router.post('/doLogin',async (ctx)=>{
console.log(ctx.request.body);
//獲取數(shù)據(jù)
let username=ctx.request.body.username;
let password=ctx.request.body.password;
let code=ctx.request.body.code;
//console.log(tools.md5(password));
//1、驗證用戶名密碼是否合法
//2、去數(shù)據(jù)庫匹配
//3、成功以后把用戶信息寫入sessoin
// if(code.toLocaleLowerCase()==ctx.session.code.toLocaleLowerCase()){
//后臺也要驗證碼用戶名密碼是否合法
var result=await DB.find('user',{"username":username,"pwd":tools.md5(password)});
console.log('result'+result)
if(result.length>0){
//console.log('成功');
console.log(ctx.state.__HOST__);
//成功后寫入sessioon ,方便下次不用登錄和判斷用
ctx.session.userinfo=result[0];
console.log('session='+ ctx.session.userinfo);
//路由重定向
ctx.redirect(ctx.state.__HOST__+'/admin');
}else{
//console.log('失敗');
ctx.render('admin/error',{
message:'用戶名或者密碼錯誤',
redirect: ctx.state.__HOST__+'/admin/login'
})
}
// }else{
// ctx.render('admin/error',{
// message:'驗證碼失敗',
// redirect: ctx.state.__HOST__+'/admin/login'
// })
// }
await ctx.render('admin/login');
});
這里封裝了mongoDb的增刪改查,后續(xù)單獨介紹
這里一個基本的koa-seesion就完成了。
接下來我們做些優(yōu)化,如果一個一個路由全部放在app.js中,那么這個文件就太多了,后期不好維護,所以我們進行拆分為單獨的文件
大概方案如下:

我們再來看看app.js中如何實現(xiàn)的
//引入路由模塊
const admin = require('./routes/admin')
const api = require('./routes/api')
const index = require('./routes/index')
router.use('/admin',admin);
router.use('/api',api);
//router.use(index);
ps:所以以/admin開頭的全部訪問admin這個js,也就是引入的admin路由
admin.js
const router = require('koa-router')();
const login =require('./admin/login');
const user =require('./admin/user');
router.get('/', async (ctx)=>{
ctx.render('admin/index');
});
router.use('/login',login);
router.use('/user',user);
module.exports=router.routes();
user.js
var router = require('koa-router')();
router.get('/',async (ctx)=>{
await ctx.render('admin/user/list');
})
router.get('/add',async (ctx)=>{
await ctx.render('admin/user/add');
})
router.get('/edit',async (ctx)=>{
ctx.body="編輯用戶";
})
router.get('/delete',async (ctx)=>{
ctx.body="刪除用戶";
})
module.exports=router.routes();
這樣路由就分開了,只需要單獨找到特定模塊,然后維護路由即可
下面介紹下數(shù)據(jù)庫mongoDb的封裝
1:定義配置信息
var app={
dbUrl: 'mongodb://localhost:27017/',
dbName: 'dongdong'
}
module.exports=app;
2:配置具體實現(xiàn)
//DB庫
var MongoDB=require('mongodb');
var MongoClient =MongoDB.MongoClient;
const ObjectID = MongoDB.ObjectID;
var Config=require('./config.js');
class Db{
static getInstance(){ /*1、單例 多次實例化實例不共享的問題*/
if(!Db.instance){
Db.instance=new Db();
}
return Db.instance;
}
constructor(){
this.dbClient=''; /*屬性 放db對象*/
this.connect(); /*實例化的時候就連接數(shù)據(jù)庫*/
}
connect(){ /*連接數(shù)據(jù)庫*/
let _that=this;
return new Promise((resolve,reject)=>{
if(!_that.dbClient){ /*1、解決數(shù)據(jù)庫多次連接的問題*/
MongoClient.connect(Config.dbUrl,(err,client)=>{
if(err){
reject(err)
}else{
_that.dbClient=client.db(Config.dbName);
resolve(_that.dbClient)
}
})
}else{
resolve(_that.dbClient);
}
})
}
find(collectionName,json){
return new Promise((resolve,reject)=>{
this.connect().then((db)=>{
var result=db.collection(collectionName).find(json);
result.toArray(function(err,docs){
if(err){
reject(err);
return;
}
resolve(docs);
})
})
})
}
update(collectionName,json1,json2){
return new Promise((resolve,reject)=>{
this.connect().then((db)=>{
//db.user.update({},{$set:{}})
db.collection(collectionName).updateOne(json1,{
$set:json2
},(err,result)=>{
if(err){
reject(err);
}else{
resolve(result);
}
})
})
})
}
insert(collectionName,json){
return new Promise((resolve,reject)=>{
this.connect().then((db)=>{
db.collection(collectionName).insertOne(json,function(err,result){
if(err){
reject(err);
}else{
resolve(result);
}
})
})
})
}
remove(collectionName,json){
return new Promise((resolve,reject)=>{
this.connect().then((db)=>{
db.collection(collectionName).removeOne(json,function(err,result){
if(err){
reject(err);
}else{
resolve(result);
}
})
})
})
}
getObjectId(id){ /*mongodb里面查詢 _id 把字符串轉(zhuǎn)換成對象*/
return new ObjectID(id);
}
}
module.exports=Db.getInstance();
效果圖

這里用到了單例模式,解決了數(shù)據(jù)庫多次連接耗費時間的性能問題,第二次不需要初始化,直接使用,
static getInstance(){ /*1、單例 多次實例化實例不共享的問題*/
if(!Db.instance){
Db.instance=new Db();
}
return Db.instance;
}
constructor(){
this.dbClient=''; /*屬性 放db對象*/
this.connect(); /*實例化的時候就連接數(shù)據(jù)庫*/
}
module.exports=Db.getInstance();
關鍵代碼如下

親測有效·········
最后上傳一個效果圖···
