【Go web开发之revel+mgo】第4章 实现评论功能

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。你成功了吗?


交流QQ:158325682



本文来自:CSDN博客

感谢作者:joveth

查看原文:【Go web开发之revel+mgo】第4章 实现评论功能

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。