模型是您与数据库交互的一些文件。它们包含处理数据所需的所有方法和函数。它们不仅包含创建、读取、更新和删除的方法,还包含业务逻辑。例如,如果您有汽车模型,则可以使用mountTyres方法。在您的数据库中,您应该为每种类型的数据至少创建一个文件。在我们的例子中,我们有用户和评论,所以我们有用户模型和评论模型。有时,当模型文件很大时,最好根据内部逻辑将模型文件分成几个文件。你应该让你的模型独立于外界。模型不应相互引用。他们不需要知道哪个控制器调用了它们。它们不应该接收请求或响应对象,它们不应该返回http错误,但它们应该返回模型错误。所有这些将使您的模型更易于维护。因为它们是独立的,所以它们经过了很好的测试。模型可以移动到任何需要的地方。改变一个模型不应该做任何其他事情,因为它是独立的。基于上面提到的几点,让我们看看如何实现我们示例中的模型。下面是评论模型。vardb=require('../db')//在你的数据库中创建新评论并返回它的id//在你的数据库中创建一个新评论exports.create=function(user,text,cb){varcomment={user:user,text:text,date:newDate().toString()}db.save(comment,cb)}//获取特定评论exports.get=function(id,cb){db.fetch({id:id},function(err,docs){if(err)returncb(err)cb(null,docs[0])})}//获取所有评论exports.all=function(cb){db.fetch({},cb)}//获取特定用户的所有评论exports.allByUser=function(user,cb){db.fetch({user:user},cb)}不包括用户模型。评论模型不关心它是什么,它只关心它是如何存储的。vardb=require('../db'),crypto=require('crypto')hash=function(password){returncrypto.createHash('sha1').update(password).digest('base64')}exports.create=function(name,email,password,cb){varuser={name:name,email:email,password:hash(password),}db.save(user,cb)}exports.get=function(id,cb){db.fetch({id:id},function(err,docs){if(err)returncb(err)cb(null,docs[0])})}exports.authenticate=function(电子邮件,密码){db.fetch({email:email},function(err,docs){if(err)returncb(err)if(docs.length===0)returncb()user=docs[0]if(user.password===hash(password)){cb(null,docs[0])}else{cb()}})}exports.changePassword=function(id,password,cb){db.update({id:id},{password:hash(password)},function(err,affected){if(err)returncb(err)cb(null,affected>0)})}除了需要创建和管理的users除了功能之外,还有用于用户身份验证和密码管理的方法。同样,该模型不知道其他模型、控制器或应用程序的其他部分已经存在。Views文件夹包含您的应用程序需要呈现的所有模板。通常,团队中的设计师在这里工作。您希望每个控制器模板都有一个子文件夹。这样,您将为同一任务组合模板。选择模板语言可能会让人感到困惑,因为有太多的选择。我们最喜欢的模板语言Jade和Mustache,我们一直都在使用。Jade非常适合生成html页面。它使编写html标签更短、更易读。它还可以将JavaScript用于条件和迭代。另一方面,Mustache专注于渲染各种模板,提供尽可能少的逻辑运算符和操作数据的方法。这非常适合编写非常干净的模板,这些模板专注于显示数据而不是操作数据。编写好的模板的最佳做法是避免在模板中进行任何处理。如果您的数据需要在显示之前进行处理,请在您的控制器中进行。还要避免添加太多逻辑,特别是如果可以将此逻辑移至控制器。doctypehtmlhtmlheadtitleYourcommentwebappbodyh1欢迎在评论article.Comment.Comment-date=comment.date.Comment-text=comment.text中留下您的评论每条评论如您所见,呈现此模板时,预计已处理的数据。Controllers这是一个文件夹,你将在这个文件夹中定义你的应用程序的所有路由。您的控制器将处理Web请求,为用户提供模板,并与您的模型交互以处理和检索数据。这是连接和控制您的Web应用程序的粘合剂。通常,应用程序的每个逻辑部分至少有一个文件。例如,一个文件处理评论,另一个文件处理关于用户的请求,等等。来自同一控制器的所有路由都具有相同的前缀是一种很好的做法。例如/comments/all和/comments/new。有时很难决定什么应该进入控制器,什么应该进入模型。最佳做法是永远不要直接访问数据库。它永远不应该调用数据库提供的write、update、fetch方法,而应该依赖模型中的方法。例如,如果你有一个汽车模型,你想在这辆车上安装4个轮子,控制器将不会调用db.update(id,{wheels:4}),但会调用类似car.mountwheels(id,4)这样的方法。下面是负责评论的控制器。varexpress=require('express'),router=express.Router(),Comment=require('../models/comment'),auth=require('../middlewares/auth')router.post('/',auth,function(req,res){user=req.user.idtext=req.body.textComment.create(user,text,function(err,comment){res.redirect('/')})})router.get('/:id',function(req,res){Comment.get(req.params.id,function(err,comment){res.render('comments/comment',{comment:comment})})})module.exports=router在controller文件夹下,还有一个index.js文件夹。它的目的是加载所有其他控制器,并可能定义一些没有相同前缀的路径,例如主页路由。varexpress=require('express'),router=express.Router(),Comment=require('../models/comment')router.use('/comments',require('./comments'))路由器.use('/users',require('./users'))//不同于评论和用户,主页不需要前缀(评论或用户)router.get('/',function(req,res){Comments.all(function(err,comments){res.render('index',{comments:comments})})})module.exports=router这个文件会处理你所有的路由。您的应用程序必须在启动时加载的唯一路由器。Middlewares在此文件夹中,您将存储所有Express中间件。中间件的目的是提取将跨多个请求执行并通常修改请求/响应对象的通用控制器代码。就像控制器一样,中间件永远不应该访问数据库,相反,对于它想要完成的每项任务,它应该使用你的模型。下面是来自middlewares/users.js文件的用户中间件。其目的是加载请求用户。User=require('../models/user')module.exports=function(req,res,next){if(req.session&&req.session.user){User.get(req.session.user,function(err,user){if(user){req.user=user}else{deletereq.userdeletereq.session.user}next()})}else{next()}}这个中间件使用用户模型,而且它不能直接访问数据库。下一步,授权中间件,当你想防止对同一路由的未授权访问时,你可以使用这个中间件。module.exports=function(req,res,next){if(req.user){next()}else{res.status(401).end()}}它没有任何外部依赖。如果您查看上面的控制器文件,您可以了解它是如何应用的。Helpers文件夹包含在多个模型、中间件或控制器中使用的有用代码,但助手不属于模型、中间件或控制器的类别。通常,对于不同的常见任务,您会有不同的文件。一个例子是提供管理日期和时间的方法的帮助文件。公共此文件仅提供静态文件。通常,它会有子文件夹,如css、libs、用于css样式的img、图像和javascript库(如jQuery)。此文件夹的最佳实践不是由您的应用程序提供服务,而是由Nginx或Apache服务器提供服务,这比Node提供静态文件服务更好。测试每个项目都需要测试,您需要将所有测试组合在一起。为了帮助管理它们,您将它们分开在不同的子文件中。控制器助手模型中间件集成ui
