express ejs mysql_GitHub - shaokai7878/ejs-express-mysql: ejs+express+mysql实现基本的CRUD后台管理应用...

本文介绍了如何使用EJS、Express和MySQL搭建一个具备用户登录、session管理、CRUD操作的后台管理系统。项目实现了登录验证、数据的增删改查以及图片上传功能。文章详细阐述了项目的整体架构、路由设置、登录功能实现,以及EJS前端页面的代码讲解。同时还涉及到了session的设置、密码签名和数据库操作。
摘要由CSDN通过智能技术生成

ejs-express-mysql

##前言

也是这两周才正式的接触node,虽然在前端开发中我们常常说前后端分离,但是在学习过程中,个人感觉还是要刁难刁难自己的。因为用ejs来写前端页面。

项目主要实现用户的登录,session的存储和加密(准确的说是签名),数据库的CRUD,包括图片的上传,删除和修改等基本功能。

关于登录,查询等操作本应该更加的严谨,这里只做简单演示。包括一些配置文件的编写。

喜欢的朋友方便的话可以给个star (^-^)V

顺便推广一波nodejs技术交流群,群号:209530601

ejs mysql nodejs express express-router...

##效果图

登录页

login.png

整体操作流程图

show.gif

GIF Brewery转gif真的有点。。。好吧,不吐槽了,后面会分开讲解每一步,好在基本操作还能看得清~

后台管理首页

index.png

博文管理

blog.png

用户管理页

user.png

操作

blog_o.png

##开发准备

关于开发前期的准备,这里就不多说了,说实话,自己也没有准备啥,关于nodejs环境,MySQL配置啥的就多少了,关于本项目的数据字典,还有SQL文件已经在目录里了,这里主要说下后端开发的每一个步骤

##项目目录

项目目录

project_str.png

##整体架构

项目重点在后端开发中,web端页面并没有涉及到,后端管理流程大致如下:

路由控制分为admin,web,还是那句话,我们操作全部在admin中

跳转到admin拦截所有的请求,判断用户是否登录

未登录则重定向到登录,登陆成功后设置session。不懂session?点击这里

登录后则可进行相关的操作,数据的增删改查等功能。

##后端开发

###后台基本架构、路由设置

const express = require('express');

const expressStatic = require('express-static');

const bodyParser = require('body-parser');

const multer = require('multer');

const multerObj = multer({dest:'./static/upload'});

const cookieParser = require('cookie-parser');

const cookieSession = require('cookie-session');

const consolidate = require('consolidate');

const ejs = require('ejs');

//创建服务器

var server = express();

server.listen(8080);

//解析请求数据

server.use(bodyParser({

extended:false

}));

server.use(multerObj.any());

//设置cookie,session

server.use(cookieParser('Neal_signed'));

(function () {

var arr = [];

for(var i = 0;i<10000;i++){

arr.push('keys_'+Math.random());

}

server.use(cookieSession({

name:'session_id',

keys:arr,

maxAge:20*60*1000//一般我会设置20分钟,这里是为了感受session过期~~带来的快感~?(●´∀`●)ノ

}))

})();

//设置模板

server.set('view engine','html');

server.set('views','./views');

server.engine('html',consolidate.ejs);

//设置路由

server.use('/admin',require('./router/admin/index')());

server.use('/',require('./router/web/index')());

//静态文件的请求

server.use('/files',expressStatic('./static'));

我的基本架构如下,关于每一部分的功能,都已经标注。关于路由的控制在admin/index.js跟server.js大同小异,我想大家也都应该知道了。

###登录功能

登录功能这里主要说两点

密码的md5签名(当然,大多数人说是md5加密)

session的应用

在lib中存放着自己写的一些方法,作为一个库,admin初始化有三个用户,包括u/p:root,neal,Nealyang

关于密码的签名方法主要如下:

var crypto = require('crypto');

module.exports = {

MD5_SUFFIX : 'JDSAIOEUQOIoieuoiqv#$%^&dhfja)(* %^&FGHJfyuieyfhfhak(^.^)YYa!!\(^o^)/Y(^o^)Y(*^__^*)ヘ|・∀・|ノ*~●',

md5:function (pwd) {

var md5 = crypto.createHash('md5');

return md5.update(pwd).digest('hex');

}

};

MD5_SUFFIX是加密字符串,用法如路由login.js:

router.post('/',function (req,res) {

var username = req.body.username;

var password = common.md5(req.body.password+common.MD5_SUFFIX);

if(username && password){

db.query('SELECT * FROM admin_table WHERE username="'+username+'"',function (err,userData) {

if(err){

console.error(err);

res.status(500).send({code:500,data:[],msg:'database error'});

}else if(userData.length == 0){

res.status(400).send({code:400,data:[],msg:'parameters error'});

}else{

if(userData[0].password != password){

res.status(400).send({code:400,data:[],msg:'username or password error'});

}else{

req.session['user_id'] = userData[0].ID;//注意这里是在req上面

res.status(200).send({code:200,data:[],msg:'success'});

}

}

})

}else{

res.status(400).send({code:400,data:[],msg:'parameters error'});

}

});

从上面的代码中也展现了什么时候设置session,并且值得提一下的是这里提供给前端页面的是接口,这样的话很多逻辑都放到了前端,后面我们都是通过页面渲染来输出的了。下面是所有请求的拦截判断:

router.use(function (req,res,next) {

if(!req.session['user_id'] && req.url != '/login'){

res.redirect('/admin/login');

}else{

next();

}

});

##ejs前端页面的重点代码讲解

公共头部的引入:

查询数据库的前端展示:

删除

修改

修改后我们通过页面给的标识来知道是否为修改的提交,毕竟这里我们没有前端逻辑的js

add.png

标题:

作者:

摘要:

链接:

##博文管理

还是那句话,如果是仅仅提供前端的接口的话,这里会方便很多,然后我们用的是ejs,所以很多的逻辑都放在了后端,在get/post到请求的时候需要做很多判断

get方法请求如下:

router.get('/', function (req, res) {

switch (req.query.action) {

case 'del':

//删除操作

db.query('DELETE FROM blog_list_table WHERE id="'+req.query.id+'"',function (err,resultData) {

if(err){

console.error(err);

res.status(500).send({code:500,msg:'database error'});

}else{

res.redirect('/admin/blog');

}

});

break;

case 'mod':

//修改操作

db.query('SELECT * FROM blog_list_table WHERE id="'+req.query.id+'"',function (err,modData) {

if(err){

console.error(err);

res.status(500).send({code:500,msg:'database error'});

}else if(modData.length == 0){

res.status(400).send({code:400,msg:'parameters error'});

}else{

db.query('SELECT * FROM blog_list_table',function (err,allData) {

if(err){

console.error(err);

res.status(500).send({code:500,msg:'database error'});

}else{

res.render('admin/blog.ejs',{formData:allData,modData:modData});

}

});

}

});

break;

default:

db.query('SELECT * FROM blog_list_table', function (err, resultData) {

if (err) {

console.error(err);

res.status(500).send({code: 500, msg: 'database error'}).end();

} else {

res.render('admin/blog.ejs', {formData: resultData});

}

});

}

});

这里的switch,主要是分为,查询,删除,和修改

都是些简单的CRUD操作,这里就不多细说了。不熟悉的兄弟们可以看一看,写的不好,多多提意见。

同理,post的请求,主要就是分为,文章列表的添加,和修改的两个post,代码如下:

router.post('/', function (req, res) {

//此处验证应该更加严格,比如正则

var title = req.body.title.trim();

var author = req.body.author.trim();

var summary = req.body.summary.trim();

var href = req.body.href.trim();

if (title && author && summary && href) {

if(req.body.modified){

db.query('UPDATE blog_list_table SET title="'+title+'",author="'+author+'",summary="'+summary+'",href="'+href+'" WHERE ID="'+req.body.modified+'"',function (err,resultData) {

if(err){

console.error(err);

res.status(500).send({code:500,msg:'database error'});

}else{

res.redirect('/admin/blog');

}

})

}else{

db.query('INSERT INTO blog_list_table (title,author,summary,href) VALUE("' + title + '","' + author + '","' + summary + '","' + href + '")', function (err, data) {

if (err) {

console.error(err);

res.status(500).send({code: 500, msg: 'database error'}).end();

} else {

res.redirect('/admin/blog');

}

});

}

} else {

res.status(400).send({code: 400, msg: 'parameters error'}).end();

}

});

##用户管理

后台的管理大概也即是这么多,用户管理和博文管理基本都是差不多的,这里重点是说下,这里用到的图片上传。

图片上传我用的是multer中间件,不知道的可以查下,注意用这个中间件接受图片上传时form表单的enctype必须要设置为multipart/form-data

关于图片上传后,默认是不包括后缀名的,所以这里我们需要用到fs模块的重命名操作,代码如下:

fs.rename(req.files[0].path, req.files[0].path + ext, function (err) {

if (err) {

console.error(err);

res.status(500).send({code: 500, msg: 'data error'});

} else {

db.query('INSERT INTO user_table (username,email,pic_header) VALUE("' + username + '","' +

email + '","' + pic_header + '")', function (err, resultData) {

if (err) {

console.error(err);

res.status(500).send({code: 500, msg: 'database error'});

} else {

res.redirect('/admin/users');

}

});

}

});

前面的变量定义主要如下:

var username = req.body.username;

var email = req.body.email;

if(req.files.length>0){

var ext = pathLib.parse(req.files[0].originalname).ext;

var pic_header = '/files/upload/' + req.files[0].filename + ext;

}

用到path模块对路径的解析。为了获取后缀名~

说到这,对于修改也就很简单了,就是删除原先有的那个图片,然后换上现在有的图片,具体代码如下:

//需要进行一些校验,这里就忽略了

if(req.body.modified){//修改

//查看有没有新传来的头像,如果有,则删除,新建,如果没有,直接更新需要更新的内容

if(req.files.length>0){

//有修改头像,则进行原来头像的删除,再上传

db.query('SELECT * FROM user_table WHERE ID="'+req.body.modified+'"',function (err,modData) {

if (err) {

console.error(err);

res.status(500).send({code: 500, msg: 'database error'});

}else if(modData.length == 0){

res.status(400).send({code: 400, msg: 'parameters error'});

}else{

fs.unlink(modData[0].pic_header.replace('\/files','static'),function (err) {

if(err){

console.error(err);

res.status(500).send({code:500,msg:'operate error'});

}else{

//删除成功,开始对新的文件进行重命名

fs.rename(req.files[0].path, req.files[0].path + ext, function (err) {

if (err) {

console.error(err);

res.status(500).send({code: 500, msg: 'operate error'});

} else {

db.query('UPDATE user_table SET username="'+

username+'",email="' + email + '",pic_header="' +

pic_header + '" WHERE ID="'+req.body.modified+'"',function (err,data) {

if (err) {

console.error(err);

res.status(500).send({code: 500, msg: 'database error'});

}else{

res.redirect('/admin/users');

}

});

}

});

}

})

}

})

}else{

db.query('UPDATE user_table SET username="'+username+'",email="' + email + '" WHERE ID="'+

req.body.modified+'"',function (err,data) {

if (err) {

console.error(err);

res.status(500).send({code: 500, msg: 'database error'});

}else{

res.redirect('/admin/users');

}

});

}

}

看到这个代码是不是感觉想死的心都有了???的确,多少篇文章都说到了关于nodejs的回调地狱,但是Node 7.6 发布了,支持了async函数,JavaScript异步的写法彻底改变了。所以这个大可不必太过于担心

况且Koa不就这么的出来和投入大范围的使用了嘛,这里我们大可用express,去尽情的感受Node的魅力。

##结束语

说到这,基本的一个小小后台管理应用就完事了,是不是感觉没有想象中的那么难?写的不好,欢迎大家吐槽指教~~~

最后,欢迎愿意一起学习nodejs的朋友加入,Nodejs技术群:209530601

~~

这个系统其实是出于学习nodejs的目的而改写的系统。 原来的系统前端使用了extjs4.2.1,后端使用了PHP5.4和ZEND框架开发,后台数据库是用mongodb2.2.2。 我抽离出了原来系统中的账户管理,角色管理,菜单管理,权限管理这4个部分, 我想这4个部分,基本上所有的系统都会用到。具有一定的普遍性。所以将这4个部分用nodejs重新改写了。 该系统目前使用模块有express,ejs,connect-mongo,mongodb,express-partials,connect-flash,fibers,wind等 其实wind模块这次系统中没有使用。可以将它排除出去。我是出于学习wind的目的,才加入这个模块的。 本来准备使用wind模块,是为了实现同步的目的,由于后来改用了fibers模块之后,就没有使用它。这里说明一下 不是fibers要比wind好,而是我暂时不能理解wind,或则是说对wind的研究不够吧。 众所周知nodejs是推崇异步模式。但是这个系统是从php过来的,而php的代码是同步模式的写法,所以为了在改写的过程中 希望 1是代码改动最少 2是同步写法更加适合思维习惯。而且代码可读性高的目的,用到了fibers。 这个系统的源代码中有些js文件里保留了一些原来的PHP代码,这是出于代码对比的目的。 是让大家了解原来的php代码是怎么实现的,用nodejs之后是如何改写的。通过对比,大家会发现 其实通过使用fibers之后,几乎两者是一模一样的。 还有源代码中还保留了一些被注释掉的函数,有些是用到了wind,有些是用到了fibers,有些是直接异步的写法。 这些内容都是在开发过程中我不断尝试后的产物。我花了1周的时间才实现了一个递归的调用,而且还是同步的方式。 到目前为止,我还不能理解在异步模式下实现递归调用函数。比如说源代码中有个函数getMenuTree,菜单下面可能有子菜单, 子菜单的下面可能还有菜单。所以是一个递归的过程。我现在是同步的写法实现了这个函数,如果有人能够提供异步写法实现的递归函数并 emai给我,我不胜荣幸。 在使用本系统之前,必须要安装nodejs 0.10.10,mongodb2.2.2,python2.7.5至于安装的方法请googel解决。 将源代码下载之后,解压到某个目录下,比如说d:\nodejs\umav4simple目录。 进入到那个目录, a)运行以下命令 npm install express npm install ejs npm install connect-mongo npm install mongodb npm install express-partials npm install connect-flash npm install fibers npm install wind 尽管在源代码中已包含了这些模块,但是最好还是要重新运行一遍。 因为有些模块可能需要重新的编译。 比如说fibers模块,我在window下运行npm install fibers的时候编译了一个win32-ia32-v8-3.14 而在linux下重新编译了linux-ia32-v8-3.14。所以说根据操作系统的不同,可能会有一些不同。 以免造成想不到的错误。 b)打开settings.js,并且将你的mongodb的设置改写并保存。 c)运行node app.js或则node cluster.js 如果没有提示错误的话,那么就说明环境配置成功了。 d)通过以下的URL可以在mongodb中追加一些数据,不过只能运行一次。否则会重复追加数据。 浏览器上输入 http://localhost:3000/admin/index/install 做完之后, 浏览器上输入http://localhost:3000/ 就通过用户名admin 密码adminadmin进行登录,并使用这个系统了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值