What can node.js do? I still don’t know where it is widely used. I have no chance to come into contact with such projects. Just because I like it, I made a website and backend in my spare time. I deeply understand the truth that if you like a technology, you can play with it, but if you use it in a project, you must spend some time solving many problems.
Technology used:
express + jade
sqlite + sequelize
redis
1. About jade
Support include. For example: include ./includes/header header is a partial view, similar to asp.net user control.
Support extends. For example: extends ../layout uses the master page layout.
The for loop is also so simple.
each item in userList (userList variable passed by the server to the front end)
tr
td #{item.username}
td #{item.telephone}
td #{item.email}
Prefer append:
extends ../admin_layout
append head
link(rel='stylesheet', href='//m.sbmmt.com/stylesheets/font-awesome.css')
script(src='/javascripts/bootstrap.js')
script(src='/javascripts/bootstrap-wysiwyg.js')
script(src='/javascripts/jquery.hotkeys.js')
block content
append will put all the steps and styles behind the master page head.
2.sequelize implements the ORM framework. Support sqlite mysql mongodb
Definition model (article):
var Article = sequelize.define('Article',{
title:{
Type:Sequelize.STRING,
validate:{}
},
content:{type:Sequelize.STRING,validate:{}},
icon:{type:Sequelize.STRING,validate:{}},
iconname:{type:Sequelize.STRING},
sequencing:{type:Sequelize.STRING,validate:{}}
},{
classMethods:{
//Article Category
GetCountAll:function(objFun){
}//end getCountAll
}//end classMethods
});
Article.belongsTo(Category);
Article.belongsTo(Category); Each article has a category.
I wrote the paging related methods when initializing sequelize. In this way, when each model is defined, there will be this method (pageOffset, pageLimit).
var sequelize = new Sequelize('database', 'username', 'password', {
// sqlite! now!
dialect: 'sqlite',
// the storage engine for sqlite
// - default ':memory:'
storage: config.sqlitePath,
define:{
classMethods:{
pageOffset:function(pageNum){
if(isNaN(pageNum) || pageNum < 1){
pageNum = 1;
}
return (pageNum - 1) * this.pageLimit();
},
pageLimit:function(){
return 10; //每页显示10条
},
totalPages:function(totalNum){
var total =parseInt((totalNum this.pageLimit() - 1) / this.pageLimit()),
arrayTotalPages = [];
for(var i=1; i<= total; i ){
arrayTotalPages.push(i);
}
return arrayTotalPages;
}
},
instanceMethods:{
}
}
});
使用:
Article.findAndCountAll({include:[Category],offset:Article.pageOffset(req.query.pageNum), limit:Article.pageLimit()}).success(function(row){
res.render('article_list', {
title: '文章管理',
articleList : row.rows,
pages:{
totalPages:Article.totalPages(row.count),
currentPage:req.query.pageNum,
router:'article'
}
});
});
保存模型:
exports.add = function(req, res) {
var form = new formidable.IncomingForm();
form.uploadDir = path.join(__dirname, '../files');
form.keepExtensions = true;
form.parse(req, function(err, fields,files){
var //iconPath = files.icon.path,
//index = iconPath.lastIndexOf('/') <= 0 ? iconPath.lastIndexOf('\') : iconPath.lastIndexOf('/') ,
icon = path.basename(files.icon.path), // iconPath.substr(index 1,iconPath.length - index),
iconname = files.icon.name;
var title = fields.title;
id = fields.articleId;
title = fields.title,
content = fields.content,
mincontent = fields.mincontent,
sequencing=fields.sequencing == 0 ? 0 : 1,
category = fields.category;
Article.sync(); //如果不存在就创建表。
Category.find(category).success(function(c){
var article = Article.build({
title : title,
content:content,
mincontent:mincontent,
icon:icon,
iconname:iconname,
sequencing:sequencing
});
article.save()
.success(function(a){
a.setCategory(c);
return res.redirect('/admin/article');
});
}); //end category
});
}
path.basename:
//iconPath = files.icon.path,
//index = iconPath.lastIndexOf('/') <= 0 ? iconPath.lastIndexOf('\') : iconPath.lastIndexOf('/') ,
icon = path.basename(files.icon.path), // iconPath.substr(index 1,iconPath.length - index),
获取文件名,比如:/a/b/aa.txt => aa.txt. 最初时候我使用截取字符串,也能实现,但是操作系统不一样的话就会有问题。mac使用'/' . window下面是'\',我也是部署完成之后才发现的问题 。 后来发现path.basename 直接替换(文档阅读的少,就吃亏啊)。对node.js的好感在加1分。:)
3. redis 缓存经常查询,而且很少变化的数据。
getCountAll:function(objFun){
redis.get('articles_getCountAll', function(err,reply){
if(err){
console.log(err);
return;
}
if(reply === null){
db.all('SELECT count(articles.CategoryId) as count,categories.name,categories.id FROM articles left join categories on articles.categoryID = categories.id group by articles.CategoryId ', function(err,row){
redis.set('articles_getCountAll',JSON.stringify(row));
objFun(row);
});
}else{
objFun(reply);
}
});
This method is defined in the model layer. Because it is Express, it is developed using MVC as much as possible. In fact, route implements the controller layer function (the route folder should be named controller).