分享
  1. 首页
  2. 文章

golang学习之go简单博客应用

caiyezi · · 1602 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

先说说golang的语法吧,个人觉得有以下特点:

  • 简洁,不管是变量、方法声明,还是代码编写,均十分简洁,效率也比较高
  • 非纯粹面向对象,但是go的struct类似c的struct,go的结构体还可以进行struct的包含,被包含的struct的方法被外层struct共享
  • 指针,方法传参时可以直接传指针,相比传值更加快速
  • 接口,go中规定,如果一个对象(struct)实现了interface中的所有方法,那么该struct便实现该接口
  • chan的定义,用来各个线程(有人叫协程,超轻量级)间的通信,基本不用考虑死锁等问题
  • 默认大写开头的结构体、方法等为public公有,小写开头为private私有

go的特性还有很多,菜鸟就不多说了,下面是一个用go开发的博客应用,功能比较简单,直接上菜:

系统环境

go版本:1.5rc1 系统:win7 数据库:mongodb(使用mgo操作) web框架:revel
样式:bootstrap

页面效果

博客主页:

新建博客:

联系:

博客详情:

界面差不多就是这样,很简单吧,下节笔记是博客新增部分,慢慢来。。。

Header页

<div class="container-fluid">
 <div class="row-fluid">
 <div class="span12">
 <div class="page-header">
 <h3>基于Golang实现的博客应用iBlog</h3>
 <h4><small>数据库采用mongodb(mgo)、页面样式使用bootstrap(布局参考csdn)、整体实现采用Revel,Revel地址:<a href="http://revel.github.io/docs/godoc/index.html" target="_blank">http://revel.github.io/docs/godoc/index.html</a></small></h4>
 <h4><small>时间:2015.12.23</small></h4> 
 </div>
 <div class="navbar navbar-inverse" style="margin-top:1px;">
 <div class="navbar-inner">
 <div class="container-fluid">
 <a class="btn btn-navbar" data-target=".navbar-responsive-collapse" data-toggle="collapse"></a> <a class="brand" href="#">iBlog</a>
 <div class="nav-collapse collapse navbar-responsive-collapse">
 <ul class="nav">
 <li class="{{.home}}">
 <a href="/">主页</a>
 </li>
 <li class="{{.blog}}">
 <a href="/blog">新博客</a>
 </li>
 <li class="{{.contact}}">
 <a href="javascript:contact()">联系</a>
 </li>
 </ul>
 </div>
 </div>
 </div>
 </div>
 </div>
 </div>
</div>

Footer页

<script type="text/javascript"> function contact(){ jQuery.dialog({ title: '关于我', content: '姓名:caiya928' + '<br/>' + '地址:陕西-西安' + '<br/>' + '博客:<a href="http://www.cnblogs.com/caiya928" target="_blank">http://www.cnblogs.com/caiya928</a>' }); } </script>

项目结构

首页页面实现

<!DOCTYPE html>
<html>
 <head> {{set . "title" "iBlog博客"}} {{set . "home" "active" }} <title>{{.title}}</title>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="shortcut icon" type="image/png" href="/public/img/favicon.png">
 <link href="/public/bootstrap/css/bootstrap.css" rel="stylesheet">
 <link href="/public/css/header.css" rel="stylesheet">
 <link href="/public/bootstrap/css/bootstrap-responsive.css" rel="stylesheet">
 <link href="/public/bootstrap/css/jquery-confirm.css" rel="stylesheet">
 <script src="/public/js/jquery-1.9.1.min.js" type="text/javascript" charset="utf-8"></script>
 <script src="/public/bootstrap/js/bootstrap.js"></script>
 <script src="/public/bootstrap/js/jquery-confirm.js"></script>
 </head>
 <body> {{template "header.html" .}} <div class="container-fluid" style="margin-top:0px;">
 <div class="row-fluid" style="margin-left:0px;margin-top:0px;">
 <div class="span12" margin-top="200px;"> {{if .blogs}} {{range $blog := .blogs}} <div style="margin-left:0px;" class="span12">
 <ul class="thumbnails">
 <li >
 <div class="caption" >
 <h3><a style="color:#000" href="/bloginfo/{{$blog.Id_}}/{{$blog.ReadCnt}}">{{$blog.GetTitle }}</a></h3>
 <span class="label label-default">作者:{{$blog.Author}}</span>
 <span class="label label-info">日期:{{$blog.CDate.Format "2006年01月02日 15:04"}}</span>
 <span class="label label-success">阅读:{{$blog.ReadCnt}}</span>
 <p>{{$blog.GetContent}}</p>
 </div>
 </li>
 </ul> 
 </div> {{end}} {{end}} </div> {{template "footer.html" .}} </body>
</html>

控制器层配置

# Routes # This file defines all application routes (Higher priority routes first) # ~~~~ module:testrunner GET / App.Index GET /blog App.Blog GET /bloginfo/:id/:rcnt App.BlogInfo POST /save WBlog.Save POST /saveComment Comment.SaveComment # Ignore favicon requests GET /favicon.ico 404 # Map static resources from the /app/public folder to the /public path GET /public/*filepath Static.Serve("public") # Catch all * /:controller/:action :controller.:action

页面跳转控制层App.go

package controllers import ( "github.com/revel/revel"
 "myapp/app/modules" ) type App struct { *revel.Controller } func (c App) Index() revel.Result { dao, err := modules.Conn() if err != nil { c.Response.Status = 500
 return c.RenderError(err) } defer dao.Close() blogs := dao.FindBlogs() return c.Render(blogs) } func (c App) Blog() revel.Result { return c.Render() } func (c App) BlogInfo(id string, rcnt int) revel.Result { dao, err := modules.Conn() if err != nil { c.Response.Status = 500
 return c.RenderError(err) } defer dao.Close() blog := dao.GetBlogFromId(id) if blog.ReadCnt == rcnt { blog.ReadCnt = rcnt + 1 dao.UpdateBlogById(id, blog) } comments := dao.GetCommentsFromBlogId(blog.Id_) blog.CommentCnt = len(comments) dao.UpdateBlogById(id, blog) return c.Render(blog, rcnt, comments) }

数据库Dao层

package modules import ( "gopkg.in/mgo.v2" ) const ( CommentCollection = "comment" DbName = "blog" UserCollection = "user" BlogCollection = "blog" MessageCollection = "message" ) type Dao struct { session *mgo.Session } func Conn() (*Dao, error) { session, err := mgo.Dial("localhost") if err != nil { return nil, err } return &Dao{session}, nil } func (dao *Dao) Close() { dao.session.Close() }

新增博客页面

<!DOCTYPE html>
<html>
 <head> {{set . "title" "新博客"}} {{set . "blog" "active"}} <title>{{.title}}</title>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="shortcut icon" type="image/png" href="/public/img/favicon.png">
 <link href="/public/bootstrap/css/bootstrap.css" rel="stylesheet">
 <link href="/public/css/header.css" rel="stylesheet">
 <link href="/public/bootstrap/css/bootstrap-responsive.css" rel="stylesheet">
 <link href="/public/bootstrap/css/jquery-confirm.css" rel="stylesheet">
 <script src="/public/js/jquery-1.9.1.min.js" type="text/javascript" charset="utf-8"></script>
 <script src="/public/bootstrap/js/bootstrap.js"></script>
 <script src="/public/bootstrap/js/jquery-confirm.js"></script>
 </head>
 <body> {{template "header.html" .}} <div class="container-fluid" style="margin-top:0px;">
 <div class="row-fluid" style="margin-left:5px;margin-top:0px;">
 <div class="row-fluid" style="margin-left:5px;margin:0px auto;border:0px;">
 <div class="span12" style="border:1px solid #ccc;border-radius: 5px;padding:10px;">
 <form action="/save" method="post">
 <div class="form-group">
 <h4>标题</h4> {{with $field := field "blog.Title" .}} <input type="text" id="{{$field.Id}}" style="width:40%" class="form-control" name="{{$field.Name}}" placeholder="请输入您的博客标题" value="{{$field.Flash}}" >
 <span class="help-inline erro">{{$field.Error}}</span> {{end}} </div>
 <div class="form-group">
 <h4>内容</h4> {{with $field := field "blog.Content" .}} <textarea class="form-control" id="{{$field.Id}}" name="{{$field.Name}}" rows="6" style="width:60%" placeholder="请输入您的博客内容">{{$field.Flash}}</textarea>
 <span class="help-inline erro">{{$field.Error}}</span> {{end}} </div>
 <div class="form-group" style="margin-left:57%">
 <button type="submit" class="btn btn-success">提交</button>
 </div>
 </form>
 </div>
 </div>
 </div>
 </div>
 </body>
</html> {{template "footer.html" .}}

博客模型层

package modules import ( "github.com/revel/revel"
 "gopkg.in/mgo.v2/bson"
 "time" ) type Blog struct { Id_ string `bson:"_id"` CDate time.Time Title string Content string ReadCnt int Year int Author string CommentCnt int } //新建博客
func (dao *Dao) CreateBlog(blog *Blog) error { BlogCollection := dao.session.DB(DbName).C(BlogCollection) blog.CDate = time.Now() blog.Year = blog.CDate.Year() blog.ReadCnt = 0 blog.CDate = time.Now() blog.Id_ = bson.NewObjectId().Hex() blog.Author = "匿名" blog.Year = blog.CDate.Year() err := BlogCollection.Insert(blog) //先根据Id查找,然后更新或插入
 if err != nil { revel.WARN.Printf("Unable to save blog:%v error % v", blog, err) } return err } //获取Title
func (blog *Blog) GetTitle() string { if len(blog.Title) > 100 { return blog.Title[:100] } return blog.Title } //获取Content
func (blog *Blog) GetContent() string { if len(blog.Content) > 500 { return blog.Content[:500] } return blog.Content } //查询所有博客
func (dao *Dao) FindBlogs() []Blog { BlogCollection := dao.session.DB(DbName).C(BlogCollection) blogs := []Blog{} query := BlogCollection.Find(bson.M{}).Sort("-cdate").Limit(50) //结果根据cdate倒序
 query.All(&blogs) return blogs } //前台数据提交校验
func (blog *Blog) Validate(v *revel.Validation) { v.Check(blog.Title, revel.Required{}, revel.MinSize{1}, revel.MaxSize{200}) v.Check(blog.Content, revel.Required{}, revel.MinSize{1}) } //根据id查询Blog对象
func (dao *Dao) GetBlogFromId(id string) *Blog { BlogCollection := dao.session.DB(DbName).C(BlogCollection) blog := new(Blog) query := BlogCollection.Find(bson.M{"_id": 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": id}, blog) if err != nil { revel.WARN.Printf("Unable to update blog: %v error %v", blog, err) } }

博客Action层

package controllers import ( "fmt"
 "github.com/revel/revel"
 "myapp/app/modules"
 "strings" ) type WBlog struct { App //结构体包含
} func (c WBlog) Save(blog *modules.Blog) revel.Result { blog.Title = strings.TrimSpace(blog.Title) blog.Content = strings.TrimSpace(blog.Content) blog.Validate(c.Validation) if c.Validation.HasErrors() { c.Validation.Keep() c.FlashParams() fmt.Println(c.Validation) return c.Redirect(App.Blog) } dao, err := modules.Conn() if err != nil { c.Response.Status = 500
 return c.RenderError(err) } defer dao.Close() err = dao.CreateBlog(blog) if err != nil { c.Response.Status = 500
 return c.RenderError(err) } return c.Redirect(App.Index) }

博客详情页

<!DOCTYPE html>
<html>
 <head> {{set . "title" "博客详情"}} {{set . "home" "active" }} <title>{{.title}}</title>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="shortcut icon" type="image/png" href="/public/img/favicon.png">
 <link href="/public/bootstrap/css/bootstrap.css" rel="stylesheet">
 <link href="/public/css/header.css" rel="stylesheet">
 <link href="/public/bootstrap/css/bootstrap-responsive.css" rel="stylesheet">
 <link href="/public/bootstrap/css/jquery-confirm.css" rel="stylesheet">
 <script src="/public/js/jquery-1.9.1.min.js" type="text/javascript" charset="utf-8"></script>
 <script src="/public/bootstrap/js/bootstrap.js"></script>
 <script src="/public/bootstrap/js/jquery-confirm.js"></script>
 </head>
 <body> {{template "header.html" .}} <div style="margin-left:5px;" class="span12"> {{if .blog}} <div class="content" style="border:1px solid #ccc;border-radius: 5px;padding:10px;">
 <ul class="thumbnails">
 <li>
 <div class="caption" >
 <h3>{{.blog.Title}}</h3>
 <span class="label label-default">作者:{{.blog.Author}}</span>
 <span class="label label-info">日期:{{.blog.CDate.Format "2006年01月02日 15:04"}}</span>
 <span class="label label-success">阅读:{{.blog.ReadCnt}}</span>
 </div>
 </li>
 </ul> 
 <p>{{.blog.Content}}</p>
 </div>
 <div class="comment" style="margin-top:20px;"> {{if .comments}} <div class="comments" style="border:1px solid #ccc;border-radius: 5px;padding:10px;">
 <h4>回复</h4>
 <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" style="margin-top:15px;">
 <a href="#"><strong>{{$comment.Email}}</strong></a>
 <span style="margin-left:10px;" class="label label-default">日期:{{$comment.CDate.Format "2006年01月02日 15:04" }}</span>
 </div>
 <div class="user-comment" style="margin-top:15px;">
 <p>{{$comment.Content}}</p>
 </div>
 </dd> {{end}} </dl>
 </div> {{end}} </div>
 <div class="comments" style="border:1px solid #ccc;border-radius: 5px;padding:10px;margin-top:20px;">
 <div class="comment-form">
 <form action="/saveComment" method="post">
 <input type="hidden" name="id" value="{{.blog.Id_}}">
 <input type="hidden" name="rcnt" value="{{.rcnt}}">
 <div class="form-group">
 <h4>邮箱</h4> {{with $field := field "comment.Email" .}} <input style="width:50%" type="email" class="form-control" id="{{$field.Id}}" name="{{$field.Name}}" placeholder="请输入您的联系方式" 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">
 <h4>评论</h4> {{with $field := field "comment.Content" .}} <textarea style="width:70%" class="form-control" id="{{$field.Id}}" name="{{$field.Name}}" rows="6" placeholder="请输入您的回复" required >{{if $field.Flash}}{{$field.Flash}}{{else}}{{$field.Value}}{{end}}</textarea> {{end}} </div>
 <div class="form-group">
 <button type="submit" style="margin-left:66.5%" class="btn btn-success">提交</button>
 </div>
 </form>
 </div>
 </div> {{end}} {{template "footer.html" .}} </body>
</html>

评论功能Dao层

package modules import ( "github.com/revel/revel"
 "gopkg.in/mgo.v2/bson"
 "time" ) type Comment struct { Id_ string `bson:"_id"` BlogId string Email string CDate time.Time Content string } func (comment *Comment) Validate(v *revel.Validation) { v.Check(comment.Email, revel.Required{}, revel.MaxSize{50}) v.Check(comment.Content, revel.Required{}, revel.MinSize{1}, revel.MaxSize{200}) } func (dao *Dao) InsertComment(comment *Comment) error { commentCollection := dao.session.DB(DbName).C(CommentCollection) comment.CDate = time.Now() err := commentCollection.Insert(comment) if err != nil { revel.WARN.Printf("Unable to save Comment: %v error %v", comment, err) } return err } func (dao *Dao) GetCommentsFromBlogId(id string) []Comment { commentCollection := dao.session.DB(DbName).C(CommentCollection) comments := []Comment{} query := commentCollection.Find(bson.M{"blogid": id}).Sort("CDate") query.All(&comments) return comments }

评论功能Action层

package controllers import ( "github.com/revel/revel"
 "gopkg.in/mgo.v2/bson"
 "myapp/app/modules"
 "strings" ) type Comment struct { App } //保存评论
func (c Comment) SaveComment(id string, rcnt int, comment *modules.Comment) revel.Result { if len(id) == 0 { return c.Redirect("/") } dao, err := modules.Conn() if err != nil { //如果报错
 c.Response.Status = 500
 return c.Redirect("/") } defer dao.Close() blog := dao.GetBlogFromId(id) if blog == nil { return c.Redirect("/") } comment.Id_ = bson.NewObjectId().Hex() 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("/bloginfo/%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("/") }

init.go初始化加载文件

package app import "github.com/revel/revel" func init() { revel.TemplateFuncs["pls"] = func(a, b int) int { return a + b } // Filters is the default set of global filters.
 revel.Filters = []revel.Filter{ revel.PanicFilter, // Recover from panics and display an error page instead.
 revel.RouterFilter, // Use the routing table to select the right Action
 revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
 revel.ParamsFilter, // Parse parameters into Controller.Params.
 revel.SessionFilter, // Restore and write the session cookie.
 revel.FlashFilter, // Restore and write the flash cookie.
 revel.ValidationFilter, // Restore kept validation errors and save new ones from cookie.
 revel.I18nFilter, // Resolve the requested language
 HeaderFilter, // Add some security based headers
 revel.InterceptorFilter, // Run interceptors around the action.
 revel.CompressFilter, // Compress the result.
 revel.ActionInvoker, // Invoke the action.
 } // register startup functions with OnAppStart // ( order dependent ) // revel.OnAppStart(InitDB) // revel.OnAppStart(FillCache)
} // TODO turn this into revel.HeaderFilter // should probably also have a filter for CSRF // not sure if it can go in the same filter or not
var HeaderFilter = func(c *revel.Controller, fc []revel.Filter) { // Add some common security headers
 c.Response.Out.Header().Add("X-Frame-Options", "SAMEORIGIN") c.Response.Out.Header().Add("X-XSS-Protection", "1; mode=block") c.Response.Out.Header().Add("X-Content-Type-Options", "nosniff") fc[0](c, fc[1:]) // Execute the next filter stage.
}

footer.css样式

.mbox dl dd{ margin-top:4px;
}

header.css

.page-header{ margin-top:2px; margin-bottom:15px; border-bottom: 1px solid #eeeeee;
} body{ line-height:30px; font-size: 16px; padding:5px; margin:5px; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; */ } li { line-height: 30px;
} .navbar .nav > li > a { float: none; padding: 15px 30px; color: #777; text-decoration: none; text-shadow: 0 0px 0 #ffffff;
} .nav{ margin:0px;
} .span12{ padding:0 5px;
} .brand{ padding:0; margin-top:5px; font-size:10px;
} .container-fluid{ padding:1px;
} .form-search{ margin-top:11px;
}

好了,完整的代码就是这样,初学就当练习用的,发现bug还望直接指出。。。


有疑问加站长微信联系(非本文作者)

本文来自:开源中国博客

感谢作者:caiyezi

查看原文:golang学习之go简单博客应用

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
1602 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏