上一节已经实现了登录、注册、发表文章和文章读取的功能,今天咱加上评论、文章页面和作者页面。
评论只能在进入文章页面后才能进行,所以咱们先写文章页面。
在上一节的代码中,我已经给文章标题添加了超链接了,
<a href="/<%= post.user %>/<%= post.time.day%>/<%= post.title %>"><%= post.title %></a>根据这个链接地址,进入文章页面的路由控制就可以写成这样:
app.get('/:user/:time/:title', function(req,res){ User.get(req.params.user,function(err, user){ Post.getOne(req.params.user, req.params.time, req.params.title, function(err, post){//还记得post.js里面获取文章的函数吧? if(err){ req.flash('err',err); return res.redirect('/'); } res.render('article',{ title: req.params.title, post: post, user: req.session.user, success: req.flash('success').toString(), error: req.flash('error').toString() }); }); }); });接下来写文章页面的视图 article.ejs
<%- include header %> <p><h2><a href="/<%= locals.post.user %>/<%= locals.post.time.day %>/<%= locals.post.title %>"><%= locals.post.title %></a></h2></p> <p class="info"> 作者:<a href="/<%= locals.post.user %>"><%= locals.post.user %></a> | 日期:<%= locals.post.time.minute %> </p> <p><%- locals.post.post %></p> <p class="info">阅读:<%= locals.post.pv %> | 评论:<%= locals.post.comments.length %> <%- include footer %>进入主页点击文章标题看看效果吧?
发现问题了吧?样式都没有了,原因先不说,说完解决方法之后你就明白了:
把header.ejs中引入style.css的路径写成这样:
<link rel="stylesheet" href="/stylesheets/style.css">好了,ok了!
现在在文章页面后面加上评论,完整的article.ejs为:
<%- include header %> <p><h2><a href="/<%= locals.post.user %>/<%= locals.post.time.day %>/<%= locals.post.title %>"><%= locals.post.title %></a></h2></p> <p class="info"> 作者:<a href="/<%= locals.post.user %>"><%= locals.post.user %></a> | 日期:<%= locals.post.time.minute %> </p> <p><%- locals.post.post %></p> <p class="info">阅读:<%= locals.post.pv %> | 评论:<%= locals.post.comments.length %> <br /><br /> <% if(locals.post.comments){ %> <% locals.post.comments.forEach(function(comment, index){ %> <p><a href="/<%= comment.website %>"><%= comment.name %></a> <time>回复于 <%= comment.time %></time></p> <p><%- comment.content %></p> <% }) %> <% } %> <form method="post"> <% if(!locals.user){ %> 姓名:<input type="text" name="name" /><br /> 邮箱:<input type="text" name="email" /><br /> 网址:<input type="text" name="website" /><br /> <% } %> 留言:<br /><textarea name="content" rows="5" cols="80"></textarea> <br /><input type="submit" value="留言" /> </form> <%- include footer %>评论视图有了,下面就是处理过程了,在app.get("/:user/:time/:title",function(){})后面添加:
app.post('/:user/:time/:title', function(req,res){ var comment = null, date = new Date(), time = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate() + " " + date.getHours() + ":" + date.getMinutes(); if(req.session.user){ var name=req.session.user.name; comment = {"name":name, "email":name+"@gmail.com", "website":"www."+name+".com", "time":time, "content":req.body.content} } else { comment = {"name":req.body.name, "email":req.body.email, "website":req.body.website, "time":time, "content":req.body.content} } var oneComment = new Comment(req.params.user, req.params.time, req.params.title, comment); oneComment.save(function(err){ if(err){ req.flash('error', err); return res.redirect('/'); } req.flash('success', '评论成功!'); res.redirect('back');//这句话的作用是评论成功后返回到被评论文章 }); });作者页面和文章页面是类似的,点击作者名字,显示该作者的所有文章。
作者页面路由控制:
app.get('/:user', function(req,res){ User.get(req.params.user, function(err, user){ if(!user){ return res.redirect('/'); } Post.getAll(req.params.user, function(err, posts){ if(err){ req.flash('err',err); return res.redirect('/'); } res.render('user',{ title: req.params.user, posts: posts, user: req.session.user, success: req.flash('success').toString(), error: req.flash('error').toString() }); }); }); });作者页面视图user.ejs:
<%- include header %> <% locals.posts.forEach(function(post, index){ %> <p><h2><a href="/<%=post.user %>/<%=post.time.day %>/<%=post.title %>"><%= post.title %></a></h2> <p class="info"> 作者:<a href="/<%= post.user %>"><%= post.user %></a> | 日期:<%= post.time.minute %> </p> <p><%- post.post %></p> <p class="info">阅读:<%= post.pv %> | 评论:<%= post.comments.length %></p> <% }) %> <%- include footer %>到目前为止,博客系统已经完成了。还有个地方可以完善一下。现在没有做权限控制,不管登录还是未登录都可以访问页面。稍稍修改一下,未登录用户不可以进入文章页面和作者页面、不可以评论、不可以发布文章、不可以退出,当用户试图执行以上操作的时候,均跳转到登录页面。
咱们在index.js中写一个函数检验用户是否登录:
function checkLogin(req, res, next){ if(!req.session.user){ req.flash('error','请登录'); return res.redirect('/login'); } next(); }然后在上面提到的几个路由控制前面加上checkLogin,如在app.get("/logout",function(){});之前加上:app.get('/logout',checkLogin);
对于登录操作,应该只对未登录用户开放,所以添加一个函数校验是否未登录:
function checkNotLogin(req,res,next){ if(req.session.user){ req.flash('error','已登录'); return res.redirect('/'); } next(); }然后在login对应的get和post处理前分别添加app.get('/login',checkNotLogin); 和app.post('/login',checkNotLogin);
好了,到现在为止,粗糙的博客系统算是做好了,像csdn的标签功能其实和文章页面差不多,就不写了。
有几个问题做一下小说明,也是我自己在第一次开发的过程中遇到的:
1、路由控制问题。要保证彼此的路由不会相互干扰,比如说,logout不会被作者页面的路由拦截,路由的书写顺序就很重要了。你可以试试把logou路由控制t放在user之后。所以在涉及到正则表达式类型的路由控制的时候,请认真思考路由的书写顺序,当你的路由解析出乎意料的时候,记得调整路由顺序。
2、前面已经说过的样式问题。我第一次开发的时候,参考的是别人给出的解决方案,就是在article.ejs里面在引入一遍style.css,后来总觉得那样不合理,才找出了解决方案。所以引入public下的文件的时候,建议用根目录。
3、我写的这个从一开始到最后,数据结构都没有变过,省了很多。但是真正做开发的时候,不一定会那么顺利。比如我刚开始做的时候,每加一个功能就要修改一次数据结构,然后就会出现先前存进去的数据包含了后面才定义的属性,出现undefined。这时候也不用着急,先清空数据库,基本上就没问题了,还有问题的话,自己看控制台的错误提示,基本上也可以自己解决了。
4、最后,题外话,写程序,思路要尽量清晰一些,开始着手书写代码的时候,要细心,个人觉得写代码可以遵循增量开发的原则,先搭好架子,后期再一步步扩展,一步步测试,这样便于调试。