目录
1、Beego框架概述
Beego是用Go语言开发的高效的HTTP框架,可以用来快速开发APl、Web应用及后端服务等各种应用。Beego是一个RESTful的框架,主要设计灵感来源于Tornado、Sinatra和Flask这3个框架。它还结合了Go语言自身的一些特性(接口、结构体嵌入等)。
1.1、Beego架构简介
Beego是基于多个独立模块构建的,是一个高度解耦的框架。最初在设计Beego时就考虑到了功能模块化,用户即使不适用Beego的HTTP逻辑,也可以独立使用这些模块(例如可以使用cache模块来处理缓存逻辑,使用日志模块来记录操作信息,使用config模块来解析各种格式
的文件)。
1.2、Beego的执行逻辑
执行逻辑可以拆分为以下几段:
- main文件监听启动端口接收请求。
- 请求经过路由和参数过滤功能被转发给绑定URL的控制器处理。
- 控制器(Controller)调用Model、Session管理、日志处理、缓存处理模块,以及辅助工具包进行相应的业务处理。其中,模型(Modl)通过ORM直接操作数据库。
- 业务处理完成,返回响应或视图(View)给请求方。
1.3、Beego项目基本结构
在实际的项目中,可能有增减或改动。
beego
- conf #配置文件目录
- app.conf #配置文件
- controllers #控制器目录
- default.go #默认控制器文件
- main.go #入口
- models #模型目录
- routers #路由目录
- router.go #路由文件
- static #静态文件目录
- css # css文件目录
- img #图片文件目录
- js #js文件目录
- tests #测试文件目录
- default_test.go #默认测试文件
- views #视图目录
- index.tpl #默认视图文件
2、Beego安装
2.1、安装Beego核心包
go get -u github.com/astaxie/beego
# beego v2版本
go get -u github.com/beego/beego/v2
2.2、安装Beego orm包
Beego的orm包用于操作数据库,它是一个独立的模块,需要单独安装。最新开发版把orm包移动到了client目录下面,所以安装使用如下命令:
go get github.com/astaxie/beego/client/orm
之前的稳定版本安装使用如下命令:
go get github.com/astaxie/beego/orm
如果以上稳定版本命令无法下载orm包,则使用“go get github.com/astaxie/beego/client/orm”命令下载安装。
2.3、安装bee工具包
bee工具包是beego开发的辅助工具,用于快速创建项目、运行项目及打包项目。安装方法如下:
# go 1.16 以前的版本
go get -u github.com/beego/bee/v2
# go 1.16及以后的版本
go install github.com/beego/bee/v2@latest
安装完之后,bee 可执行文件默认存放在 $GOPATH/bin
里面,所以需要把 $GOPATH/bin
添加到环境变量中,才可以进行下一步。
3、创建并运行Beego第一个项目
3.1、使用bee创建项目
安装好bee工具包后,直接选择一个目录,打开命令行终端输入:
s bee new beego
命令行终端会返回如下信息,如果最后是“New application successfully created!”,则代表项目创建成功:
3.2、运行项目
在项目创建成功后,会生成一个名为“beego”的项目目录,可以通过bee工具运行项目。进入刚才创建好的项目根目录下,运行“bee run”命令:
cd ./beego
bee run
如果运行成功,则命令行终端会输出如下:
通过浏览器访问htp:/localhost:8080,可以看到“Welcome to Beego”页面,如图所示。
4、Beego参数配置
4.1、Beego默认参数
在默认情况下,conf/app.conf就是默认的配置文件。该文件的内容形式如下:
appname = beego #应用名称
httpport = 8080 #端口
runmode = dev #运行模式:dev、test、prod
4.2、Beego自定义参数
也可以自定义参数配置,然后通过beego.AppConfig对象的方法读取配置。例如,在app.conf增加下面自定义配置:
# MySQL数据库的配置参数
mysql_user = "root"
mysql_password = "123456"
mysql_host = "127.0.0.1:3306"
mysql_dbname = "beego"
下面是读取配置的代码:
beego.AppConfig.String("mysql_user")
beego.AppConfig.String("mysql_password")
beego.AppConfig.String("mysql_host")
beego.AppConfig.String("mysql_dbname")
4.3、不同运行级别的参数
在Beego中,runmode参数可以被设置为不同的运行级别,一般用来区分不用的运行环境,例如dev、test等。如果希望数据库配置在不同环境中账号密码都不一样,则可以使用如下配置方式:
# 配置运行级别
runmode = "dev"
[dev]
mysql_user = "root"
mysql_password = "123456"
mysql_host = "127.0.0.1:3306"
mysql_dbname = "beego"
[test]
mysql_user = "root1"
mysql_password = "123456"
mysql_host = "127.0.0.1:3306"
mysql_dbname = "beego"
[prod]
mysql_user = "root2"
mysql_password = "123456"
mysql_host = "127.0.0.1:3306"
mysql_dbname = "beego"
上面的例子,为dev、test、prod这3个环境配置了不同的数据库参数。在通过beego.AppConfig读取参数时,由runmode决定读取哪个环境的参数。
4.4、使用多个配置文件
在实际项目中,一般都使用多个配置文件管理配置,多个配置文件也方便模块化管理配置。例如,新建一个名为ysql.conf的配置文件,用来保存数据库配置。该文件的内容如下:
[dev]
mysql_user = "root"
mysql_password = "123456"
mysql_host = "127.0.0.1:3306"
mysql_dbname = "beego"
在conf/app.conf主配置文件中,通过“include”命令将小ySQL配置文件包含进去:
appname = beego
httpport = 8080
runmode = dev
#包含MySQL配置文件
include "mysql.conf"
这种通过“include”命令包含其他配置文件的方式,跟把所有配置都写在一个配置文件的效果是一样的。区别就是:在使用多个配置文件时,各个模块的配置更加清晰。
无论是使用“include’”命令包含配置文件,还是直接将所有配置都写在一个配置文件,读取配置的方式是一样的。
5、Beego控制器
5.1、路由配置
Beego提供两种设置处理器函数的路由配置的方式。
5.1.1、直接绑定处理器函数。
直接绑定处理器函数,就是直接将一个URL路由和一个函数绑定起来。示例如下:
//将URL和一个匿名函数绑定起来,这个URL的GET请求由这个匿名函数处理
beego.Get("/hello", func(ctx *context.Context) {
ctx.Output.Body([]byte("hi beego"))
})
// 定义一个处理器函数
func Index(ctx *context.Context) {
ctx.Output.Body([]byte("hello beego"))
}
//将URL /index路由和index()函数绑定起来,由Index()函数处理这个URL的POST请求
beego.Post("/index", Index)
下面是Beego支持的常用基础函数:
beego.Get (router, beego.FilterFunc)
beego.Post (router, beego.FilterFunc)
beego.Any (router, beego.FilterFunc)
其中beego.Any()函数用于处理任意HTTP请求,可以根据不同的HTTP请求方法选择用不同的函数设置路由。
5.1.2、绑定一个控制器对象
Beego默认支持RESTful风格。RESTful路由使用beego.Router()函数设置。
示例如下:
// “/”的所有HTTP请求方法都由MainController控制器的对应函数处理
beego.Router("/",&controllers.MainController{))
// “/user”的所有HTTP请求方法都由UserControl1er控制器的对应函数处理
// 例如:GET/user请求由Get()函数处理,P0ST/user请求由Post()函数处理
beego.Router("/user",&controllers.UserController{})
5.1.3、URL路由方式
1.固定路由
前面介绍的URL路由例子都属于固定路由方式。固定路由是指URL规则是固定的一个URL。
示例如下:
beego.Router("/user",&controllers.UserController{})
2.正则路由
正则路由比较灵活。一个正则路由代表的是一序列的URL。正则路由更像是一种URL模板。
URL正则路由示例如下:
/user/:id
/user/:id([0-9]+)
/user/:username([\w]+)
/1ist_:cat([0-9]+)_:page([0-9]+).html
/api/*
在Controller对象中,可以通过下面的方式获取URL路由匹配的参数:
this.Ctx.Input.Param(":id")
3.自动路由
自动路由是指,通过反射获取控制器的名字和控制器实现的所有函数名字,自动生成URL路由。使用自动路由,需要用beego.AutoRouter()函数注册控制器。
示例如下:
beego.AutoRouter(&controllers.UserController())
然后可以通过如下形式访问路由:
/user/1ogin //调用UserContro11er中的Login()方法
除前缀两个“/:Controller/:Method
”形式的匹配外,对于剩下的URL,Beego会自动将它们解析为参数保存在this.Ctx.Input.Params中。
4.路由命名空间
路由命名空间(namespace),一般用来做API接口开发版本处理。示例如下:
//创建版本2的命名空间
ns2 := beego.NewNamespace("/v2",
beego.NSNamespace("/user",
//URL路由: /v2/user/info
beego.NSRouter("/info", &controllers.User2Controller{})
),
)
//注册namespace
beego.AddNamespace(ns2)
通过NewNamespace()函数可以创建多个命名空间,NSNamespace()函数可以无限嵌套命名空间。从上面的例子可以看出来,命名空间的作用其实就是定义URL路由的前缀。如果一个命名空间定义URL路由为“/user”,则这个命名空间下面定义的所有路由的前缀都是以“/user”开头的。
下面是命名空间支持的常用路由设置函数:
NewNamespace(prefix string, funcs ...interface{})
NSNamespace(prefix string, funcs ...interface())
NSPost (rootpath string, f FilterFunc)
这些路由设置函数的参数,跟前面的路由设置函数类似,
区别是:命名空间的函数名前面多了NS前缀。
5.2、控制器函数
控制器函数是指处理用户请求的函数。Beego框架支持beego.FilterFunc()函数和控制器函数两种处理用户请求的函数。
5.2.1、beego.FilterFunc()函数
beego.FilterFunc()是最简单的请求处理函数,其定义如下:
type FilterFunc func(*context.Context)
即只要定义一个函数,并且接收一个Context参数,则这个函数就可以作为处理用户请求的函数。示例如下:
func DoLogin(ctx *context.Context){
//省去处理请求的逻辑
//通过Context获取请求参数,返回请求结果
}
有了处理函数,就可以将处理函数跟一个URL路由绑定起来。示例如下:
beego.Get ("/user/login", DoLogin)
5.2.2、控制器函数
控制器函数是Beego的RESTful API的实现方式。在Beego的设计中,控制器就是一个嵌套了beego.Controller的结构体对象。示例如下:
//定义一个新的控制器
type UserController struct {
//嵌套beego基础控制器
beego.Controller
}
结构体嵌套类似于其他高级语言中的“继承”特性,嵌套beego.Controller控制器,就拥有了beego.Controller定义的属性和方法。
5.3、获取请求参数
基础控制器beego.Controller,提供了多种读取请求参数的函数。
下面分别介绍各种获取参数的场景。
5.3.1、默认获取参数方式
基础控制器beego.Controller提供了形如“GetXXX()”的一系列函数来获取参数,其中“XXX”是指返回不同的数据类型,比如GetInt()等函数。示例如下:
type UserController struct {
beego.Controller
}
//处理GET请求
func (this *UserController) Get() {
//获取参数,返回int类型
id, _ := this.GetInt("uid")
//获取参数,返回string类型。如果参数不存在,则返回none作为默认值
username := this.GetString("username", "none")
//获取参数,返回float类型。如果参数不存在,则返回0作为默认值
balance, _ := this.GetFloat("balance", 0)
str := fmt.Sprint("id:", id, "\tusername:", username, "\tbalance:", balance)
this.Ctx.Output.Body([]byte(str))
}
注册路由:
beego.Router("/user", &controllers.UserController{})
下面是常用的获取参数的函数定义:
GetString(key string,def ...string) string
GetInt(key string,def...int)(int, error)
GetBool(key string,def ...bool)(bool, error)
默认情况下,用户请求的参数都是字符串类型。如果要转换成其他类型,则有类型转换失败的可能性。因此除GetString()函数外,其他形如“GetXXX”的函数都返回两个值:第1个值是需要获取的参数值;第2个值是error,表示是数据类型转换是否失败。
5.3.2、绑定结构体方式
针对POST请求的表单数据,Beeg0支持直接将表单数据绑定到一个结构体变量。示例如下:
//定义一个结构体用来保存表单数据
type UserForm struct {
//忽略掉Id字段
Id int `form:"-"`
//表单字段名为name
Name string `form:"name"`
Phone string `form:"phone"`
}
如果表单的字段跟结构体的字段(小写)同名,则不需要设置fom标签。表单的HTML代码示例如下:
<form acton="/user" method="POST">
手机号:<input name="phone" type="text" /><br/>
用户名:<input name="name" type="text" />
<input type="submit" value="提交" />
</form>
表单对应的控制器函数代码示例如下:
//处理POST请求,绑定结构体获取参数
func (this *UserController) Post() {
//定义保存表单数据的结构体对象
u := models.UserForm{}
//通过ParseForm()函数,将请求参数绑定到结构体变量
if err := this.ParseForm(&u); err != nil {
}
this.Ctx.Output.Body([]byte(u.ToString()))
}
用struct绑定请求参数的方式,仅适用于POST请求。
5.3.3、处理JSON请求参数
一般在接口开发时,有时会将JSON请求参数保存在HTTP请求的请求体中。这时就不能使用绑定结构体方式获取JSON数据,需要直接读取请求体的内容,然后格式化数据。处理JSON参数的步骤如下:
- 在app.conf配置文件中添加一行:
CopyRequestBody=true
。 - 通过
this.Ctx.Input.RequestBody
语句获取HTTP请求中请求体的内容。 - 通过
json.Unmarshal()
函数反序列化JSON字符串,将JSON参数绑定到结构体变量。
JSON请求参数的示例如下:
//JSON结构体
type UserJson struct {
//忽略掉Id字段
Id int `json:"-"`
//JSON字段名为name
Name string `json:"name"`
Phone string `json:"phone"`
}
func (this *UserJson) ToString() string {
str := "name:" + this.Name + ",phone:" + this.Phone
return str
}
控制器代码:
type UserJsonController struct {
beego.Controller
}
// 处理GET请求,默认获取参数
func (this *UserJsonController) Post() {
u := models.UserJson{}
//获取请求题内容
body := this.Ctx.Input.RequestBody
//反序列化JSON数据,将结果保存到u
if err := json.Unmarshal(body, &u); err != nil {
}
this.Ctx.Output.Body([]byte(u.ToString()))
}
注册路由:
beego.Router("userjson", &controllers.UserJsonController{})
如果请求参数是XML格式,则XML的参数会被保存在请求体中。
5.4、响应请求
在处理完用户的请求后,通常会返回HTML代码,然后浏览器就可以显示HTML内容。除返回HTML外,在API接口开发中,还可以返回JSON、XML、JSONP格式的数据。
如果使用Beego开发API,则需要在app.conf中设置AutoRender=false,以禁止自动渲染模板,否则Beego每次处理请求都会尝试渲染模板,如果模板不存在则会报错。
5.4.1、返回JSON数据
// JSON结构体
type UserJson struct {
//忽略掉Id字段
Id int `json:"-"`
//JSON字段名为name
Name string `json:"name"`
Phone string `json:"phone"`
}
func (this *UserController) Get() {
//返回JSON数据
user := models.UserJson{1, "tom", "123456"}
//讲需要返回的数据赋值给json字段
this.Data["json"] = &user
//将数据序列化成json字符串,然后返回给客户端
this.ServeJSON()
}
5.4.2、返回XML数据
// XML结构体
type UserXml struct {
//忽略掉Id字段
Id int `xml:"-"`
//JSON字段名为name
Name string `xml:"name"`
Phone string `xml:"phone"`
}
func (this *UserController) Get() {
//返回XML数据
user := models.UserXml{1, "tom", "123456"}
//将需要返回的数据赋值给XML字段
this.Data["xml"] = &user
//序列化并返回
this.ServeXML()
}
5.4.3、返回JSONP数据
func (this *UserController) Get() {
//返回JSONP数据
user := models.UserJson{1, "tom", "123456"}
//将需要返回的数据赋值给JSONP字段
this.Data["jsonp"] = &user
//序列化
this.ServeJSONP()
}
5.4.4、返回HTML代码
如果开发的是网页,则通常需要返回HTML代码。在Beego项目中,是模板引擎技术渲染HTML代码,然后将结果返给浏览器。示例如下:
func (c *MainController) Get() {
// 设置模板参数
c.Data["Website"] = "beego.vip"
c.Data["Email"] = "astaxie@gmail.com"
// 需要渲染的模板,Beego会渲染这个模板然后返回结果
c.TplName = "index.tpl"
}
5.4.5、添加响应头
//通过this.Ctx.Output.Header设置响应头
this.Ctx.Output.Header("Cache-Control", "no-cache, no-store, must-revalidate")
6、Beego模型
在Beego中,模型默认使用Beego ORM对进行数据库相关操作。
7、Beego模板
Beego的视图(View)模板引擎是基于Go原生的模板库(html/template)进行开发的。Beego的模板默认支持“tpl”和“html”
后缀名。
7.1、模板基础示例
新建一个名为index.html的模板文件,其代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>用户个人信心:</h1>
<p>
用户名:{{.user.Name}}<br/>
注册时间:{{.user.Phone}}
</p>
</body>
</html>
控制器:
func (this *UserController) Get() {
//渲染视图
user := models.UserForm{1, "tom", "123456"}
this.Data["user"] = user
//设置要渲染的模板路径,即views目录下面的相对路径
//如果不设置TplName,则beego默认按照 "<控制器名字>/<方法名>.tpl" 格式去查找模板文件
this.TplName = "user/index.html"
//如果关闭了自动渲染,则需要手动调用渲染函数。默认开启自动渲染
this.Render()
}
7.2、模板标签冲突
默认情况下,模板引擎使用“{{模板表达式}}”作为模板标签。假如前端开发使用的是React、Angular之类的框架,则会因为这些前端框架也使用“{{模板表达式}}”作为模板标签而造成冲突。可以通过修改Go模板引擎的默认标签,来解决模板标签冲突问题。示例如下:
//修改Go的模板标签
beego.TemplateLeft = "<<<"
beego.TemplateRight = ">>>"
修改后的模板表达式:
<<<.user.phone>>>
8、Beego处理session
Beego内置的session模块,在Beego的设计中可以自由配置。目前session模块支持Memory、cookie、File、MySQL、Redis等常用的存储引擎。
8.1、session基本配置
在app.conf配置文件中加入如下配置,然后重启Beego程序即可生效。
首先打开session,这一步是必须的,否则Beego默认不会开启session:
sessionon = true
设置session id的名字,这个通常都是保存在客户端cookie里面:
sessionname = "beegosessionID"
设置Session的过期时间,默认3600s:
sessiongcmaxlifetime = 3600
设置session id的过期时间,因为session id是保存在cookie中的:
SessionCookieLifeTime = 3600
app.conf:
appname = beego
httpport = 8080
runmode = dev
# 处理JSON请求参数
copyrequestbody = true
# 禁止自动渲染模板
autorender = false
#包含MySQL配置文件
include "mysql.conf"
sessionon = true # 开启session
sessionname = "beegosessionID" # beegosessionID
sessiongcmaxlifetime = 3600 # session过期时间
SessionCookieLifeTime = 3600 # session id 的过期时间,因为其保存在cookie中
8.2、session读写示例
下面是一个在控制器函数中操作session的示例:
func (c *MainController) Get() {
// 设置模板参数
c.Data["Website"] = "beego.vip"
c.Data["Email"] = "astaxie@gmail.com"
//读取session数据
v := c.GetSession("count")
if v == nil {
//写入session数据
c.SetSession("count", int(1))
c.Data["num"] = 0
} else {
c.SetSession("count", v.(int) + 1)
c.Data["num"] = v.(int)
}
// 需要渲染的模板,Beego会渲染这个模板然后返回结果
c.TplName = "index.tpl"
}
在Beego的session包中,数据的读写函数如下。
- SetSession(name string,value interface{}):设置session值;
- GetSession(name string)interface{}:读取session值;
- DelSession(name string):删除指定的session值;
- SessionRegeneratelD():生成新的session id;
- DestroySession():销毁session;
8.3、配置session的存储引擎
session的存储引擎默认是Memory,即session数据默认保存在运行Beego程序的机器内存中。下面分别介绍常用session存储引擎的配置方式。
8.3.1、将session数据保存到文件中
#设置session,保存到文件中
sessionprovider = "file"
#设置session数据的保存目录
sessionproviderconfig = "./data/session"
8.3.2、将session数据保存到Redis中
安装Beego的Redis驱动程序:
go get github.com/astaxie/beego/session/redis
通过import语句导入Redis驱动程序:
import "github.com/astaxie/beego/session/redis"
修改conf/app.conf配置如下:
#设置session的存储引擎
sessionprovider = "redis"
#Redis存储引擎配置
#Redis配置格式:Redis地址,Redis连接池最大连接数,Redis密码
#Redis.连接池和Redis密码配置,没有保持为空
sessionproviderconfig = "127.0.0.1:6379,1000,123456"
9、Beego项目部署
9.1、项目打包
之前介绍过bee工具,在项目根目录执行下面命令即可完成项目打包:
$ bee pack
在打包完成后,在当前目录下会生成一个“.gz”后缀的压缩包。
9.2、独立部署
独立部署是指直接将上面得到的压缩包上传到服务器,解压缩后直接运行Go程序。
进入项目目录下,打开命令行终端输入如下命令即可:
nohup ./beepkg &
9.3、Beego热更新
热更新是指,在不中断服务的情况下完成程序升级。
Beego项目默认已经实现了热更新。下面介绍Beego如何实现热更新。
首先在app.conf配置文件中打开热更新配置:
Graceful = true
假设目前老版本的程序正在运行,进程ID是2367。现在将新版本的Beego程序压缩包上传到服务器中,解压缩,直接覆盖老的文件。
然后触发Beego程序热更新,具体命令如下:
kill -HUP 进程ID
上面这个命令的意思是给指定进程发送一个HUB信号,Beego程序在接收到这个信号后就开始处理热更新操作。如果老版本的进程ID是8689,则命令如下:
kill -HUP 8689
执行命令后就完成了热更新操作。