前面用exprss搭建了一个简单的后台管理系统,现在用koa来的搭建一个同样的后台系统,除了基本语法稍有不同外,其实大部分思路是一样的,话不多说,上代码
准备工作:
为了检测代码改变,安装一个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,现在用一个比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公共静态资源
//配置 静态资源的中间件
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,然后后续访问其他页面,用这个来判断,有session才可以访问,没有就跳转到登录页面,进行登录判断才可以后续的操作
思路如下
1:登录页面
2:定义后台api接口,获取数据
3:在数据库查询匹配,成功就写入
4:路由跳转指定页面
好,开始
1:定义一个login.html页面
2:定义一个提交接口
<form action="{{__HOST__}}/admin/login/doLogin" method="post" id="loginForm">
ps:这里__host__,使用了一个全局变量定义
方法如下
定义一个全局中间件 ctx.state.__host__来实现的
//全局路由访问的中间件
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)
//这里做权限控制 已经登录直接跳转后台首页
if(ctx.session.userinfo){
await next(); //已经登录 继续向下执行
}else{ //没有登录
console.log(ctx.request.url);
if(ctx.request.url =='/admin/login' || ctx.request.url =='/admin/login/doLogin'){ // 登录页面和登录接口向下执行
await next();
}else{ //判断不是登录页面和登录接口 就跳转必须去登录页面
ctx.redirect('/admin/login');
}
}
next();
});
好了现在来看登录接口提交
//post 提交
router.post('/doLogin',async (ctx)=>{
console.log(ctx.request.body);
//获取数据
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、去数据库匹配
//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的增删改查,后续单独介绍
这里一个基本的koa-seesion就完成了。
接下来我们做些优化,如果一个一个路由全部放在app.js中,那么这个文件就太多了,后期不好维护,所以我们进行拆分为单独的文件
大概方案如下:
我们再来看看app.js中如何实现的
//引入路由模块
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();
这样路由就分开了,只需要单独找到特定模块,然后维护路由即可
下面介绍下数据库mongoDb的封装
1:定义配置信息
var app={
dbUrl: 'mongodb://localhost:27017/',
dbName: 'dongdong'
}
module.exports=app;
2:配置具体实现
//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(); /*实例化的时候就连接数据库*/
}
connect(){ /*连接数据库*/
let _that=this;
return new Promise((resolve,reject)=>{
if(!_that.dbClient){ /*1、解决数据库多次连接的问题*/
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 把字符串转换成对象*/
return new ObjectID(id);
}
}
module.exports=Db.getInstance();
效果图
这里用到了单例模式,解决了数据库多次连接耗费时间的性能问题,第二次不需要初始化,直接使用,
static getInstance(){ /*1、单例 多次实例化实例不共享的问题*/
if(!Db.instance){
Db.instance=new Db();
}
return Db.instance;
}
constructor(){
this.dbClient=''; /*属性 放db对象*/
this.connect(); /*实例化的时候就连接数据库*/
}
module.exports=Db.getInstance();
关键代码如下
亲测有效·········
最后上传一个效果图···