内容简介:虽然接触go有一段时间了,但web框架一直没有接触。为了方便做CURD,所以这两天简单学了一下beego框架,为以后使用做准备。
虽然接触 go 有一段时间了,但web框架一直没有接触。
为了方便做CURD,所以这两天简单学了一下beego框架,为以后使用做准备。
点击下载文档 。
正文
Beego Web框架调研
ORM Object风格的INSERT操作 13
Orm Object风格的Read操作 14
QuerySelector风格的CURD 15
QueryBuilder风格的CURD 16
参考文档: https://beego.me/quickstart
下载依赖
$ go get -u github.com/astaxie/beego
$ go get -u github.com/beego/bee
生成框架
比如我最终要把项目上传到 https://github.com/owenliang/beego-demo ,那么就这样生成项目:
bin/bee new github.com/owenliang/beego-demo
框架会生成在$GOPATH/src/github.com/owenliang/beego-demo下面:
-rw-r–r– 1 liangdong staff 25 1 16 10:10 README.md
drwxr-xr-x 3 liangdong staff 96 1 16 10:05 conf
drwxr-xr-x 3 liangdong staff 96 1 16 10:05 controllers
-rw-r–r– 1 liangdong staff 129 1 16 10:05 main.go
drwxr-xr-x 2 liangdong staff 64 1 16 10:05 models
drwxr-xr-x 3 liangdong staff 96 1 16 10:05 routers
drwxr-xr-x 5 liangdong staff 160 1 16 10:05 static
drwxr-xr-x 3 liangdong staff 96 1 16 10:05 tests
drwxr-xr-x 3 liangdong staff 96 1 16 10:05 views
验证框架
需要配置IDE修改程序的工作目录,因为beego会根据工作目录相对路径查找模板和配置文件。
然后就可以运行main.go了:
代码很简单,引入了routers模块,启动了beego:
Routers模块会在init回调中注册路由到beego:
。
MainController渲染了一下views/index.tpl模板:
访问localhost:8080,页面正常:
参考文档: https://beego.me/docs/intro/
Bee工具
bee new创建web项目,bee api创建纯api项目。
bee run运行项目可以监听开发阶段的代码变化,实时自动编译,达到脚本语言的开发效率。
Bee run需要进入项目根目录执行:
bee generate用于生成mvc代码,后面遇到再说。
Controller
Conf/app.conf目录下,详细文档:
https://beego.me/docs/mvc/controller/config.md
runmode可以切换不同环境的多份配置,而runmode自身可以通过环境变量传递,从而实现不同环境不同配置的需要。
详细参考: https://beego.me/docs/mvc/controller/router.md
一共3种模式:固定路由、正则路由、自动路由
固定路由,要求URI完全匹配:
beego.Router( “/” , &controllers.MainController{})
正则路由,长相有点奇怪,举个栗子:
beego.Router(“/api/:id([0-9]+)“, &controllers.RController{})
controller取参的时候:
this.Ctx.Input.Param(“:id”)
自动路由,需要把你的controller对象注册上去:
beego.AutoRouter(&controllers.ObjectController{})
beego会反射这个controller对象的方法,生成路由表,比如:
/object/login 调用 ObjectController 中的 Login 方法
/object/logout 调用 ObjectController 中的 Logout 方法
还支持namespace,说白了就是具备某个URI前缀的路由表,我把原先的router改成这样:
funcinit() {
ns := beego.NewNamespace( “/v1” ,
beego.NSRouter( “/” , &controllers.MainController{}),
)
beego.AddNamespace(ns)
}
就可以访问localhost:8080/v1了。
我们的controller继承beego基类,有各种操作方法,controller里的数据已经被beego框架填充好了:
typeMainController struct {
beego.Controller
}
根据HTTP request的action的不同,会回调MainController的POST/GET/DELETE等方法,这些方法在beego.Controller中都有留空了实现,我们可以覆写。
func(c *MainController) Get() {
“beego.me”
c.Data[ “Email” ] =“astaxie@gmail.com”
c.TplName =“index.tpl”
}另外prepare和finish方法是留给我们覆写的,在执行action之前和之后做一些自定义操作,例如:
func(c *MainController) Prepare() {
“beego.me”
c.Data[ “Email” ] =“astaxie@gmail.com”
}func(c *MainController) Get() {
“index.tpl”
}如果想防止跨站提交表单,看一下beego提供的API即可: https://beego.me/docs/mvc/controller/xsrf.md
获取参数
获取Get/Post参数: https://beego.me/docs/mvc/controller/params.md
比如请求: http://localhost:8080/v1/?arg=xxx ,可以这样获取参数:
func(c *MainController) Get() {
v := c.Input().Get( “arg” )
fmt.Println(v)
“index.tpl”
}也可以这样:
func(c *MainController) Get() {
v := c.GetString( “arg” )
fmt.Println(v)
“index.tpl”
}区别就是前者是取原始解析出来的字符串,后者是支持强类型转换到int之类的。
Beego也支持文件表单上传,就不说明了。
Session
beego支持session存储到redis/mysql之类的。
但是session的k-v最好别用struct作为value,否则序列化和反序列化很麻烦,就用普通int/string就行。
通常我们用redis,需要经历如下操作:
- 安装beego的providor:
go get -u github.com/astaxie/beego/session/redis
然后在main.go中引入:
import _ “github.com/astaxie/beego/session/redis”
- 安装 redis 的driver:
go get github.com/gomodule/redigo
然后在main.go中引入:
_ “github.com/gomodule/redigo/redis”
- 启动redis:redis-server
- 配置beego使用redis session:
appname = beego-demo
httpport = 8080
runmode = dev
sessionon = true
sessionprovider = redis
sessionproviderconfig=127.0.0.1:6379
- 在beego中访问session,统计用户浏览次数:
func(c *MainController) Get() {
visit_times := 0
times := c.GetSession( “visit_times” )
iftimes != nil {
visit_times = times.(int)
}
visit_times += 1
c.SetSession( “visit_times” , visit_times)
c.Ctx.WriteString( “visit_times=” + strconv.Itoa(visit_times))
// c.TplName = “index.tpl”
}beego.InsertFilter(pattern string, position int, filter FilterFunc, params …bool)
即在URI满足某个pattern规则的时候,会在某个生命期position插入该过滤回调filterFunc。
试了一下,某些position没有回调,用时候再追原因吧。
输出json
把结构体赋值给Data的json字段,然后调用ServeJSON就可以返回了:
typeResp struct {
Name string
Age int
}
func(c *MainController) Get() {
c.Data[ “json” ] = &Resp{Name: “owen” , Age: 20}
c.ServeJSON()
}
输入验证
MVC框架大多提供validator这种东西或者model,用来快速校验提交的表单数据是否合法。
Beego提供了一个库来简化验证工作,免得我们一个参数一个参数的去check: https://beego.me/docs/mvc/controller/validation.md ,这是需要安装的,等有需要再看。
错误处理
MVC框架一般支持运行出错的时候进入通用的error handler/error controller,beego也支持: https://beego.me/docs/mvc/controller/errors.md ,用error controller方式更简单合理。
日志管理
Beego封装了日志库,我们需要手动配置一波:
funcinit() {
// 配置日志
// 打印行号
beego.SetLogFuncCall( true )
// 配置文件日志(保存到beego.log, 日志最多保留1天, 最高级输出INFO日志)
beego.SetLogger(logs. AdapterFile ,{"filename": "./beego.log", "maxdays": 1, "maxlines": 1, "level": 6}
)
// 删除命令行日志
beego.BeeLogger.DelLogger(logs. AdapterConsole )}
funcmain() {
beego.Run()
}
logger库支持多路输出,默认是输出到AdapterConsole,但是我把这一路删了,然后加了一路adpterFile输出到日志文件 。 日志支持按行数/大小/天滚动文件,上面我设置了maxliens:1,所以每打印1行日志,文件就被滚动换掉了:
-r–r—– 1 liangdong staff 1058 1 16 14:18 beego.2019-01-16.001.log
-r–r—– 1 liangdong staff 84 1 16 14:19 beego.2019-01-16.002.log
-rw-rw—- 1 liangdong staff 84 1 16 14:19 beego.log
Maxdays配置那些被归档的日志多久被删除,我设置的1天。
Beego框架本身就会打一些日志,我们程序也可以打:
func(c *MainController) Get() {
beego.Info( “heihei” )
c.Data[ “json” ] = &Resp{Name: “owen” , Age: 20}
c.ServeJSON()
}
更多细节参考:
https://beego.me/docs/mvc/controller/logs.md
https://beego.me/docs/module/logs.md
Beego提供了ORM库,以 mysql 为例。
先安装mysql的driver:
Go get github.com/go-sql-driver/mysql
再安装beego orm:
go get github.com/astaxie/beego/orm
数据库设置
在本地建好数据库:create database beego;
在main.go中做注册:
funcinit() {
// 注册driver
orm.RegisterDriver( “mysql” , orm. DRMySQL )// 注册数据库( 最后2个数字是最大空闲连接和最大数据库连接数量)
orm.RegisterDataBase( “default” , “mysql” , “root:baidu@123@tcp(127.0.0.1:3306)/beego?charset=utf8&loc=Asia%2fShanghai” , 1, 10)}
funcmain() {
beego.Run()
}
具体的mysql schema参考driver文档: https://github.com/go-sql-driver/mysql
注册model
在models目录下定义model:
packagemodels
typeUser struct {
Id int64
orm:"size(64);unique"
// varchar(64), 唯一索引
}可以用orm标签,指定各种属性告诉beego每个字段的约束,这个用途主要有2个:
- 保存model到数据库的时候,可以供beego检查
- 根据Model初始化table的时候,生成 sql 语句。
对于2)来说,我们通常会发现golang的web程序会自动创建table,这是通过model->table同步实现的:
funcinit() {
// 注册driver
orm.RegisterDriver( “mysql” , orm. DRMySQL )// 注册数据库( 最后2个数字是最大空闲连接和最大数据库连接数量)
orm.RegisterDataBase( “default” , “mysql” , “root:baidu@123@tcp(127.0.0.1:3306)/beego?charset=utf8&loc=Asia%2fShanghai” , 1, 10)// 注册model
orm.RegisterModel(&models.User{})// 初始化table
orm.RunSyncdb( “default” , false , false )}
在registerModel后,可以通过runsyncdb做一次建表,底层执行的就是create if not exists,所以model的标签这时候就发挥了作用。
比如size(64)其实就会导致name字段的类型是varchar(64),因为name是string类型。
查看数据库,user表已经建立:
| user | CREATE TABLE user
(
id
bigint(20) NOT NULL AUTO_INCREMENT,
name
varchar(64) NOT NULL DEFAULT ”,
PRIMARY KEY ( id
),
UNIQUE KEY name
( name
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
更多细节参考: https://beego.me/docs/mvc/model/models.md
ORM Object风格的INSERT操作
插入:
funcInsertUser(user *User) (err error) {
// 每次请求的ormer需要新建, 不能并发使用
orm := orm.NewOrm()// 插入
user.Id, err = orm.Insert(user)return
}创建user对象,完成插入:
func(c *MainController) Get() {
user := models.User{Name: “owen” }
iferr := models.InsertUser(&user); err == nil {
beego.Info( “插入用户:” , user)
c.Ctx.WriteString( “ok” )
} else {
c.Ctx.WriteString(err.Error())
}
}
执行1次插入了记录:
mysql> select * from user;
+—-+——+
| id | name |
+—-+——+
| 1 | owen |
+—-+——+
再执行报错:
Error 1062: Duplicate entry ‘owen’ for key ‘name’
说明name字段根据struct标签定义为unique了。
Orm Object风格的Read操作
定义方法:
funcFindUser(user *User) (err error) {
// 每次请求的ormer需要新建, 不能并发使用
orm := orm.NewOrm()err = orm.Read(user)
return
}然后查找:
func(c *MainController) Get() {
// 查找Id=1的记录
user := models.User{Id: 1}iferr := models.FindUser(&user); err == nil {
c.Ctx.WriteString( “找到:” + user.Name)
} else {
c.Ctx.WriteString( “不存在” )
}
}
得到结果:
找到:owen
Delete和Update就不演示了,都是ORM对象风格,文档: https://beego.me/docs/mvc/model/object.md
QuerySelector风格的CURD
上述纯ORM object的底层基于query selector构建SQL,这套API风格类似于django,不建议深入了解,文档: https://beego.me/docs/mvc/model/query.md
原生SQL风格的CURD
类似于这样的:
var users []User
num, err := o.Raw(“SELECT id, user_name FROM user WHERE id = ?”, 1).QueryRows(&users)
仍旧支持struct的自动反序列化,我觉得这种就够用,不需要用ORM那些。
QueryBuilder风格的CURD
避免手写SQL的尴尬,给我们提供链式构造SQL的能力:
qb.Select(“user.name”,
“profile.age”).
From(“user”).
InnerJoin(“profile”).On(“user.id_user = profile.fk_user”).
Where(“age > ?”).
OrderBy(“name”).Desc().
Limit(10).Offset(0)
比ORM灵活,比裸写SQL清晰,我喜欢这种。
很简单,围绕一个ORM()对象展开begin/rollback/commit:
https://beego.me/docs/mvc/model/transaction.md
详细文档: https://beego.me/docs/mvc/view/tutorial.md ,底层用的是Go标准库template,额外做了一些扩展。
下面举一个简单例子:
使用的时候,首先是准备模板数据放到controller的Data里,然后赋值TplName为相对于views目录的路径:
func(c *MainController) Get() {
// 查找Id=1的记录
user := models.User{Id: 1}// 找到记录
if err := models.FindUser(&user); err == nil {// 设置模板数据
c.Data[ “user” ] = &user}
// 设置模板文件
c.TplName =“main.html”
}然后编写main.html:
{{ template “header.html” .}}
{{ if .user}}
欢迎你,{{.user.Name | htmlquote}}
{{ else }}
您没有登录!
{{ end }}
{{ template “footer.html” .}}
这里引入了另外2个模板,并且把当前的上下文参数通过.带给了2个嵌套模板。
Go语言动态的部分都要放在{{}}内,具体语法参考文档。
Header.html和footer.html不需要{{define}}也能用,比go template方便点。
Header.html:
<!DOCTYPE html >
< html lang=”en” >
< head >
< meta charset=”UTF-8″ >
< title >beego</ title >
</ head >
< body >
Footer.html:
< script ></ script >
</ body >
</ html >
博主无私的分享着知识,你愿意送他一顿热腾腾的早餐吗?
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。