sorry,各位在开始这一章之前请各位先到,第5章把整个项目的css copy出来,这一章忘了加,本来想在后面加的,但是发现页面的内容太多了
1.设计评论页面
上一章我们做了简单的写blog和显示功能,这里不得不说一下,首先,我们的blog里面不能加图片链接这样的东西,不支持markdown语法。博主比较懒,尝试找了几个插件发现不满意之后就不想尝试了(其实能找到github编写wiki的编辑器才是我想要的,有谁知道的告诉我哦),大家可以自己尝试去找一些自己喜欢的编辑器(虽然revel中文社区的那个已经很不错了,但是弹出框风格很不喜欢,golang社区的编辑器也很强,但也不是我喜欢的风格,你妹啊,这么挑剔。。。。),总之,大家可以参考一下,喜欢就用。
在views/App下面新建BlogInfor.html 内容:
{{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.实现评论功能
首先看一下我们的Index.html里面的title的链接内容:
/bloginfor/{{$blog.Id.Hex}}/{{$blog.ReadCnt}}
恩,对,我们传递了blog的id和阅读次数,为什么要传阅读次数呢,因为从这个链接点进去的时候我们要把阅读次数加1,但是如果我们不传递,那么到详细页面的时候应该是直接将db里面的数据增加,这样就有问题了,我在详细页面一直按F5刷新,发现阅读次数飞快的增加,这让我很无奈,怎么版办呢,把阅读次数也传过来把,至少把原来的一步增加了2步,稍微的缓解一下把,但是仍然不知最好的方法啊,最好的方法是,我们获取,请求用户的 IP,做判断,只能为这个Ip增加一次,这都是后话了。
好了我们修改一下路径的配置conf/routes:
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进去看看,是不是能正常进入详细页面。
我这边是ok的,我们往下进行,首先app/controllers/app.go的BlogInfor方法,修改如下:
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中的比较,这样的话,用户想要修改加密后的东西并不是一件容易的事件。
那么我们的model也要有对应的方法,打开 app/models/blog.go,添加方法:
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)
}
}
一个是查找,一个是更新,没什么好说的。
打开views/App/BlogInfor.html修改成:
{{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信息。好,点进去看看效果:
ok,我们来做评论。
在app/models下建立comment.go 内容:
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表单,里面的东西跟我们上一章讲的差不多。
在app/controllers下面新建wcomment.go,为什么以w开头,write嘛,内容:
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。
最后的c.Redirect("/bloginfor/%s/%d",id,rcnt)是让它再次回到infor页面的。
好,添加我们的路径,conf/routes:
POST /docomment WComment.Docomment
你可以试试能不能提交成功了。虽然还看不到什么结果。
下面来显示我们的评论,在app/controllers/app.go的BlogInfor方法里,return之前加上下面的代码:
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开始的,这。。。
好,打开我们的app/init.go,话说里面还有很多我也不知到的东西,就不给大家讲了,func init() 里面添加:
revel.TemplateFuncs["pls"] = func(a, b int) int { return a + b }
就是定义了一个简单的模板方法。
好了吗。各位,赶快试试期待已久的评论功能把。
nice。你成功了吗?