【Go web开发之revel+mgo】第4章 实现评论功能
sorry,各位在开始这一章之前请各位先到,第5章把整个项目的css copy出来,这一章忘了加,本来想在后面加的,但是发现页面的内容太多了
1.设计评论页面
{{set . "title" "Bloginfor - GBlog" }} {{set . "home" "active" }} {{template "header.html" .}} <div class="content"> <div class="infor-content"> <div class="infor-header"> <h3>Title</h3> <div class="subject-infor"> <span class="label label-success">Author</span> <span>jov123@163.com</span> <span class="label label-default">Date</span> 2014-04-25 15:04 <span class="label label-info">Read</span> 1 </div> </div> <div class="infor-body"> this is the subject </div> </div> <div class="comments"> <span>回复</span> <hr> <dl class="the-comments"> <dd > <span class="label label-default pull-right">#1</span> <div class="user-info"> <a href="#"><strong>omind@163.com</strong></a> • 2014-04-25 16:04 </div> <div class="user-comment"> <p>nice!</p> </div> </dd> </dl> </div> <div class="comments"> <div class="comment-form"> <form action="/docomment" method="post"> <input type="hidden" name="id" value="{{.blog.Id.Hex}}"> <input type="hidden" name="rcnt" value="{{.rcnt}}"> <div class="form-group"> <label >Email</label> {{with $field := field "comment.Email" .}} <input type="email" class="form-control" id="{{$field.Id}}" name="{{$field.Name}}" placeholder="Your email" required value="{{if $field.Flash}}{{$field.Flash}}{{else}}{{$field.Value}}{{end}}"> <span class="help-inline erro">{{$field.Error}}</span> {{end}} </div> <div class="form-group"> <label >Comment</label> {{with $field := field "comment.Content" .}} <textarea class="form-control" id="{{$field.Id}}" name="{{$field.Name}}" rows="6" placeholder="Enter the comment" required >{{if $field.Flash}}{{$field.Flash}}{{else}}{{$field.Value}}{{end}}</textarea> {{end}} </div> <div class="form-group"> <button type="submit" class="btn btn-success">Submit</button> </div> </form> </div> </div> </div> {{template "footer.html" .}}
在app/controllers/app.go里面添加我们的处理方法:
func (c App) BlogInfor() revel.Result { return c.Render() }
在conf/routes里面添加路径:
GET /bloginfor App.BlogInfor
ok在地址里面用http://localhost:9000/bloginfor访问看看,效果:
2.实现评论功能
/bloginfor/{{$blog.Id.Hex}}/{{$blog.ReadCnt}}
恩,对,我们传递了blog的id和阅读次数,为什么要传阅读次数呢,因为从这个链接点进去的时候我们要把阅读次数加1,但是如果我们不传递,那么到详细页面的时候应该是直接将db里面的数据增加,这样就有问题了,我在详细页面一直按F5刷新,发现阅读次数飞快的增加,这让我很无奈,怎么版办呢,把阅读次数也传过来把,至少把原来的一步增加了2步,稍微的缓解一下把,但是仍然不知最好的方法啊,最好的方法是,我们获取,请求用户的 IP,做判断,只能为这个Ip增加一次,这都是后话了。
GET /bloginfor/:id/:rcnt App.BlogInfor
把app/controllers/app.go里面的BlogInfor方法也加两个参数:
func (c App) BlogInfor(id string,rcnt int) revel.Result { return c.Render() }
好,我们这次从首页点击我们blog的title进去看看,是不是能正常进入详细页面。
func (c App) BlogInfor(id string,rcnt int) revel.Result { dao, err := models.NewDao() if err != nil { c.Response.Status = 500 return c.RenderError(err) } defer dao.Close() blog := dao.FindBlogById(id) if(blog.ReadCnt==rcnt){ blog.ReadCnt = rcnt+1 dao.UpdateBlogById(id,blog) } return c.Render(blog,rcnt) }
我们去找到这个blog,并且把阅读次数做一下更新,看一下里面的判断,我们是把阅读次数和db中的相比较,只有相等的情况才去更新,这样确实增加了2步。不过,如果你有时间,你也可以采用另外一种方法,就是把阅读次数加密(可逆的加密),解密之后再与db中的比较,这样的话,用户想要修改加密后的东西并不是一件容易的事件。
func (dao *Dao) FindBlogById(id string) *Blog{ blogCollection := dao.session.DB(DbName).C(BlogCollection) blog := new(Blog) query := blogCollection.Find(bson.M{"id": bson.ObjectIdHex(id)}) query.One(blog) return blog } func (dao *Dao) UpdateBlogById(id string,blog *Blog) { blogCollection := dao.session.DB(DbName).C(BlogCollection) err := blogCollection.Update(bson.M{"id": bson.ObjectIdHex(id)}, blog) if err!=nil{ revel.WARN.Printf("Unable to update blog: %v error %v", blog, err) } }
一个是查找,一个是更新,没什么好说的。
{{set . "title" "Bloginfor - GBlog" }} {{set . "home" "active" }} {{template "header.html" .}} <div class="content"> {{if .blog}} <div class="infor-content"> <div class="infor-header"> <h3>{{.blog.Title}}</h3> <div class="subject-infor"> <span class="label label-success">Author</span> <span>{{.blog.Email}}</span> <span class="label label-default">Date</span> {{.blog.CDate.Format "2006-01-02 15:04"}} <span class="label label-info">Read</span> {{.blog.ReadCnt}} </div> </div> <div class="infor-body"> {{.blog.Subject}} </div> </div> <div class="comments"> <span>回复</span> <hr> <dl class="the-comments"> <dd > <span class="label label-default pull-right">#1</span> <div class="user-info"> <a href="#"><strong>omind@163.com</strong></a> • 2014-04-25 16:04 </div> <div class="user-comment"> <p>nice!</p> </div> </dd> </dl> </div> <div class="comments"> <div class="comment-form"> <form action="/docomment" method="post"> <input type="hidden" name="id" value="{{.blog.Id.Hex}}"> <input type="hidden" name="rcnt" value="{{.rcnt}}"> <div class="form-group"> <label >Email</label> {{with $field := field "comment.Email" .}} <input type="email" class="form-control" id="{{$field.Id}}" name="{{$field.Name}}" placeholder="Your email" required value="{{if $field.Flash}}{{$field.Flash}}{{else}}{{$field.Value}}{{end}}"> <span class="help-inline erro">{{$field.Error}}</span> {{end}} </div> <div class="form-group"> <label >Comment</label> {{with $field := field "comment.Content" .}} <textarea class="form-control" id="{{$field.Id}}" name="{{$field.Name}}" rows="6" placeholder="Enter the comment" required >{{if $field.Flash}}{{$field.Flash}}{{else}}{{$field.Value}}{{end}}</textarea> {{end}} </div> <div class="form-group"> <button type="submit" class="btn btn-success">Submit</button> </div> </form> </div> </div> {{end}} </div> {{template "footer.html" .}}
显示了 blog信息。好,点进去看看效果:
package models import ( "github.com/revel/revel" "labix.org/v2/mgo/bson" "time" ) type Comment struct{ BlogId bson.ObjectId Email string CDate time.Time Content string } func (comment *Comment) Validate(v *revel.Validation) { v.Check(comment.Email, revel.Required{}, revel.MaxSize{50}, ) v.Email(comment.Email) v.Check(comment.Content, revel.Required{}, revel.MinSize{1}, revel.MaxSize{1000}, ) } func (dao *Dao) InsertComment(comment *Comment) error { commCollection := dao.session.DB(DbName).C(CommentCollection) //set the time comment.CDate = time.Now(); err := commCollection.Insert(comment) if err != nil { revel.WARN.Printf("Unable to save Comment: %v error %v", comment, err) } return err } func (dao *Dao) FindCommentsByBlogId(id bson.ObjectId) []Comment{ commCollection := dao.session.DB(DbName).C(CommentCollection) comms := []Comment{} query := commCollection.Find(bson.M{"blogid":id}).Sort("CDate") query.All(&comms) return comms }
跟我们的blog.go很相似,不用多解释。有了dao,我们来做逻辑,还是先做提交评论的功能,看下 我们的BlogInfo.html页面。最后的form表单,里面的东西跟我们上一章讲的差不多。
package controllers import ( "github.com/revel/revel" "GBlog/app/models" "strings" ) type WComment struct { App } func (c WComment) Docomment(id string,rcnt int,comment *models.Comment) revel.Result { if len(id)==0{ return c.Redirect(App.Index) } dao, err := models.NewDao() if err != nil { c.Response.Status = 500 return c.Redirect(App.Index) } defer dao.Close() blog := dao.FindBlogById(id) if blog==nil { return c.Redirect(App.Index) } comment.BlogId = blog.Id comment.Content = strings.TrimSpace(comment.Content) comment.Email = strings.TrimSpace(comment.Email) comment.Validate(c.Validation) if c.Validation.HasErrors() { c.Validation.Keep() c.FlashParams() c.Flash.Error("Errs:The email and the content should not be null,or the maxsize of email is 50.") return c.Redirect("/bloginfor/%s/%d",id,rcnt) } err = dao.InsertComment(comment) if err!=nil { c.Response.Status = 500 return c.RenderError(err) } blog.CommentCnt++ dao.UpdateBlogById(id,blog) return c.Redirect("/bloginfor/%s/%d",id,rcnt) }
看一下里面的逻辑,我们先去查找一下,有没有这个blog对象,没有的话,就直接 返回到Index页面,然后是comment的校验,最后我们的blog的评论次数加1。
POST /docomment WComment.Docomment
你可以试试能不能提交成功了。虽然还看不到什么结果。
comments := dao.FindCommentsByBlogId(blog.Id); if len(comments)==0&&blog.CommentCnt!=0{ blog.CommentCnt=0; dao.UpdateBlogById(id,blog) }else if len(comments)!=blog.CommentCnt{ blog.CommentCnt=len(comments); dao.UpdateBlogById(id,blog) }
最后的return修改为:
return c.Render(blog,rcnt,comments)
打开views/App/BlogInfor.html,将其中的块:
<div class="comments"> <span>回复</span> <hr> <dl class="the-comments"> <dd > <span class="label label-default pull-right">#1</span> <div class="user-info"> <a href="#"><strong>omind@163.com</strong></a> • 2014-04-25 16:04 </div> <div class="user-comment"> <p>nice!</p> </div> </dd> </dl> </div>
{{if .comments}} <div class="comments"> <span>回复</span> <hr> <dl class="the-comments"> {{range $index,$comment := .comments}} <dd > <span class="label label-default pull-right">#{{pls $index 1}}</span> <div class="user-info"> <a href="#"><strong>{{$comment.Email}}</strong></a> • {{$comment.CDate.Format "2006-01-02 15:04" }} </div> <div class="user-comment"> <p>{{$comment.Content}}</p> </div> </dd> {{end}} </dl> </div> {{end}}
哎呦,不错哦,基本上做完了,为什么说基本上呢,因为你现在刷新页面的话应该会有错,看到了吗?上面的代码:
{{pls $index 1}}这个是用来显示楼层的的东西,这个什么呢,是我们自定义的模板,这里不得不感谢revel中文社区的kevin,如果我们直接用$index它是从0开始的,这。。。
revel.TemplateFuncs["pls"] = func(a, b int) int { return a + b }
就是定义了一个简单的模板方法。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。