zoukankan      html  css  js  c++  java
  • golang学习之go简单博客应用

    先说说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="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="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="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="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还望直接指出。。。

  • 相关阅读:
    局域网搭建https局域网
    在内部局域网内搭建HTTPs
    在局域网内实现https安全访问
    http网站转换成https网站
    iis6 和iis7s上整个网站重定向
    我们在部署 HTTPS 网站时,该如何选择SSL证书?
    HTML:几个常见的列表标签
    HTML:基本的标签
    iOS: 字体样式
    iOS: 首次使用App时,显示半透明新手指引
  • 原文地址:https://www.cnblogs.com/vipzhou/p/5071458.html
Copyright © 2011-2022 走看看