nodejs用expressjs框架搭建多人博客(一)
想学习点新东西就是开手写,就写了个简单的实现,利用node实现一个博客。主要的内容就在首页也能看到了。
话不多说,expressjs怎么创建项目选择ejs模板,之前的文章都写过了。
首先从用户注册开始,有了用户才能根据id查找文章。
<%- include("../layouts/header", {cssAry: ['/style/reg/index.css']}) %>
<div class="body flex center">
<div class="index-main">
<div class="index-header">
<h1 class="logo"></h1>
<p class="describe">一条大河波浪宽</p>
</div>
<div class="form-name flex center">
<a class="form-active" href="/reg">注册</a>
<a href="/login">登录</a>
</div>
<div class="index-form">
<form method="post" action="/reg">
<input type="hidden" name="_csrf" value="<%= csrf %>">
<div class="form-item">
<input type="input" name="email" placeholder="邮箱"/>
</div>
<div class="form-item">
<input type="password" name="pwd" placeholder="密码(大于六位)">
</div>
<div class="form-item">
<input type="password" name="repeatpwd" placeholder="确定密码">
</div>
<div class="button-item">
<input class="btn btn-sure" type="submit" value="注册">
</div>
</form>
</div>
</div>
</div>
<%- include("../layouts/footer", {jsAry: []}) %>
include 传递参数时就把需要的css 和js 传递到head 和foot模块里
header.ejs
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0">
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<link rel="shortcut icon" type="image/x-icon" href="/images/favicon3.ico">
<meta name="csrf-token" content="<%= csrf %>">
<title><%= title %></title>
<link rel='stylesheet' href='/style/main.css' />
<% for(var i = 0, item; item = cssAry[i++]; ) {%>
<link rel='stylesheet' href='<%= item %>'/>
<% } %>
</head>
<body>
footer.ejs
<script type="text/javascript" src="http://lib.sinaapp.com/js/jquery/2.2.4/jquery-2.2.4.min.js"></script>
<script type="text/javascript" src="/javascripts/main.js"></script>
<% for(var i = 0, item; item = jsAry[i++]; ) {%>
<script type="text/javascript" src="/<%= item %>"></script>
<% } %>
</body>
</html>
route路由,编写对应再到reg.ejs的页面
//注册
router.get('/reg', function(req, res) {
res.render('reg/index', {
title: '注册',
pwd_err: req.session.pwd_err
});
});
//注册提交
router.post('/reg', function(req, res) {
if(!util.isEqual(req.body.pwd, req.body.repeatpwd)) {
req.session.pwd_err = true;
return res.redirect('/reg');
}
let pwd = util.mix(req.body.pwd);
let User = {
email: req.body.email,
pwd: pwd
}
userDao.setUser(User, function(err){
if (err) {
return res.redirect('/reg');
}
req.session.email = req.body.email;
return res.redirect('/login');
});
});
同时需要user和数据库的交互创建userDao,并且继承自baseDao
import { ObjectID } from 'mongodb';
import connect from '../../config/connect';
import BaseDao from './BaseDao';
import User from '../models/User';
import util from '../lib/util';
//继承Dao
class UserDao extends BaseDao {
//获取用户信息 登录等
getUser (user, callback) {
this.query(user, 'users', callback);
}
//用户注册 玩家 和管理员
saveUser (user, col, callback) {
let _that = this;
let model = Object.assign(JSON.parse(User), user);
this.query(model, col, function(err, u) {
//用户已经存在
if (u !== null) {
err = 'notnull';
return callback(err);
}
_that.save(model, col, callback);
});
};
//普通用户注册
setUser (user, callback) {
this.saveUser(user, 'users', callback);
}
updateUserOne(userUpdate, callback) {
let ID = {};
if (util.isString(userUpdate.id) ) {
ID = {_id: new ObjectID(userUpdate.id)};
} else {
ID = userUpdate.id;
}
this.updateOne('users', ID, {$set: userUpdate.field}, callback);
}
// 加入postId
updatePostId(userPost, callback) {
let _that = this;
this.updatePromise(userPost.id, 'postId').then(function(result) {
let postId = result.data || [];
postId.push(userPost.postId);
let userUpdate = {
id: result.id,
field: {
postId: postId
}
};
_that.updateUserOne(userUpdate, callback);
}, function(err) {
return err;
});
}
updatePromise(id, key) {
let _that = this;
let ID = {_id: new ObjectID(id)};
return new Promise(function(resolve, reject) {
_that.query(ID, 'users', function(err, rtn) {
if (err) {
reject(err);
} else {
let result = {data: rtn[key], id: ID};
resolve(result);
}
});
});
}
}
module.exports = UserDao;
import connect from '../../config/connect';
import { ObjectID } from 'mongodb';
class BaseDao {
//查询 field查询字段, col 集合或表
query(field, col, callback) {
connect.open(function(err, db) {
if (err) {
return callback(err);
}
//要查找的集合
db.collection(col, function(err, collection) {
//要查找的字段
collection.findOne(field, function(err, result){
connect.close();
if (err) {
return callback(err);
}
//成功
callback(null, result);
});
});
});
}
//查找排序 query={field: field, orderby: orderby, }
querySort(query, col, callback) {
connect.open(function(err, db) {
if (err) return callback(err);
db.collection(col, function(err, collection) {
if (query.limit) {
collection.find(query.field).sort(query.orderby).limit(query.limit).toArray(function(err, result) {
connect.close();
if (err) return callback(err);
callback(null, result);
});
} else {
collection.find(query.field).sort(query.orderby).toArray(function(err, result) {
connect.close();
if (err) return callback(err);
callback(null, result);
});
}
});
});
}
//查询首页全部
queryAll(col, query, callback) {
connect.open(function(err, db) {
if( err ) return callback(err);
db.collection(col, function(err, collection) {
collection.find().sort(query.sort).limit(query.limit).toArray(function(err, result) {
connect.close();
if (err) return callback(err);
callback(null, result);
});
});
});
}
//保存 新建
save(field, col, callback) {
connect.open(function(err, db) {
if (err) {
return callback(err);
}
db.collection(col, function(err, collection) {
//if(field._id) delete field._id;
collection.insert(field, {
safe: true
}, function(err, result) {
connect.close();
if (err) {
return callback(err);
}
callback(null, result);
});
});
});
}
//只修改一个 根据Id查找
updateOne(col, id, updateField, callback) {
connect.open(function(err, db) {
if (err) {
return callback(err);
}
db.collection(col, function(err, collection) {
collection.updateOne(id, updateField, function(err, result) {
connect.close();
if (err) {
return callback(err);
}
//成功
callback(null, result);
});
});
});
}
//更新
updates(col, field, updateFields, callback) {
connect.open(function(err, db) {
if (err) {
return callback(err);
}
db.collection(col, function(err, collection) {
collection.update(field, updateFields, function(err, result) {
connect.close();
if (err) {
return callback(err);
}
//成功
callback(null, result);
});
});
});
}
//删除一个表
removeOne(col, field, callback) {
connect.open(function(err, db) {
if (err) {
return callback(err);
}
db.collection(col, function(err, collection) {
collection.removeOne(field, function(err, result) {
connect.close();
if (err) {
return callback(err);
}
//成功
callback(null, result);
});
});
});
}
}
module.exports = BaseDao;
工具类
import crypto from 'crypto';
class util {
static isNull(str) {
if (str.trim() == null || str.trim() == '') {
//为空
return true;
}
}
//密码加密混淆
static mix(str) {
let sha1 = crypto.createHash('sha1');
return sha1.update(str).digest('hex');
}
//字符串是否相等
static isEqual(str, str2) {
if(str.trim() === str2.trim()) {
return true;
}
}
//未登录 1
static notLogin = function(req, res) {
if(!req.session.user){
req.flash('isLogin', '1');
res.redirect('/login');
return true;
}
return false;
}
//已经登录 0
static login(req, res) {
if(req.session.user){
if(req.session.user['_id'] === req.params._id) {
req.flash('isLogin', '0');
return true;
} else {
return false;
}
}
return false;
}
//json里出去空值
static mergeJson(basedata, newdata) {
let merge = {};
for (let key1 in basedata) {
merge[key1] = basedata[key1];
}
for (let key in newdata) {
if ( newdata[key] !== '' && newdata !== null) {
merge[key] = newdata[key];
}
}
return merge;
}
//字符串
static isString(str) {
if(typeof str === 'string' && str.constructor === String ) return true;
}
//图片路径
static getPath(str, aim) {
var reg = new RegExp(aim + '\\/(\\S*)');
return str.match(reg)[1];
}
//时间格式化
static format(str, mat) {
let d, date = new Date(str),
year = date.getFullYear(),
month = date.getMonth() + 1,
day = date.getDate();
switch(mat){
case 'year':
d = year
break;
case 'month':
d = month;
break
case 'day':
d = day;
default:
d = year+'-'+month+'-'+day;
}
return d;
}
}
module.exports = util;
做到此发觉痛点是和数据库mongodb交互用mongodb = require('mongodb'),很别扭,应该用mongoose,不过既然都这么用了,就都应该学习下。
接下来进入登录界面
登录的路由
//进入登录页面
router.get('/login', function(req, res) {
let error_name = req.flash('error_name');
res.render('login/index', {
title: '登录',
error_name: req.flash('error_name'),
error_pwd: req.flash('error_pwd'),
isLogin: req.flash('isLogin'),
email: req.session.email,
});
});
//登录
router.post('/login', function(req, res) {
if (util.isNull(req.body.email)) {
req.flash('error_name', 'error_name');
return res.redirect('/login');
}
if (util.isNull(req.body.pwd)) {
req.flash('error_pwd', false);
return res.redirect('/login');
}
//用户查找
let pwd = util.mix(req.body.pwd);
let User = {
email: req.body.email,
pwd: pwd
}
userDao.getUser(User, function(err, result) {
if (err) {
return res.redirect('/login');
}
if (result === null) {
return res.redirect('/reg');
}
if (req.session.user && req.session.user['email'] === req.params.email) {
delete req.session.user;
}
req.session.user = {
_id: result._id,
email: result.email,
};
return res.redirect('/personal/'+ result._id);
});
});
<%- include("../layouts/header", {cssAry: ['/style/login/index.css']}) %>
<div class="body flex center">
<div class="index-main">
<div class="index-header">
<h1 class="logo"></h1>
<p class="describe">一条大河波浪宽</p>
</div>
<div class="form-name flex center">
<a class="form-active" href="/login">登录</a>
<a href="/reg">注册</a>
</div>
<div class="index-form">
<form method="post" action="/login">
<input type="hidden" name="_csrf" value="<%= csrf %>">
<div class="form-item">
<input type="input" name="email" placeholder="邮箱"/>
</div>
<div class="form-item">
<input type="password" name="pwd" placeholder="请输入密码">
</div>
<div class="button-item">
<input class="btn btn-sure" type="submit" value="注册">
</div>
</form>
</div>
</div>
</div>
<%- include("../layouts/footer", {jsAry: []}) %>
登录成功后进入个人中心页面personal,根据id进入同时用到
import async from 'async';
当然不用的话可以用es6的promise(resolve,reject), resolve就是成功后的参数传递,reject就是错误异常时。
//个人中心
router.get('/personal/:_id', function(req, res) {
let ID = req.params._id;
let boo = util.login(req, res);
async.waterfall([function(callback){
userDao.getUser({_id: new ObjectID(ID)}, function(err, result) {
if(err) return false;
callback(null, result)
});
}, function(arg1, callback) {
let options = {
field: {id: ID},
orderby: {time: -1}
}
postDao.queryPostSort(options, function(err, rtn) {
let json = {
title: '个人中心',
id: ID,
usermsg: arg1.usermsg,
postId: arg1.postId,
postSize: arg1['postId'].length,
postList: rtn,
login: boo
}
callback(null, json);
});
}], function(err, result) {
res.render('personal/index', result);
});
});
用户主要的字段信息有如下
let user = {
"email" : "",
"pwd" : "",
"postId" :[],
"usermsg" : {
"username" : "",
"userwork" : "",
"userdegree" : "",
"userarea" : "",
"usersex" : "",
"userintr" : "",
"userhead": "",
},
"postclass":{
0: "博文"
}, //作者文章分类
}
当点击资料编辑时,进入资料编辑页面
//个人资料修改
router.get('/personal/edit/:_id', function(req, res) {
let boo = util.notLogin(req, res);
if(boo) return false;
req.session.article = false;
let ID = req.session.user['_id'];
async.parallel([function(callback) {
userDao.getUser({_id: new ObjectID(ID)}, function(err, result) {
if(err) return false;
callback(null, result.usermsg);
});
}, function(callback) {
//头像上传
mkdirs('/var/www/near/public/images/users/' + req.session.user['_id'] + '/avatar/', '0777');
callback(null, 'ok');
}], function(err, results){
res.render('personal/edit', {
title: '个人资料修改',
id: ID,
usermsg: results[0],
login: true
});
});
});
router.post('/personal/edit/:_id', function (req, res) {
let boo = util.notLogin(req, res);
if(boo) return false;
if(req.session.user['_id'] !== req.params._id) return res.redirect('login');
let Upload = upload.single("userhead"); //头像图片上传,未把头像图片单独做出来,选中后ajax提交
Upload(req, res, function(err) {
if (err) {
return ;
}
let id = req.session.user['_id'];
userDao.updatePromise(id, 'usermsg').then(function(result) {
let data = util.mergeJson(result.data, req.body);
data['userhead'] = req.session.postcover;
req.session['postcover'] = null;
let userUpdate = {
id: result.id,
field: {usermsg: data}
};
userDao.updateUserOne(userUpdate, function() {
return res.redirect('/personal/'+ id);
})
}, function(err) {
return res.redirect('/reg');
});
});
import upload from '../lib/multer.config';
import multer from 'multer';
import fs from 'fs' ;
var storage = multer.diskStorage({
destination: function (req, file, cb) {
let newDestination = '/var/www/near/public/images/users/' + req.session.user['_id'];
req.session.article ? (newDestination += '/posts/') : (newDestination += '/avatar/');
cb(null, newDestination);
},
filename: function (req, file, cb) {
let originalname = file.originalname,
start = originalname.lastIndexOf('.'),
len = originalname.length,
type = originalname.substring(start+1, len),
filename = Date.now() + '.' + type;
req.session.postcover = filename;
cb(null, filename);
}
});
let upload = multer(
{
limits: {
fieldNameSize: 100,
fileSize: 60000000
},
storage: storage
}
);
module.exports = upload;
ejs<%- include("../layouts/header", {cssAry: ['/style/personal/edit.css']}) %>
<div class="body">
<%- include("../layouts/main_head", {publishBtn: true}) %>
<div class="main">
<form action="/personal/edit/<%= id %>?_csrf=<%= csrf %>" method="POST" id="userform" enctype="multipart/form-data">
<div class="form-item useravatar" id="useravatar">
<img src="/<%= usermsg.userhead ? ('images/users/' + id +'/avatar/' + usermsg.userhead) : 'images/default_avatar.jpg' %>">
<em class="cover" id="cover"></em>
<input class="input-file item-val" type="file" id="input-file" name="userhead">
</div>
<div class="form-item">
<div class="flex center">
<span class="profile-name"><%= usermsg.username || "暂未填写" %></span>
<a class="modify-btn" data-type="center" href="javascript:;">修改</a>
</div>
<div class="modify-content flex-center-h">
<input class="modify-name item-val" type="text" placeholder="请填写昵称" name="username">
<a href="javascript:;" class="btn btn-cancel">取消</a>
<a href="javascript:;" class="btn btn-sure">确定</a>
</div>
</div>
<div class="form-item flex">
<div class="item-name">职业</div>
<div>
<p class="modify-msg flex">
<span class="modify-file"><%= usermsg.userwork || "暂未填写" %></span>
<a class="modify-btn" data-type="com" href="javascript:;">修改</a>
</p>
<div class="modify-content flex-center-h">
<input class="modify-name item-val" type="text" placeholder="请输入职业" name="userwork">
<a href="javascript:;" class="btn btn-cancel">取消</a>
<a href="javascript:;" class="btn btn-sure">确定</a>
</div>
</div>
</div>
<div class="form-item flex">
<div class="item-name">学位</div>
<div>
<p class="modify-msg flex">
<span class="modify-file"><%= usermsg.userdegree || "暂未填写" %></span>
<a class="modify-btn" data-type="com" href="javascript:;">修改</a>
</p>
<div class="modify-content flex-center-h">
<input class="modify-name item-val" type="text" placeholder="请输入学位" name="userdegree">
<a href="javascript:;" class="btn btn-cancel">取消</a>
<a href="javascript:;" class="btn btn-sure">确定</a>
</div>
</div>
</div>
<div class="form-item flex">
<div class="item-name">地区</div>
<div>
<p class="modify-msg flex">
<span class="modify-file"><%= usermsg.userarea || "暂未填写" %></span>
<a class="modify-btn" data-type="com" href="javascript:;">修改</a>
</p>
<div class="modify-content flex-center-h">
<input class="modify-name item-val" type="text" placeholder="请填写地区" name="userarea">
<a href="javascript:;" class="btn btn-cancel">取消</a>
<a href="javascript:;" class="btn btn-sure">确定</a>
</div>
</div>
</div>
<div class="form-item flex">
<div class="item-name">性别</div>
<div>
<p class="modify-msg flex">
<span class="modify-file"><% if(usermsg.usersex) { %>
<%= usermsg.usersex == 0 ? "女" : "男" %>
<% } else { %>
<%= "暂未填写" %>
<% } %></span>
<a class="modify-btn" data-type="radio" href="javascript:;">修改</a>
</p>
<div class="modify-content flex-center-h">
<label><input class="item-val" type="radio" name="usersex" value="1"> <em>男</em></label>
<label><input class="item-val" type="radio" name="usersex" value="0"> <em>女</em></label>
<a href="javascript:;" class="btn btn-cancel">取消</a>
<a href="javascript:;" class="btn btn-sure">确定</a>
</div>
</div>
</div>
<div class="form-item flex">
<div class="item-name">介绍自己</div>
<div>
<p class="modify-msg flex">
<span class="modify-file"><%= usermsg.userintr || "暂未填写" %></span>
<a class="modify-btn" data-type="com" href="javascript:;">修改</a>
</p>
<div class="modify-content modify-content-ta">
<textarea class="modify-name item-val" placeholder="请简单的介绍自己" name="userintr"></textarea>
<a href="javascript:;" class="btn btn-cancel">取消</a>
<a href="javascript:;" class="btn btn-sure">确定</a>
</div>
</div>
</div>
</form>
</div>
</div>
<%- include("../layouts/footer", {jsAry: ['javascripts/personal/edit.js']}) %>
目录结构
有需要的交流的可以加个好友
想学习点新东西就是开手写,就写了个简单的实现,利用node实现一个博客。主要的内容就在首页也能看到了。
话不多说,expressjs怎么创建项目选择ejs模板,之前的文章都写过了。
首先从用户注册开始,有了用户才能根据id查找文章。
<%- include("../layouts/header", {cssAry: ['/style/reg/index.css']}) %>
<div class="body flex center">
<div class="index-main">
<div class="index-header">
<h1 class="logo"></h1>
<p class="describe">一条大河波浪宽</p>
</div>
<div class="form-name flex center">
<a class="form-active" href="/reg">注册</a>
<a href="/login">登录</a>
</div>
<div class="index-form">
<form method="post" action="/reg">
<input type="hidden" name="_csrf" value="<%= csrf %>">
<div class="form-item">
<input type="input" name="email" placeholder="邮箱"/>
</div>
<div class="form-item">
<input type="password" name="pwd" placeholder="密码(大于六位)">
</div>
<div class="form-item">
<input type="password" name="repeatpwd" placeholder="确定密码">
</div>
<div class="button-item">
<input class="btn btn-sure" type="submit" value="注册">
</div>
</form>
</div>
</div>
</div>
<%- include("../layouts/footer", {jsAry: []}) %>
include 传递参数时就把需要的css 和js 传递到head 和foot模块里
header.ejs
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0">
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<link rel="shortcut icon" type="image/x-icon" href="/images/favicon3.ico">
<meta name="csrf-token" content="<%= csrf %>">
<title><%= title %></title>
<link rel='stylesheet' href='/style/main.css' />
<% for(var i = 0, item; item = cssAry[i++]; ) {%>
<link rel='stylesheet' href='<%= item %>'/>
<% } %>
</head>
<body>
footer.ejs
<script type="text/javascript" src="http://lib.sinaapp.com/js/jquery/2.2.4/jquery-2.2.4.min.js"></script>
<script type="text/javascript" src="/javascripts/main.js"></script>
<% for(var i = 0, item; item = jsAry[i++]; ) {%>
<script type="text/javascript" src="/<%= item %>"></script>
<% } %>
</body>
</html>
route路由,编写对应再到reg.ejs的页面
//注册
router.get('/reg', function(req, res) {
res.render('reg/index', {
title: '注册',
pwd_err: req.session.pwd_err
});
});
//注册提交
router.post('/reg', function(req, res) {
if(!util.isEqual(req.body.pwd, req.body.repeatpwd)) {
req.session.pwd_err = true;
return res.redirect('/reg');
}
let pwd = util.mix(req.body.pwd);
let User = {
email: req.body.email,
pwd: pwd
}
userDao.setUser(User, function(err){
if (err) {
return res.redirect('/reg');
}
req.session.email = req.body.email;
return res.redirect('/login');
});
});
同时需要user和数据库的交互创建userDao,并且继承自baseDao
import { ObjectID } from 'mongodb';
import connect from '../../config/connect';
import BaseDao from './BaseDao';
import User from '../models/User';
import util from '../lib/util';
//继承Dao
class UserDao extends BaseDao {
//获取用户信息 登录等
getUser (user, callback) {
this.query(user, 'users', callback);
}
//用户注册 玩家 和管理员
saveUser (user, col, callback) {
let _that = this;
let model = Object.assign(JSON.parse(User), user);
this.query(model, col, function(err, u) {
//用户已经存在
if (u !== null) {
err = 'notnull';
return callback(err);
}
_that.save(model, col, callback);
});
};
//普通用户注册
setUser (user, callback) {
this.saveUser(user, 'users', callback);
}
updateUserOne(userUpdate, callback) {
let ID = {};
if (util.isString(userUpdate.id) ) {
ID = {_id: new ObjectID(userUpdate.id)};
} else {
ID = userUpdate.id;
}
this.updateOne('users', ID, {$set: userUpdate.field}, callback);
}
// 加入postId
updatePostId(userPost, callback) {
let _that = this;
this.updatePromise(userPost.id, 'postId').then(function(result) {
let postId = result.data || [];
postId.push(userPost.postId);
let userUpdate = {
id: result.id,
field: {
postId: postId
}
};
_that.updateUserOne(userUpdate, callback);
}, function(err) {
return err;
});
}
updatePromise(id, key) {
let _that = this;
let ID = {_id: new ObjectID(id)};
return new Promise(function(resolve, reject) {
_that.query(ID, 'users', function(err, rtn) {
if (err) {
reject(err);
} else {
let result = {data: rtn[key], id: ID};
resolve(result);
}
});
});
}
}
module.exports = UserDao;
import connect from '../../config/connect';
import { ObjectID } from 'mongodb';
class BaseDao {
//查询 field查询字段, col 集合或表
query(field, col, callback) {
connect.open(function(err, db) {
if (err) {
return callback(err);
}
//要查找的集合
db.collection(col, function(err, collection) {
//要查找的字段
collection.findOne(field, function(err, result){
connect.close();
if (err) {
return callback(err);
}
//成功
callback(null, result);
});
});
});
}
//查找排序 query={field: field, orderby: orderby, }
querySort(query, col, callback) {
connect.open(function(err, db) {
if (err) return callback(err);
db.collection(col, function(err, collection) {
if (query.limit) {
collection.find(query.field).sort(query.orderby).limit(query.limit).toArray(function(err, result) {
connect.close();
if (err) return callback(err);
callback(null, result);
});
} else {
collection.find(query.field).sort(query.orderby).toArray(function(err, result) {
connect.close();
if (err) return callback(err);
callback(null, result);
});
}
});
});
}
//查询首页全部
queryAll(col, query, callback) {
connect.open(function(err, db) {
if( err ) return callback(err);
db.collection(col, function(err, collection) {
collection.find().sort(query.sort).limit(query.limit).toArray(function(err, result) {
connect.close();
if (err) return callback(err);
callback(null, result);
});
});
});
}
//保存 新建
save(field, col, callback) {
connect.open(function(err, db) {
if (err) {
return callback(err);
}
db.collection(col, function(err, collection) {
//if(field._id) delete field._id;
collection.insert(field, {
safe: true
}, function(err, result) {
connect.close();
if (err) {
return callback(err);
}
callback(null, result);
});
});
});
}
//只修改一个 根据Id查找
updateOne(col, id, updateField, callback) {
connect.open(function(err, db) {
if (err) {
return callback(err);
}
db.collection(col, function(err, collection) {
collection.updateOne(id, updateField, function(err, result) {
connect.close();
if (err) {
return callback(err);
}
//成功
callback(null, result);
});
});
});
}
//更新
updates(col, field, updateFields, callback) {
connect.open(function(err, db) {
if (err) {
return callback(err);
}
db.collection(col, function(err, collection) {
collection.update(field, updateFields, function(err, result) {
connect.close();
if (err) {
return callback(err);
}
//成功
callback(null, result);
});
});
});
}
//删除一个表
removeOne(col, field, callback) {
connect.open(function(err, db) {
if (err) {
return callback(err);
}
db.collection(col, function(err, collection) {
collection.removeOne(field, function(err, result) {
connect.close();
if (err) {
return callback(err);
}
//成功
callback(null, result);
});
});
});
}
}
module.exports = BaseDao;
工具类
import crypto from 'crypto';
class util {
static isNull(str) {
if (str.trim() == null || str.trim() == '') {
//为空
return true;
}
}
//密码加密混淆
static mix(str) {
let sha1 = crypto.createHash('sha1');
return sha1.update(str).digest('hex');
}
//字符串是否相等
static isEqual(str, str2) {
if(str.trim() === str2.trim()) {
return true;
}
}
//未登录 1
static notLogin = function(req, res) {
if(!req.session.user){
req.flash('isLogin', '1');
res.redirect('/login');
return true;
}
return false;
}
//已经登录 0
static login(req, res) {
if(req.session.user){
if(req.session.user['_id'] === req.params._id) {
req.flash('isLogin', '0');
return true;
} else {
return false;
}
}
return false;
}
//json里出去空值
static mergeJson(basedata, newdata) {
let merge = {};
for (let key1 in basedata) {
merge[key1] = basedata[key1];
}
for (let key in newdata) {
if ( newdata[key] !== '' && newdata !== null) {
merge[key] = newdata[key];
}
}
return merge;
}
//字符串
static isString(str) {
if(typeof str === 'string' && str.constructor === String ) return true;
}
//图片路径
static getPath(str, aim) {
var reg = new RegExp(aim + '\\/(\\S*)');
return str.match(reg)[1];
}
//时间格式化
static format(str, mat) {
let d, date = new Date(str),
year = date.getFullYear(),
month = date.getMonth() + 1,
day = date.getDate();
switch(mat){
case 'year':
d = year
break;
case 'month':
d = month;
break
case 'day':
d = day;
default:
d = year+'-'+month+'-'+day;
}
return d;
}
}
module.exports = util;
做到此发觉痛点是和数据库mongodb交互用mongodb = require('mongodb'),很别扭,应该用mongoose,不过既然都这么用了,就都应该学习下。
接下来进入登录界面
登录的路由
//进入登录页面
router.get('/login', function(req, res) {
let error_name = req.flash('error_name');
res.render('login/index', {
title: '登录',
error_name: req.flash('error_name'),
error_pwd: req.flash('error_pwd'),
isLogin: req.flash('isLogin'),
email: req.session.email,
});
});
//登录
router.post('/login', function(req, res) {
if (util.isNull(req.body.email)) {
req.flash('error_name', 'error_name');
return res.redirect('/login');
}
if (util.isNull(req.body.pwd)) {
req.flash('error_pwd', false);
return res.redirect('/login');
}
//用户查找
let pwd = util.mix(req.body.pwd);
let User = {
email: req.body.email,
pwd: pwd
}
userDao.getUser(User, function(err, result) {
if (err) {
return res.redirect('/login');
}
if (result === null) {
return res.redirect('/reg');
}
if (req.session.user && req.session.user['email'] === req.params.email) {
delete req.session.user;
}
req.session.user = {
_id: result._id,
email: result.email,
};
return res.redirect('/personal/'+ result._id);
});
});
<%- include("../layouts/header", {cssAry: ['/style/login/index.css']}) %>
<div class="body flex center">
<div class="index-main">
<div class="index-header">
<h1 class="logo"></h1>
<p class="describe">一条大河波浪宽</p>
</div>
<div class="form-name flex center">
<a class="form-active" href="/login">登录</a>
<a href="/reg">注册</a>
</div>
<div class="index-form">
<form method="post" action="/login">
<input type="hidden" name="_csrf" value="<%= csrf %>">
<div class="form-item">
<input type="input" name="email" placeholder="邮箱"/>
</div>
<div class="form-item">
<input type="password" name="pwd" placeholder="请输入密码">
</div>
<div class="button-item">
<input class="btn btn-sure" type="submit" value="注册">
</div>
</form>
</div>
</div>
</div>
<%- include("../layouts/footer", {jsAry: []}) %>
登录成功后进入个人中心页面personal,根据id进入同时用到
import async from 'async';
当然不用的话可以用es6的promise(resolve,reject), resolve就是成功后的参数传递,reject就是错误异常时。
//个人中心
router.get('/personal/:_id', function(req, res) {
let ID = req.params._id;
let boo = util.login(req, res);
async.waterfall([function(callback){
userDao.getUser({_id: new ObjectID(ID)}, function(err, result) {
if(err) return false;
callback(null, result)
});
}, function(arg1, callback) {
let options = {
field: {id: ID},
orderby: {time: -1}
}
postDao.queryPostSort(options, function(err, rtn) {
let json = {
title: '个人中心',
id: ID,
usermsg: arg1.usermsg,
postId: arg1.postId,
postSize: arg1['postId'].length,
postList: rtn,
login: boo
}
callback(null, json);
});
}], function(err, result) {
res.render('personal/index', result);
});
});
用户主要的字段信息有如下
let user = {
"email" : "",
"pwd" : "",
"postId" :[],
"usermsg" : {
"username" : "",
"userwork" : "",
"userdegree" : "",
"userarea" : "",
"usersex" : "",
"userintr" : "",
"userhead": "",
},
"postclass":{
0: "博文"
}, //作者文章分类
}
当点击资料编辑时,进入资料编辑页面
//个人资料修改
router.get('/personal/edit/:_id', function(req, res) {
let boo = util.notLogin(req, res);
if(boo) return false;
req.session.article = false;
let ID = req.session.user['_id'];
async.parallel([function(callback) {
userDao.getUser({_id: new ObjectID(ID)}, function(err, result) {
if(err) return false;
callback(null, result.usermsg);
});
}, function(callback) {
//头像上传
mkdirs('/var/www/near/public/images/users/' + req.session.user['_id'] + '/avatar/', '0777');
callback(null, 'ok');
}], function(err, results){
res.render('personal/edit', {
title: '个人资料修改',
id: ID,
usermsg: results[0],
login: true
});
});
});
router.post('/personal/edit/:_id', function (req, res) {
let boo = util.notLogin(req, res);
if(boo) return false;
if(req.session.user['_id'] !== req.params._id) return res.redirect('login');
let Upload = upload.single("userhead"); //头像图片上传,未把头像图片单独做出来,选中后ajax提交
Upload(req, res, function(err) {
if (err) {
return ;
}
let id = req.session.user['_id'];
userDao.updatePromise(id, 'usermsg').then(function(result) {
let data = util.mergeJson(result.data, req.body);
data['userhead'] = req.session.postcover;
req.session['postcover'] = null;
let userUpdate = {
id: result.id,
field: {usermsg: data}
};
userDao.updateUserOne(userUpdate, function() {
return res.redirect('/personal/'+ id);
})
}, function(err) {
return res.redirect('/reg');
});
});
import upload from '../lib/multer.config';
import multer from 'multer';
import fs from 'fs' ;
var storage = multer.diskStorage({
destination: function (req, file, cb) {
let newDestination = '/var/www/near/public/images/users/' + req.session.user['_id'];
req.session.article ? (newDestination += '/posts/') : (newDestination += '/avatar/');
cb(null, newDestination);
},
filename: function (req, file, cb) {
let originalname = file.originalname,
start = originalname.lastIndexOf('.'),
len = originalname.length,
type = originalname.substring(start+1, len),
filename = Date.now() + '.' + type;
req.session.postcover = filename;
cb(null, filename);
}
});
let upload = multer(
{
limits: {
fieldNameSize: 100,
fileSize: 60000000
},
storage: storage
}
);
module.exports = upload;
ejs<%- include("../layouts/header", {cssAry: ['/style/personal/edit.css']}) %>
<div class="body">
<%- include("../layouts/main_head", {publishBtn: true}) %>
<div class="main">
<form action="/personal/edit/<%= id %>?_csrf=<%= csrf %>" method="POST" id="userform" enctype="multipart/form-data">
<div class="form-item useravatar" id="useravatar">
<img src="/<%= usermsg.userhead ? ('images/users/' + id +'/avatar/' + usermsg.userhead) : 'images/default_avatar.jpg' %>">
<em class="cover" id="cover"></em>
<input class="input-file item-val" type="file" id="input-file" name="userhead">
</div>
<div class="form-item">
<div class="flex center">
<span class="profile-name"><%= usermsg.username || "暂未填写" %></span>
<a class="modify-btn" data-type="center" href="javascript:;">修改</a>
</div>
<div class="modify-content flex-center-h">
<input class="modify-name item-val" type="text" placeholder="请填写昵称" name="username">
<a href="javascript:;" class="btn btn-cancel">取消</a>
<a href="javascript:;" class="btn btn-sure">确定</a>
</div>
</div>
<div class="form-item flex">
<div class="item-name">职业</div>
<div>
<p class="modify-msg flex">
<span class="modify-file"><%= usermsg.userwork || "暂未填写" %></span>
<a class="modify-btn" data-type="com" href="javascript:;">修改</a>
</p>
<div class="modify-content flex-center-h">
<input class="modify-name item-val" type="text" placeholder="请输入职业" name="userwork">
<a href="javascript:;" class="btn btn-cancel">取消</a>
<a href="javascript:;" class="btn btn-sure">确定</a>
</div>
</div>
</div>
<div class="form-item flex">
<div class="item-name">学位</div>
<div>
<p class="modify-msg flex">
<span class="modify-file"><%= usermsg.userdegree || "暂未填写" %></span>
<a class="modify-btn" data-type="com" href="javascript:;">修改</a>
</p>
<div class="modify-content flex-center-h">
<input class="modify-name item-val" type="text" placeholder="请输入学位" name="userdegree">
<a href="javascript:;" class="btn btn-cancel">取消</a>
<a href="javascript:;" class="btn btn-sure">确定</a>
</div>
</div>
</div>
<div class="form-item flex">
<div class="item-name">地区</div>
<div>
<p class="modify-msg flex">
<span class="modify-file"><%= usermsg.userarea || "暂未填写" %></span>
<a class="modify-btn" data-type="com" href="javascript:;">修改</a>
</p>
<div class="modify-content flex-center-h">
<input class="modify-name item-val" type="text" placeholder="请填写地区" name="userarea">
<a href="javascript:;" class="btn btn-cancel">取消</a>
<a href="javascript:;" class="btn btn-sure">确定</a>
</div>
</div>
</div>
<div class="form-item flex">
<div class="item-name">性别</div>
<div>
<p class="modify-msg flex">
<span class="modify-file"><% if(usermsg.usersex) { %>
<%= usermsg.usersex == 0 ? "女" : "男" %>
<% } else { %>
<%= "暂未填写" %>
<% } %></span>
<a class="modify-btn" data-type="radio" href="javascript:;">修改</a>
</p>
<div class="modify-content flex-center-h">
<label><input class="item-val" type="radio" name="usersex" value="1"> <em>男</em></label>
<label><input class="item-val" type="radio" name="usersex" value="0"> <em>女</em></label>
<a href="javascript:;" class="btn btn-cancel">取消</a>
<a href="javascript:;" class="btn btn-sure">确定</a>
</div>
</div>
</div>
<div class="form-item flex">
<div class="item-name">介绍自己</div>
<div>
<p class="modify-msg flex">
<span class="modify-file"><%= usermsg.userintr || "暂未填写" %></span>
<a class="modify-btn" data-type="com" href="javascript:;">修改</a>
</p>
<div class="modify-content modify-content-ta">
<textarea class="modify-name item-val" placeholder="请简单的介绍自己" name="userintr"></textarea>
<a href="javascript:;" class="btn btn-cancel">取消</a>
<a href="javascript:;" class="btn btn-sure">确定</a>
</div>
</div>
</div>
</form>
</div>
</div>
<%- include("../layouts/footer", {jsAry: ['javascripts/personal/edit.js']}) %>
目录结构
有需要的交流的可以加个好友