先说说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.</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 # 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 =
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 =
return c.RenderError(err)
}
defer dao.Close()
blog := dao.GetBlogFromId(id)
if blog.ReadCnt == rcnt {
blog.ReadCnt = rcnt +
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="" 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 =
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) > {
return blog.Title[:]
}
return blog.Title
} //获取Content
func (blog *Blog) GetContent() string {
if len(blog.Content) > {
return blog.Content[:]
}
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() //结果根据cdate倒序
query.All(&blogs)
return blogs
} //前台数据提交校验
func (blog *Blog) Validate(v *revel.Validation) {
v.Check(blog.Title, revel.Required{}, revel.MinSize{}, revel.MaxSize{})
v.Check(blog.Content, revel.Required{}, revel.MinSize{})
} //根据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 =
return c.RenderError(err)
}
defer dao.Close()
err = dao.CreateBlog(blog)
if err != nil {
c.Response.Status =
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 }}</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="" 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{})
v.Check(comment.Content, revel.Required{}, revel.MinSize{}, revel.MaxSize{})
} 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) == {
return c.Redirect("/")
}
dao, err := modules.Conn()
if err != nil { //如果报错
c.Response.Status =
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 =
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[](c, fc[:]) // 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:;
margin-top:5px;
font-size:10px;
} .container-fluid{
padding:1px;
} .form-search{
margin-top:11px;
}

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

golang学习之go简单博客应用的更多相关文章

  1. 多IDC数据分布--MySQL多机房部署 - 学习笔记 - 51CTO技术博客

    多IDC数据分布--MySQL多机房部署 - 学习笔记 - 51CTO技术博客 多IDC数据分布--MySQL多机房部署

  2. [基于NetCore的简单博客系统]-登录

    0-项目背景 一个基于.NET CORE RAZOR PAGES的简单博客系统 技术栈全部采用微软官方实现方式,目的是熟悉新技术 项目地址:https://github.com/ganqiyin/BL ...

  3. yii2实战教程之新手入门指南-简单博客管理系统

    作者:白狼 出处:http://www.manks.top/document/easy_blog_manage_system.html 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文 ...

  4. Do Now 一个让你静心学习的APP——团队博客

    Do Now 一个让你静心学习的APP 来自油条只要半根团队的智慧凝聚的产物! 团队博客总目录: 团队作业第一周 团队作业第二周 Do Now -- 团队冲刺博客一 Do-Now-团队Scrum 冲刺 ...

  5. [python][django学习篇][7]设计博客视图(1)

    1上网的流程: 打开浏览器,输入网址(http://zmrenwu.com/) 浏览器根据输入网址,完成以下几件事:1识别服务器地址,2将用户的浏览意图打包成一个http请求,发送给服务器,等待服务器 ...

  6. python关于Django搭建简单博客项目(详解一)

    上一篇我们说了如何搭建简易博客网站,下面我们来进行详细解答.本文没有特定顺序,请结合上一篇和源代码参照学习. 相关源代码和解析请参看:https://github.com/Cheng0829/mysi ...

  7. Django学习(六)---博客文章页面的超链接设置

    Django中的超链接 超链接的目标地址 href后面是目标地址 template中可以用 {% url  'app_name : url_name'   param %} app_name:应用命名 ...

  8. 学习c++的优秀博客(转)

    http://zhedahht.blog.163.com/  本博客讨论程序员面试题,并主要集中在C/C++.数据结构算法和算法上.http://saturnman.blog.163.com/ sat ...

  9. Node.js 博客实例(一)简单博客

    原教程 https://github.com/nswbmw/N-blog/wiki/_pages的第一章.因为版本号等的原因,在原教程基础上稍加修改就可以实现. 环境: win7旗舰版64位 Node ...

随机推荐

  1. DELL PowerEdge R410系统日志满报错

    DELL PowerEdge R410系统日志满报错 重启服务器时在自检过程中看到CTRL+E时快速按下CTRL+E进入到远程管理ip地址配置界面

  2. 6.iptables常用规则

    开启ip段192.168.1.0/24端的80口 开启ip段211.123.16.123/24端ip段的80口 # iptables -I INPUT -p tcp --dport 80 -j DRO ...

  3. CF1059C Sequence Transformation 题解

    这几天不知道写点什么,状态也不太好,搬个题上来吧 题意:给定一个数n,设一个从1到n的序列,每次删掉一个序列中的数,求按字典序最大化的GCD序列 做法:按2的倍数找,但是如果除2能得到3的这种情况要特 ...

  4. 利用Python工具进行打包功能

    基于Python脚本 iOS 工程的自动打包 导入的库 import os import requests import webbrowser import subprocess import shu ...

  5. Python的__getattribute__二三事

    本来以为自己对__getattribute__已经比较了解了,结果用到的时候,才发现有一些知识点之前一直没有真正弄明白,记录如下(针对python3,python2差异较大): object类有__g ...

  6. 提交app时候遇到IDFA警告

    1.最近提交app时候遇到如下问题,解决方案: Everything has come to its usual state now. Simply upload your binary as you ...

  7. excel2010冻结行列

    https://jingyan.baidu.com/article/a24b33cd56f6bd19ff002b7c.html

  8. Vue项目中用的Jquery.js和easing.js做的抛物线

    如果项目中还用到自有的$ <script> jQuery.noConflict();</script> //星星掉落movePathNew(args) { let self = ...

  9. simulate UE activity

    can: 1,connect, disconnect 2,configure serial,nic,com,model,version,IMEI,IMSI,IP 3,various AT comman ...

  10. js从后台取值并绑定到元素上

    用ajax从后台取值不是什么有技术含量的活计,把后台取来的值绑定到Vue对象上也不算难,但每一次向后台拿数据的时候都得写上这么一段代码就十分痛苦了. 于是我写了这么一小段js代码,能够自己根据url去 ...