Go:Beego写一个博客
目录:
Beego使用
bee工具
安装beego的bee工具
$ go get github.com/astaxie/beego
$ go get github.com/beego/bee
使用bee生成beego项目
$ bee new everyday
______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v1.10.0
2018/11/20 18:26:20 INFO ▶ 0001 Creating application...
create /root/go_code/src/everyday/
create /root/go_code/src/everyday/conf/
create /root/go_code/src/everyday/controllers/
create /root/go_code/src/everyday/models/
create /root/go_code/src/everyday/routers/
create /root/go_code/src/everyday/tests/
create /root/go_code/src/everyday/static/
create /root/go_code/src/everyday/static/js/
create /root/go_code/src/everyday/static/css/
create /root/go_code/src/everyday/static/img/
create /root/go_code/src/everyday/views/
create /root/go_code/src/everyday/conf/app.conf
create /root/go_code/src/everyday/controllers/default.go
create /root/go_code/src/everyday/views/index.tpl
create /root/go_code/src/everyday/routers/router.go
create /root/go_code/src/everyday/tests/default_test.go
create /root/go_code/src/everyday/main.go
2018/11/20 18:26:20 SUCCESS ▶ 0002 New application successfully created!
目录结构
看一下目录结构
$ tree src/everyday/
src/beeblog/
├── conf //配置文件
│ └── app.conf
├── controllers //控制器
│ └── default.go
├── main.go
├── models //数据库相关
├── routers
│ └── router.go
├── static //静态文件
│ ├── css
│ ├── img
│ └── js
│ └── reload.min.js
├── tests
│ └── default_test.go
└── views //模板文件目录
└── index.tpl
启动beego
$ bee run
______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v1.10.0
2018/11/20 18:33:06 INFO ▶ 0001 Using 'beeblog' as 'appname'
2018/11/20 18:33:06 INFO ▶ 0002 Initializing watcher...
2018/11/20 18:33:08 SUCCESS ▶ 0003 Built Successfully!
2018/11/20 18:33:08 INFO ▶ 0004 Restarting 'beeblog'...
2018/11/20 18:33:08 SUCCESS ▶ 0005 './beeblog' is running...
2018/11/20 18:33:08.083 [I] [asm_amd64.s:2361] http server Running on http://:8080
模板使用
示例
可以先参考一下生成的文件
views/index.tpl中有以下内容,和django的模板类似
<footer>
<div class="author">
Official website:
<a href="http://{{.Website}}">{{.Website}}</a> /
Contact me:
<a class="email" href="mailto:{{.Email}}">{{.Email}}</a>
</div>
</footer>
字段在controllers/default.go中定义
package controllers
import (
"github.com/astaxie/beego"
)
type MainController struct {
beego.Controller
}
func (c *MainController) Get() {
c.Data["Website"] = "beego.me"
c.Data["Email"] = "astaxie@gmail.com"
c.TplName = "index.tpl"
}
if判断
{{if true}}
{{else}}
{{end}}
struct
type u struct {
Name string
Age int
Sex string
}
user := &u {
Name: "Why",
Age: 24,
Sex: "Male",
}
nums := []int{1, 2, 3, 4, 5}
定义静态文件目录
beego.SetStaticPath("/static","public")
- 第一个参数是url路径
- 第二个参数是静态文件的本地目录
过滤和中间件
var FilterUser = func(w http.ResponseWriter, r *http.Request) { if r.URL.User == nil || r.URL.User.Username() != "admin" { http.Error(w, "", http.StatusUnauthorized) } }
beego.Filter(FilterUser)
编写一个博客——beeblog
beeblog的处理流程是
- 直接使用main.go注册路由router或者引入文件方式注册
- 然后router到不同的Controller
- Controller中创建路由对应名称的crontroller的struct(类型),直接定义以crontroller为参数的Get或者Post方法即可实现,业务逻辑
- 通过返回一个data的map返回前端数据和网页,网页在返回给前端之前由beego进行模板渲染,展示给浏览器。
配置
conf/app.conf
appname = beeblog
httpport = 8080
runmode = dev
uname = admin
pwd = admin
model设计
models/models.go
package models
import (
"os"
"path"
"time"
"github.com/Unknwon/com"
"github.com/astaxie/beego/orm"
//只执行初始化函数,不进行其他函数的调用,驱动会在初始化函数中进行注册
_ "github.com/mattn/go-sqlite3"
)
//常量定义
const (
//数据库名称
_DB_NAME = "data/beeblog.db"
//驱动名称
_SQLITE3_DRIVER = "sqlite3"
)
//结构定义
type Category struct {
// Id默认是主键
Id int64
// 文章分类
Title string
// 创建时间
Created time.Time `orm: "index"`
// 浏览次数
Views int64 `orm: "index"`
// 分类最后一个的创建时间
TopicTime time.Time `orm: "index"`
// 分类文章数量
TopicCount int64
// 最后操作的用户Id
TopicLastUserId int64
}
type Topic struct {
Id int64
// 用户Id
Uid int64
// 标题
Title string
// 文本
Content string `orm: "size(5000)"`
// 附件
Attachment string
// 创建时间
Created time.Time `orm: "index"`
// 更新时间
Updated time.Time `orm: "index"`
//
Views int64
// 作者名称
Author string
// 回复时间
ReplyTime time.Time `orm: "index"`
// 回复数量
ReplyCount int64
// 最后回复的用户Id
ReplyLastUserId int64
}
// 主进程调用
func RegisterDB(){
//判断对比文件是否存在
if !com.IsExist(_DB_NAME) {
os.MkdirAll(path.Dir(_DB_NAME), os.ModePerm)
os.Create(_DB_NAME)
}
//注册模型
orm.RegisterModel(new(Category), new(Topic))
//注册驱动
orm.RegisterDriver(_SQLITE3_DRIVER, orm.DRSqlite)
//注册默认数据库, 默认第一个名称需要为default,然后是驱动,数据库文件,最大连接数
orm.RegisterDataBase("default", _SQLITE3_DRIVER, _DB_NAME, 10)
}
初始化数据库
main.go
package main
import (
_ "beeblog/routers"
"beeblog/controllers"
"beeblog/models"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
)
func init() {
models.RegisterDB()
}
func main() {
// 打印相关信息
orm.Debug = true
orm.RunSyncdb("default", false, true)
beego.Router("/", &controllers.MainController{})
beego.Run()
}
直接启动服务
[root@why 01:32:46 beeblog]go get github.com/Unknwon/com
[root@why 01:33:15 beeblog]go get github.com/mattn/go-sqlite3
[root@why 01:34:34 beeblog]#/root/go/bin/bee run beeblog
______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v1.10.0
2018/08/29 01:34:36 INFO ▶ 0001 Using 'beeblog' as 'appname'
2018/08/29 01:34:36 INFO ▶ 0002 Initializing watcher...
beeblog/models
beeblog
2018/08/29 01:34:40 SUCCESS ▶ 0003 Built Successfully!
2018/08/29 01:34:40 INFO ▶ 0004 Restarting 'beeblog'...
2018/08/29 01:34:40 SUCCESS ▶ 0005 './beeblog' is running...
create table `category`
-- --------------------------------------------------
-- Table Structure for `beeblog/models.Category`
-- --------------------------------------------------
CREATE TABLE IF NOT EXISTS `category` (
`id` integer NOT NULL PRIMARY KEY AUTOINCREMENT,
`title` varchar(255) NOT NULL DEFAULT '' ,
`created` datetime NOT NULL,
`views` integer NOT NULL DEFAULT 0 ,
`topic_time` datetime NOT NULL,
`topic_count` integer NOT NULL DEFAULT 0 ,
`topic_last_user_id` integer NOT NULL DEFAULT 0
);
create table `topic`
-- --------------------------------------------------
-- Table Structure for `beeblog/models.Topic`
-- --------------------------------------------------
CREATE TABLE IF NOT EXISTS `topic` (
`id` integer NOT NULL PRIMARY KEY AUTOINCREMENT,
`uid` integer NOT NULL DEFAULT 0 ,
`title` varchar(255) NOT NULL DEFAULT '' ,
`content` varchar(255) NOT NULL DEFAULT '' ,
`attachment` varchar(255) NOT NULL DEFAULT '' ,
`created` datetime NOT NULL,
`updated` datetime NOT NULL,
`views` integer NOT NULL DEFAULT 0 ,
`author` varchar(255) NOT NULL DEFAULT '' ,
`reply_time` datetime NOT NULL,
`reply_count` integer NOT NULL DEFAULT 0 ,
`reply_last_user_id` integer NOT NULL DEFAULT 0
);
2018/08/29 01:34:40.909 [I] [asm_amd64.s:2361] http server Running on http://:8080
可以看到服务已经被自动创建
创建首页
定义路由vi main.go
package main
import (
_ "beeblog/routers"
"beeblog/controllers"
"beeblog/models"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
)
func init() {
models.RegisterDB()
}
func main() {
orm.Debug = true
orm.RunSyncdb("default", false, true)
// 主页
beego.Router("/", &controllers.MainController{})
beego.Run()
}
写路由对应业务逻辑vi controllers/default.go
package controllers
import (
"github.com/astaxie/beego"
"beeblog/models"
)
type MainController struct {
beego.Controller
}
func (this *MainController) Get() {
this.TplName = "home.html"
}
主页页面vi views/home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="shortcut icon" href="/static/img/favicon.png">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<meta name="description" content="">
<meta name="author" content="">
<!-- Bootstrap core CSS -->
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
<link href="https://v3.bootcss.com/assets/js/ie10-viewport-bug-workaround.js" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="https://v3.bootcss.com/examples/starter-template/starter-template.css" rel="stylesheet">
<!-- Just for debugging purposes. Don't actually copy these 2 lines! -->
<!--[if lt IE 9]><script src="../../assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
<script src="https://v3.bootcss.com/assets/js/ie-emulation-modes-warning.js"></script>
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container">
<a class="navbar-brand" href="/">我的博客</a>
<div>
<ul class="nav navbar-nav">
<li><a href="/">首页</a></li>
<li><a href="/category">分类</a></li>
<li><a href="/topic">文章</a></li>
</ul>
</div>
</div>
</nav>
<div class="container theme-showcase">
<div class="page-header">
<h1>第一篇博客</h1>
<h6 class="text-muted">文章发表与2018年08月29日</h6>
<p>
Hello World!
</p>
</div>
</div>
<script src="https://code.jquery.com/jquery-2.2.4.js" integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
再次启动看一下首页
$ /root/go/bin/bee run beeblog
使用模板
头部模板
t_header1.html
{{define "header1"}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="shortcut icon" href="/static/img/favicon.png">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<meta name="description" content="">
<meta name="author" content="">
<!-- Bootstrap core CSS -->
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
<link href="https://v3.bootcss.com/assets/js/ie10-viewport-bug-workaround.js" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="https://v3.bootcss.com/examples/starter-template/starter-template.css" rel="stylesheet">
<!-- Just for debugging purposes. Don't actually copy these 2 lines! -->
<!--[if lt IE 9]><script src="../../assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
<script src="https://v3.bootcss.com/assets/js/ie-emulation-modes-warning.js"></script>
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
{{end}}
导航模板
t_container.html
{{define "container"}}
</head>
<body>
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container">
<a class="navbar-brand" href="/">我的博客</a>
<div>
<ul class="nav navbar-nav">
<li {{if .IsHome}}class="active"{{end}}><a href="/">首页</a></li>
<li {{if .IsCategory}}class="active"{{end}}><a href="/category">分类</a></li>
<li {{if .IsTopic}}class="active"{{end}}><a href="/topic">文章</a></li>
</ul>
</div>
<div class="pull-right">
<ul class="nav navbar-nav">
{{if .IsLogin}}
<li><a href="/login?exit=true">退出</a></li>
{{else}}
<li><a href="/login">登录</a></li>
{{end}}
</ul>
</div>
</div>
</nav>
{{end}}
- 通过当前页面位置判断导航栏
- 通过登录状态判断显示登录或退出
首页使用模板
views/home.html
{{template "header1" .}}
<title>首页 - 我的beego博客</title>
{{template "container" .}}
<div class="container theme-showcase">
<div class="page-header">
<h1>第一篇博客</h1>
<h6 class="text-muted">文章发表与2018年08月29日</h6>
<p>
Hello World!
</p>
</div>
</div>
<script src="https://code.jquery.com/jquery-2.2.4.js" integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
设计登录
主页路由
main.go
package main
import (
_ "beeblog/routers"
"beeblog/controllers"
"beeblog/models"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
)
func init() {
models.RegisterDB()
}
func main() {
orm.Debug = true
orm.RunSyncdb("default", false, true)
beego.Router("/", &controllers.MainController{})
beego.Router("/login", &controllers.LoginController{})
// 自动路由,结构必须以Controller结尾
beego.AutoRouter(&controllers.TopicController{})
beego.Router("/reply", &controllers.ReplyController{})
beego.Run()
}
登录前端
views/login.html
{{template "header1" .}}
<title>首页 - 我的beego博客</title>
</head>
<body>
<div class="container" style="width: 500px">
<form method="post" action="/login">
<div class="form-group">
<label>Account</label>
<input id="uname" name="uname" class="form-control" placeholder="Enter Account">
</div>
<div class="form-group">
<label>Password</label>
<input id="pwd" name="pwd" class="form-control" placeholder="Password">
</div>
<div class="checkbox">
<label>
<input name="autoLogin" type="checkbox"> 记住登录
</label>
</div>
<button type="submit" class="btn btn-default" onclick="return checkInput();">登录</button>
<button class="btn btn-default" onclick="return backToHome();">退出</button>
</form>
</div>
<script type="text/javascript">
function checkInput() {
var uname = document.getElementById("uname")
var pwd = document.getElementById("pwd")
if (uname.value.length == 0) {
alert("请输入账号");
return false
}
if (pwd.value.length == 0) {
alert("请输入密码");
return false
}
return true
}
function backToHome() {
window.location.href = "/";
return false;
}
</script>
<script src="https://code.jquery.com/jquery-2.2.4.js" integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
从前端输入用户名和密码到后端,js对账号和密码的为空做了验证
controller
controllers/login.go
package controllers
import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/context"
)
type LoginController struct {
beego.Controller
}
func (this *LoginController) Get() {
// 用于退出
isExit := this.Input().Get("exit") == "true"
if isExit {
this.Ctx.SetCookie("uname", "", -1, "/")
this.Ctx.SetCookie("pwd", "", -1, "/")
this.Redirect("/", 301)
return
}
// 用于登录
this.TplName = "login.html"
}
func (this *LoginController) Post() {
// 获取数据
uname := this.Input().Get("uname")
pwd := this.Input().Get("pwd")
// 直接进行比对判断
autoLogin := this.Input().Get("autoLogin") == "on"
// 认证登录
if beego.AppConfig.String("uname") == uname && beego.AppConfig.String("pwd") == pwd {
maxAge := 0
if autoLogin {
maxAge = 1<<31 - 1
}
this.Ctx.SetCookie("uname", uname, maxAge, "/")
this.Ctx.SetCookie("pwd", pwd, maxAge, "/")
}
this.Redirect("/", 301)
return
}
// cookie认证
func checkAccount(ctx *context.Context) bool {
ck, err := ctx.Request.Cookie("uname")
if err != nil {
return false
}
uname := ck.Value
//上边已经声明
ck, err = ctx.Request.Cookie("pwd")
if err != nil {
return false
}
pwd := ck.Value
return beego.AppConfig.String("uname") == uname && beego.AppConfig.String("pwd") == pwd
}
首页对登录进行认证
controllers/default.go
package controllers
import (
"github.com/astaxie/beego"
)
type MainController struct {
beego.Controller
}
func (this *MainController) Get() {
this.Data["IsHome"] = true
this.TplName = "home.html"
this.Data["IsLogin"] = true// checkAccount(this.Ctx)
}
分类
创建路由
main.go
package main
import (
_ "beeblog/routers"
"beeblog/controllers"
"beeblog/models"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
)
func init() {
models.RegisterDB()
}
func main() {
orm.Debug = true
orm.RunSyncdb("default", false, true)
beego.Router("/", &controllers.MainController{})
beego.Router("/login", &controllers.LoginController{})
beego.Router("/category", &controllers.CategoryController{})
// 自动路由,结构必须以Controller结尾
beego.AutoRouter(&controllers.TopicController{})
beego.Router("/reply", &controllers.ReplyController{})
beego.Run()
}
前端页面
{{template "header1" .}}
<title>分类 - 我的beego博客</title>
{{template "container" .}}
<div class="container">
<h1>分类列表</h1>
<form method="get" action="/category">
<div class="form-group">
<label>分类名称</label>
<input id="name" name="name" class="form-control" placeholder="Enter Account">
</div>
<input type="hidden" name="op" value="add">
<button type="submit" class="btn btn-default" onclick="return checkInput();">添加</button>
</form>
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>名称</th>
<th>文章数</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{{range .Categories}}
<tr>
<th>{{.Id}}</th>
<th>{{.Title}}</th>
<th>{{.TopicCount}}</th>
<th>
<a href="/category?op=del&id={{.Id}}">删除</a>
</th>
</tr>
{{end}}
</tbody>
</table>
</div>
<script type="text/javascript">
function checkInput() {
var name = document.getElementById("name")
if (name.value.length == 0) {
alert("请分类名称");
return false
}
return true
}
</script>
<script src="https://code.jquery.com/jquery-2.2.4.js" integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
使用form进行添加,使用/category?op=del&id={{.Id}}
进行删除
数据库操作
models/models.go
func AddCategory(name string) error {
o := orm.NewOrm()
t := time.Now()
// 这里传递的一个引用
cate := &Category{Title: name}
// 获取表
qs := o.QueryTable("category")
// 查找数据是否存在
err := qs.Filter("title", name).One(cate)
if err == nil {
return err
}
cate = &Category{Title: name, Created: t, TopicTime: t}
// 插入数据
_, err = o.Insert(cate)
if err != nil {
return err
}
return nil
}
func GetAllCategories() ([]*Category, error) {
o := orm.NewOrm()
cates := make([]*Category, 0)
qs := o.QueryTable("category")
_, err := qs.All(&cates)
return cates, err
}
func DelCategory(id string) error {
cid, err := strconv.ParseInt(id, 10, 64)
if err != nil {
return err
}
o := orm.NewOrm()
cate := &Category{Id: cid}
_, err = o.Delete(cate)
return err
}
controller业务逻辑
package controllers
import (
"github.com/astaxie/beego"
"beeblog/models"
)
type CategoryController struct {
beego.Controller
}
func (this *CategoryController) Get() {
op := this.Input().Get("op")
switch op {
case "add":
name := this.Input().Get("name")
err := models.AddCategory(name)
if err == nil {
beego.Error(err)
}
this.Redirect("/category", 301)
return
case "del":
id := this.Input().Get("id")
err := models.DelCategory(id)
if err == nil {
beego.Error(err)
}
this.Redirect("/category", 301)
return
}
this.Data["IsCategory"] = true
this.TplName = "category.html"
var err error
this.Data["Categories"],err = models.GetAllCategories()
if err != nil {
beego.Error(err)
}
}
文章添加和展示
路由
main.go
package main
import (
_ "beeblog/routers"
"beeblog/controllers"
"beeblog/models"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
)
func init() {
models.RegisterDB()
}
func main() {
orm.Debug = true
orm.RunSyncdb("default", false, true)
beego.Router("/", &controllers.MainController{})
beego.Router("/login", &controllers.LoginController{})
beego.Router("/category", &controllers.CategoryController{})
beego.Router("/topic", &controllers.TopicController{})
// 自动路由,结构必须以Controller结尾
beego.AutoRouter(&controllers.TopicController{})
beego.Router("/reply", &controllers.ReplyController{})
beego.Run()
}
前端页面
用于添加文章
views/topic_add.html
{{template "header1" .}}
<title>添加文章 - 我的beego博客</title>
{{template "container" .}}
<div class="container">
<h1>添加文章</h1>
<form method="post" action="/topic/">
<div class="form-group">
<label>文章标题: </label>
<input type="text" name="title" class="form-control">
</div>
<div class="form-group">
<label>文章内容: </label>
<textarea class="form-control" name="content" cols="30" rows="10"></textarea>
</div>
<button type="submit" class="btn btn-default">添加文章</button>
</form>
<script type="text/javascript">
function checkInput() {
var title = document.getElementById("title")
if (title.value.length == 0) {
alert("请输入文章标题);
return false
}
return true
}
</script>
<script src="https://code.jquery.com/jquery-2.2.4.js" integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
用于展示文章
{{template "header1" .}}
<title>文章 - 我的beego博客</title>
{{template "container" .}}
<div class="container">
<h1>文章列表</h1>
<a href="/topic/add" class="btn btn-default">添加文章</a>
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>名称</th>
<th>文章数</th>
<th>浏览</th>
<th>回复</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{{range .Topics}}
<tr>
<th>{{.Id}}</th>
<th>{{.Title}}</th>
<th>{{.Content}}</th>
<th>{{.Views}}</th>
<th>{{.ReplyCount}}</th>
<th>
<a href="/topic/delete/{{.Id}}">删除</a>
</th>
</tr>
{{end}}
</tbody>
</table>
</div>
<script type="text/javascript">
function checkInput() {
var name = document.getElementById("name")
if (name.value.length == 0) {
alert("请分类名称");
return false
}
return true
}
</script>
<script src="https://code.jquery.com/jquery-2.2.4.js" integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
数据库操作
models/models.go
func AddTopic(title, content string) error {
o := orm.NewOrm()
topic := &Topic{
Title: title,
Content: content,
Created: time.Now(),
Updated: time.Now(),
ReplyTime: time.Now(),
}
_, err := o.Insert(topic)
return err
}
func GetAllTopics(isDesc bool) ([]*Topic, error) {
o := orm.NewOrm()
topics := make([]*Topic, 0)
qs := o.QueryTable("topic")
var err error
// 用于倒叙
if isDesc {
// create为小写
_, err = qs.OrderBy("-created").All(&topics)
}else{
_, err = qs.All(&topics)
}
return topics, err
}
controller业务逻辑
controllers/topic.go
package controllers
import (
"github.com/astaxie/beego"
"beeblog/models"
)
type TopicController struct {
beego.Controller
}
func (this *TopicController) Get() {
this.Data["IsLogin"] = checkAccount(this.Ctx)
this.Data["IsTopic"] = true
this.TplName = "topic.html"
var err error
category := ""
this.Data["Topics"], err = models.GetAllTopics(category)
if err != nil {
beego.Error(err)
}
}
func (this *TopicController) Post() {
if !checkAccount(this.Ctx) {
this.Redirect("/login", 302)
return
}
title := this.Input().Get("title")
content := this.Input().Get("content")
tid := this.Input().Get("tid")
var err error
if len(tid) != 0 {
err = models.ModifyTopic(tid, title, content)
}else{
err = models.AddTopic(title, content)
}
if err != nil {
beego.Error(err)
}
this.Redirect("/topic", 302)
}
func (this *TopicController) Add() {
//this.Ctx.WriteString("add")
this.TplName = "topic_add.html"
}
首页获取文章
views/home.html
{{template "header1" .}}
<title>首页 - 我的beego博客</title>
{{template "container" .}}
<div class="container theme-showcase">
{{range .Topics}}
<div class="page-header">
<h1>{{.Title}}</h1>
<h6 class="text-muted">文章发表{{.Create}}, 共有{{.Views}}次浏览,{{.ReplyCount}}个评论.</h6>
<p>
{{.Content}}
</p>
</div>
{{end}}
</div>
<script src="https://code.jquery.com/jquery-2.2.4.js" integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
controllers/default.go
package controllers
import (
"github.com/astaxie/beego"
"beeblog/models"
)
type MainController struct {
beego.Controller
}
func (this *MainController) Get() {
this.Data["IsHome"] = true
this.TplName = "home.html"
this.Data["IsLogin"] = checkAccount(this.Ctx)
this.Data["Categories"], err := models.GetAllCategories()
if err != nil {
beego.Error(err)
}
}
查看文章,修改和删除
controller
controllers/topic.go
func (this *TopicController) View() {
this.TplName = "topic_view.html"
// 获取自动路由的参数
tidMap := this.Ctx.Input.Params()
this.Data["Tid"] = tidMap["0"]
topic, err := models.GetTopic(tidMap["0"])
if err != nil {
beego.Error(err)
this.Redirect("/", 302)
return
}
this.Data["Topic"] = topic
replies, err := models.GetAllReplies(tidMap["0"])
if err != nil {
beego.Error(err)
return
}
this.Data["Replies"] = replies
this.Data["IsLogin"] = checkAccount(this.Ctx)
}
func (this *TopicController) Modify() {
this.TplName = "topic_modify.html"
tid := this.Input().Get("tid")
topic, err := models.GetTopic(tid)
if err != nil {
beego.Error(err)
}
this.Data["Topic"] = topic
this.Data["Tid"] = tid
}
func (this *TopicController) Delete() {
if !checkAccount(this.Ctx) {
this.Redirect("/login", 302)
return
}
tidMap := this.Ctx.Input.Params()
tid := tidMap["0"]
err := models.DeleteTopic(tid)
if err != nil {
beego.Error(err)
}
this.Redirect("/topic", 302)
}
前端界面
查看
views/topic_view.html
{{template "header1" .}}
<title>{{.Topic.Title}} - 我的beego博客</title>
{{template "container" .}}
<div class="container">
<h1>{{.Topic.Title}}</h1>
<a href="/topic/modify?tid={{.Tid}}" class="btn btn-default">修改文章</a>
{{.Topic.Content}}
</div>
<script src="https://code.jquery.com/jquery-2.2.4.js" integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
编辑
views/topic_modify.html
{{template "header1" .}}
<title>添加文章 - 我的beego博客</title>
{{template "container" .}}
<div class="container">
<h1>添加文章</h1>
<form method="post" action="/topic">
<input class="hidden" type="text" name="tid" value="{{.Topic.Id}}">
<div class="form-group">
<label>文章标题: </label>
<input type="text" name="title" class="form-control" value="{{.Topic.Title}}">
</div>
<div class="form-group">
<label>文章内容: </label>
<textarea class="form-control" name="content" cols="30" rows="10">{{.Topic.Content}}</textarea>
</div>
<button type="submit" class="btn btn-default">添加文章</button>
</form>
<script type="text/javascript">
function checkInput() {
var name = document.getElementById("name")
if (name.value.length == 0) {
alert("请分类名称");
return false
}
return true
}
</script>
<script src="https://code.jquery.com/jquery-2.2.4.js" integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
数据库操作
orm这边可以定义一个全局的
func GetTopic(tid string) (*Topic, error) {
tidNum, err := strconv.ParseInt(tid, 10, 64)
if err != nil {
return nil, err
}
o := orm.NewOrm()
topic := new(Topic)
qs := o.QueryTable("topic")
err = qs.Filter("id", tidNum).One(topic)
if err != nil{
return nil, err
}
topic.Views++
_, err = o.Update(topic)
return topic, err
}
func ModifyTopic(tid, title, content string) error {
// 转为int64
tidNum, err := strconv.ParseInt(tid, 10, 64)
if err != nil {
return err
}
o := orm.NewOrm()
topic := &Topic{Id: tidNum}
if o.Read(topic) == nil {
topic.Title = title
topic.Content = content
topic.Updated = time.Now()
o.Update(topic)
}
return err
}
func DeleteTopic(tid string) error {
tidNum, err := strconv.ParseInt(tid, 10, 64)
if err != nil {
return err
}
o := orm.NewOrm()
topic := &Topic{Id: tidNum}
_, err = o.Delete(topic)
return err
}
文章设置分类
前端界面
add添加增加的地方,views/topuc_add.html
{{template "header1" .}}
<title>添加文章 - 我的beego博客</title>
{{template "container" .}}
<div class="container">
<h1>添加文章</h1>
<form method="post" action="/topic/">
<div class="form-group">
<label>文章标题: </label>
<input type="text" name="title" class="form-control">
</div>
<div class="form-group">
<label>文章分类: </label>
<input type="text" name="category" class="form-control">
</div>
<div class="form-group">
<label>文章内容: </label>
<textarea class="form-control" name="content" cols="30" rows="10"></textarea>
</div>
<button type="submit" class="btn btn-default">添加文章</button>
</form>
<script type="text/javascript">
function checkInput() {
var title = document.getElementById("title")
if (title.value.length == 0) {
alert("请输入文章标题);
return false
}
return true
}
</script>
<script src="https://code.jquery.com/jquery-2.2.4.js" integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
motify添加原来的值,views/topic_modify.html
{{template "header1" .}}
<title>添加文章 - 我的beego博客</title>
{{template "container" .}}
<div class="container">
<h1>添加文章</h1>
<form method="post" action="/topic">
<input class="hidden" type="text" name="tid" value="{{.Topic.Id}}">
<div class="form-group">
<label>文章标题: </label>
<input type="text" name="title" class="form-control" value="{{.Topic.Title}}">
</div>
<div class="form-group">
<label>文章分类: </label>
<input type="text" name="title" class="form-control" value="{{.Topic.Category}}">
</div>
<div class="form-group">
<label>文章内容: </label>
<textarea class="form-control" name="content" cols="30" rows="10">{{.Topic.Content}}</textarea>
</div>
<button type="submit" class="btn btn-default">添加文章</button>
</form>
<script type="text/javascript">
function checkInput() {
var name = document.getElementById("name")
if (name.value.length == 0) {
alert("请分类名称");
return false
}
return true
}
</script>
<script src="https://code.jquery.com/jquery-2.2.4.js" integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
controller
POST方法添加参数
controllers/topic.go
func (this *TopicController) Post() {
if !checkAccount(this.Ctx) {
this.Redirect("/login", 302)
return
}
title := this.Input().Get("title")
content := this.Input().Get("content")
category := this.Input().Get("category")
tid := this.Input().Get("tid")
var err error
if len(tid) != 0 {
err = models.ModifyTopic(tid, title, category, content)
}else{
err = models.AddTopic(title, category, content)
}
if err != nil {
beego.Error(err)
}
this.Redirect("/topic", 302)
}
数据库处理
model的add和motify也需要加一下
type Topic struct {
Id int64
Uid int64
Title string
Category string
Content string `orm: "size(5000)"`
Attachment string
Created time.Time `orm: "index"`
Updated time.Time `orm: "index"`
Views int64
Author string
ReplyTime time.Time `orm: "index"`
ReplyCount int64
ReplyLastUserId int64
}
...
func AddTopic(title, category, content string) error {
o := orm.NewOrm()
topic := &Topic{
Title: title,
Category: category,
Content: content,
Created: time.Now(),
Updated: time.Now(),
ReplyTime: time.Now(),
}
_, err := o.Insert(topic)
return err
}
...
func ModifyTopic(tid, title, category , content string) error {
// 转为int64
tidNum, err := strconv.ParseInt(tid, 10, 64)
if err != nil {
return err
}
o := orm.NewOrm()
topic := &Topic{Id: tidNum}
if o.Read(topic) == nil {
topic.Title = title
topic.Category = category
topic.Content = content
topic.Updated = time.Now()
o.Update(topic)
}
return err
}
添加评论
前端页面
views/topic_view.html
{{template "header1" .}}
<title>{{.Topic.Title}} - 我的beego博客</title>
{{template "container" .}}
<div class="container">
<h1>{{.Topic.Title}}</h1>
<a href="/topic/modify?tid={{.Tid}}" class="btn btn-default">修改文章</a>
{{.Topic.Content}}
</div>
<div class="container">
<h3>文本回复</h3>
<form method="post" action="/reply/add">
<input type="hidden" name="tid" value="{{.Topic.Id}}">
<div class="form-group">
<label>显示昵称:</label>
<input type="text" class="form-control" name="nickname">
</div>
<div class="form-group">
<label>内容:</label>
<textarea type="content" id="" cols="30" rows="10" class="form-control"></textarea>
</div>
<button class="btn btn-default">回复</button>
</form>
</div>
<script src="https://code.jquery.com/jquery-2.2.4.js" integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
controller
controllers/reply.go
package controllers
import (
"github.com/astaxie/beego"
"beeblog/models"
)
type ReplyController struct {
beego.Controller
}
func (this *ReplyController) Add() {
tid := this.Input().Get("tid")
nickname := this.Input().Get("nickname")
content := this.Input().Get("content")
err := models.AddReply(tid, nickname, content)
if err != nil {
beego.Error(err)
}
this.Redirect("/topic/view/"+tid, 302)
}
数据库操作
创建model
models/models.go
type Comment struct {
Id int64
Tid int64
Name string
Content string `orm: "size(1000)"`
Created time.Time `orm: "index"`
}
对于回复的操作
func AddReply(tid, nickname, content string) error {
tidNum, err := strconv.ParseInt(tid, 10, 64)
if err != nil {
return err
}
reply := &Comment{
Tid: tidNum,
Name: nickname,
Content: content,
Created: time.Now(),
}
o := orm.NewOrm()
_, err = o.Insert(reply)
return err
}
设置路由
main.go
package main
import (
_ "beeblog/routers"
"beeblog/controllers"
"beeblog/models"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
)
func init() {
models.RegisterDB()
}
func main() {
orm.Debug = true
orm.RunSyncdb("default", false, true)
beego.Router("/", &controllers.MainController{})
beego.Router("/login", &controllers.LoginController{})
beego.Router("/category", &controllers.CategoryController{})
beego.Router("/topic", &controllers.TopicController{})
// 自动路由,结构必须以Controller结尾
beego.AutoRouter(&controllers.TopicController{})
beego.Router("/reply", &controllers.ReplyController{})
beego.Router("/reply/add", &controllers.ReplyController{}, "post:Add")
beego.Run()
}
显示回复
前端显示
views/topic_view.html
{{template "header1" .}}
<title>{{.Topic.Title}} - 我的beego博客</title>
{{template "container" .}}
<div class="container">
<h1>{{.Topic.Title}}</h1>
<a href="/topic/modify?tid={{.Tid}}" class="btn btn-default">修改文章</a>
{{.Topic.Content}}
</div>
<div class="container">
{{range .Replies}}
<h3>{{.Name}} <small>{{.Created}}</small> </h3>
{{.Content}}
{{end}}
<h3>文本回复</h3>
<form method="post" action="/reply/add">
<input type="hidden" name="tid" value="{{.Topic.Id}}">
<div class="form-group">
<label>显示昵称:</label>
<input type="text" class="form-control" name="nickname">
</div>
<div class="form-group">
<label>内容:</label>
<textarea type="content" id="" cols="30" rows="10" class="form-control"></textarea>
</div>
<button class="btn btn-default">回复</button>
</form>
</div>
<script src="https://code.jquery.com/jquery-2.2.4.js" integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
controller
在views中显示
controllers/topic.go
func (this *TopicController) View() {
this.TplName = "topic_view.html"
// 获取自动路由的参数
tidMap := this.Ctx.Input.Params()
this.Data["Tid"] = tidMap["0"]
topic, err := models.GetTopic(tidMap["0"])
if err != nil {
beego.Error(err)
this.Redirect("/", 302)
return
}
this.Data["Topic"] = topic
replies, err := models.GetAllReplies(tidMap["0"])
if err != nil {
beego.Error(err)
return
}
this.Data["Replies"] = replies
this.Data["IsLogin"] = checkAccount(this.Ctx)
}
数据库操作
func GetAllReplies(tid string) (replies []*Comment, err error) {
tidNum, err := strconv.ParseInt(tid, 10, 64)
if err != nil {
return nil, err
}
replies = make([]*Comment, 0)
o := orm.NewOrm()
qs := o.QueryTable("comment")
_, err = qs.Filter("tid", tidNum).All(&replies)
return replies, err
}
删除评论
前端只需要提交一个删除操作
{{$tid := .Topic.Id}}
{{$islogin := .IsLogin}}
{{range .Replies}}
<h3>{{.Name}} <small>{{.Created}}</small> {{if $islogin}}</h3><a href="/reply/delete?tid={{$tid}}&rid={{.Id}}">删除</a>{{end}}
{{.Content}}
{{end}}
注册路由
beego.Router("/reply/delete", &controllers.ReplyController{}, "get:Delete")
controller对应的方法
func (this *ReplyController) Delete() {
if !checkAccount(this.Ctx) {
return
}
tid := this.Input().Get("tid")
rid := this.Input().Get("rid")
err := models.DeleteReply(rid)
if err != nil {
beego.Error(err)
}
this.Redirect("/topic/view/"+tid, 302)
}
数据库对应的操作
func DeleteReply(rid string) error {
ridNum, err := strconv.ParseInt(rid, 10, 64)
if err != nil {
return err
}
o := orm.NewOrm()
reply := &Comment{Id: ridNum}
_, err = o.Delete(reply)
return err
}
分类显示
views/home.html
{{template "header1" .}}
<title>首页 - 我的beego博客</title>
{{template "container" .}}
<div class="container theme-showcase">
<div class="col-md-9">
{{range .Topics}}
<div class="page-header">
<h1>{{.Title}}</h1>
<h6 class="text-muted">文章发表{{.Created}}, 共有{{.Views}}次浏览,{{.ReplyCount}}个评论.</h6>
<p>
{{.Content}}
</p>
</div>
</div>
{{end}}
</div>
<div class="col-md-3">
<h3>文章分类</h3>
<ul>
{{range .Categories}}
<li><a href="/?cate={{.Title}}">{{.Title}}</a></li>
{{end}}
<script src="https://code.jquery.com/jquery-2.2.4.js" integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
controllers/default.go
package controllers
import (
"github.com/astaxie/beego"
"beeblog/models"
)
type MainController struct {
beego.Controller
}
func (this *MainController) Get() {
var err error
this.Data["IsHome"] = true
this.TplName = "home.html"
this.Data["IsLogin"] = checkAccount(this.Ctx)
this.Data["Topics"], err = models.GetAllTopics(this.Input().Get("cate"), true)
if err != nil {
beego.Error(err)
}
categories, err := models.GetAllCategories()
if err != nil{
beego.Error(err)
}
this.Data["Categories"] = categories
}
models/models.py
func GetAllTopics(cate string, isDesc bool) ([]*Topic, error) {
o := orm.NewOrm()
topics := make([]*Topic, 0)
qs := o.QueryTable("topic")
var err error
// 用于倒叙
if isDesc {
if len(cate) > 0 {
qs = qs.Filter("category", cate)
}
// create为小写
_, err = qs.OrderBy("-created").All(&topics)
}else{
_, err = qs.All(&topics)
}
return topics, err
}
将原来调用GetAllTopics方法的第一个参数改为空字符串