ddms是基于express的一个表单管理系统,今天抽时间看了下它的代码,其实算不上源码学习,只是对它其中一些小的开发技巧做一些记录,希望以后在项目开发中能够实践下。
- 数据层封装
- 模块只对外暴露model,由业务层完成具体数据操作;
- 利用mongoose的schema的static属性,扩展常用、基础的操作
var form = new Schema({ user: {type: ObjectId, ref: 'User'}, project: {type: ObjectId, ref: 'Project'}, sid: {type: String, unique: true,'default': shortid.generate }, title: { type: String, required: true, default: 'New Form' }, desc: String, createDateTime: { type: Date, default: Date.now }, updateDateTime: { type: Date, default: Date.now }, schemata: Mixed }); form.static({ list: function (callback) { return this.find() .populate('user',{_id: 1,name: 1,email: 1,role: 1}) .populate('project',{_id: 1,name: 1,desc: 1}) .sort({_id: -1}) .exec(callback) }, listByProjectId: function (projectid,callback) { return this.find({project: projectid}) .populate('user',{_id: 1,name: 1,email: 1,role: 1}) .populate('project',{_id: 1,name: 1,desc: 1}) .sort({_id: -1}) .exec(callback); } }); module.exports = mongoose.model('Form', form);
- 充分利用schema type特性
- 充分利用schema type的例如gettersettervalidate等 参考:http://mongoosejs.com/docs/2.7.x/docs/schematypes.html。可以将原本业务层的很多处理直接交给mongodb.
var userSchema = new Schema({ email: { type: String, required: true, //需要校验
//给字段存储前线全部小写处理 set: function (value) { return value.trim().toLowerCase() },
//校验的方法 validate: [ function (email) { return (email.match(/[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/i) != null) }, 'Invalid email' ] }, //。。。。 twitter: Mixed });
- 利用ref来实现join,可以存在多个,如下:
var form = new Schema({ user: {type: ObjectId, ref: 'User'}, project: {type: ObjectId, ref: 'Project'}, sid: {type: String, unique: true,'default': shortid.generate },
form.static({ list: function (callback) { return this.find() .populate('user',{_id: 1,name: 1,email: 1,role: 1}) .populate('project',{_id: 1,name: 1,desc: 1}) .sort({_id: -1}) .exec(callback) }, listByProjectId: function (projectid,callback) { return this.find({project: projectid}) .populate('user',{_id: 1,name: 1,email: 1,role: 1}) .populate('project',{_id: 1,name: 1,desc: 1}) .sort({_id: -1}) .exec(callback); } });
- 充分利用app.use
- app.use在express中类似servlet里的filter,属于一种过滤器,它会在每个http请求中被调用
- ddms通过app.use向req对象中添加model
//app.js中 app.use(function (req, res, next) { if (!models.User) return next(new Error("No models.")); req.models = models; return next(); }); //route.js中 exports.showListByProjectId = function (req, res, next) { var pid = req.params.projectid; var pp = Promise.resolve( req.models.Project.findOne({_id: pid}) ); var fp = Promise.resolve( req.models.Form.listByProjectId(pid) ); Promise.all([pp,fp]) .then(function(docs){ res.render('forms/list', {project: docs[0],forms: docs[1]}); }).catch(function (error) { return next(error); }); };
- 采用bluebird的promise库做同步
之前一直用async,看了下promise,感觉非常清爽,同上例代码
- 利用app.get的多callback实现中间件的效果,如下:
app.get('/formdatas/:formid', authorize.editor, routes.formData.showList); app.get('/formdatas/create/:formid', authorize.editor, routes.formData.showCreateData); app.post('/formdatas/create/:formid', writeLog, authorize.editor, routes.formData.createData); app.get('/formdatas/update/:id', authorize.editor, routes.formData.showUpdateData); app.post('/formdatas/update/:id', writeLog, authorize.editor, routes.formData.updateData); app.get('/formdatas/delete/:id', writeLog, authorize.editor, routes.formData.deleteData); app.get('/formdatas/csv/:formid', writeLog, authorize.editor, routes.formData.getCSV);