Koa搭建一個后臺系統(tǒng)

前面用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');

})
image.png

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中,那么這個文件就太多了,后期不好維護,所以我們進行拆分為單獨的文件
大概方案如下:


image.png

我們再來看看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();

效果圖


image.png

這里用到了單例模式,解決了數(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();

關鍵代碼如下


image.png

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


image.png
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 杭州的水 杭州的水有種攝人心魄的安靜,第一眼就不能忘記,也許已經(jīng)愛上。雖是來杭州讀大學,來杭州卻并不是第一次,家里...
    南蠻小狐閱讀 500評論 4 5
  • 小時候?qū)W習魯迅的文章,知道故事里有個美麗的水鄉(xiāng)——周莊。于是從那時起,身居北方的我,心里便住著一個美麗的江南水鄉(xiāng)—...
    愛如你我閱讀 1,188評論 1 8
  • 原來是使用桌面云的某臺win10進行打包和簽名。但是因為桌面云遷移導致了信息丟失,密鑰還在,簽名流程和過程缺失( ...
    Water水先生閱讀 490評論 0 0

友情鏈接更多精彩內(nèi)容